├── Docs
├── SPDemo.gif
├── SupportingDelphi.jpg
├── CommandLine.md
├── Spid.md
├── APIDoc.md
└── Samples.md
├── Demos
├── SAML
│ ├── SPDemo.res
│ ├── SAML_SP.res
│ ├── SAML.http.Server.dfm
│ ├── pages
│ │ ├── sp.css
│ │ └── sp.html
│ ├── SPDemo.dpr
│ ├── SAML.Form.Main.pas
│ ├── SAML.Form.Main.dfm
│ └── SPDemo.dproj
├── XmlSec
│ ├── XmlSecDemo.res
│ ├── XmlSecDemo.dpr
│ ├── SAML.XML.MainForm.dfm
│ ├── XmlSecDemo.dproj
│ └── SAML.XML.MainForm.pas
├── Metadata
│ ├── MetadataDemo.res
│ ├── MetadataDemo.dpr
│ ├── SAML.Forms.Main.dfm
│ ├── MetadataDemo.dproj
│ └── SAML.Forms.Main.pas
├── bin
│ ├── sp-auth0.ini
│ ├── idp-auth0.ini
│ ├── sp-key.pem
│ └── keygen.bat
├── bin64
│ ├── sp-auth0.ini
│ └── idp-auth0.ini
└── Demos.groupproj
├── Test
├── SAML.Test.App.res
├── SAML.Test.Encrypt.pas
├── SAML.Test.Signature.pas
├── SAML.Test.App.dpr
└── SAML.Test.Consts.pas
├── Sources
├── bindings
│ ├── README.md
│ └── libexslt.pas
├── SAML.inc
└── SAML.Core.pas
├── Samples
├── sp-metadata.xml
├── sp-authnrequest-signed.xml
├── sp-metadata-with-keys.xml
├── assertion-samltest.xml
└── idp-metadata-samltest.xml
├── .gitignore
├── README.md
├── README.htm
└── LICENSE
/Docs/SPDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Docs/SPDemo.gif
--------------------------------------------------------------------------------
/Demos/SAML/SPDemo.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Demos/SAML/SPDemo.res
--------------------------------------------------------------------------------
/Demos/SAML/SAML_SP.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Demos/SAML/SAML_SP.res
--------------------------------------------------------------------------------
/Test/SAML.Test.App.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Test/SAML.Test.App.res
--------------------------------------------------------------------------------
/Docs/SupportingDelphi.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Docs/SupportingDelphi.jpg
--------------------------------------------------------------------------------
/Demos/XmlSec/XmlSecDemo.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Demos/XmlSec/XmlSecDemo.res
--------------------------------------------------------------------------------
/Demos/Metadata/MetadataDemo.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EtheaDev/Delphi-SAML/HEAD/Demos/Metadata/MetadataDemo.res
--------------------------------------------------------------------------------
/Sources/bindings/README.md:
--------------------------------------------------------------------------------
1 | # Pascal units
2 |
3 | The units in this folder are a slightly modified version of:
4 |
5 | https://www.zlatkovic.com/projects/libxml/index.html
--------------------------------------------------------------------------------
/Demos/bin/sp-auth0.ini:
--------------------------------------------------------------------------------
1 | EntityId=urn:msingh.samltools:sp
2 | HomeUrl=http://sp.samltools.com:4567/pages/sp.html
3 | AssertionUrl=http://sp.samltools.com:4567/assertion
4 | SignRequest=0
5 |
--------------------------------------------------------------------------------
/Demos/bin64/sp-auth0.ini:
--------------------------------------------------------------------------------
1 | EntityId=urn:msingh.samltools:sp
2 | HomeUrl=http://sp.samltools.com:4567/pages/sp.html
3 | AssertionUrl=http://sp.samltools.com:4567/assertion
4 | SignRequest=0
5 |
--------------------------------------------------------------------------------
/Demos/SAML/SAML.http.Server.dfm:
--------------------------------------------------------------------------------
1 | object modHttpServer: TmodHttpServer
2 | Height = 244
3 | Width = 334
4 | object SPServer: TIdHTTPServer
5 | Bindings = <>
6 | DefaultPort = 4567
7 | OnCommandGet = SPServerCommandGet
8 | Left = 144
9 | Top = 80
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/Demos/bin/idp-auth0.ini:
--------------------------------------------------------------------------------
1 | EntityId=urn:dev-ejtl988w.auth0.com
2 | SSOUrl=https://dev-ejtl988w.auth0.com/samlp/lqrbWWMYc25UrCiYA5Pt06U625c4K6DO
3 | SSOBinding=HTTP-Redirect
4 | SLOUrl=
5 | SLOBinding=HTTP-Redirect
6 | SignRequest=0
7 | SignPubKeyFile=
8 | SignPubKeyFormat=CERT_PEM
9 | EncPubKeyFile=
10 | EncPubKeyFormat=CERT_PEM
11 | SkipSignatureCheck=0
--------------------------------------------------------------------------------
/Demos/bin64/idp-auth0.ini:
--------------------------------------------------------------------------------
1 | EntityId=urn:dev-ejtl988w.auth0.com
2 | SSOUrl=https://dev-ejtl988w.auth0.com/samlp/lqrbWWMYc25UrCiYA5Pt06U625c4K6DO
3 | SSOBinding=HTTP-Redirect
4 | SLOUrl=
5 | SLOBinding=HTTP-Redirect
6 | SignRequest=0
7 | SignPubKeyFile=
8 | SignPubKeyFormat=CERT_PEM
9 | EncPubKeyFile=
10 | EncPubKeyFormat=CERT_PEM
11 | SkipSignatureCheck=0
--------------------------------------------------------------------------------
/Demos/SAML/pages/sp.css:
--------------------------------------------------------------------------------
1 | li
2 | {
3 | margin-bottom: 10px;
4 | }
5 |
6 | .button
7 | {
8 | font-size: 14px;
9 | font-weight: bold;
10 | padding: 10px 0px 10px 0px;
11 | border-radius: 10px;
12 | border: 2px solid #222;
13 | overflow-wrap: anywhere;
14 | width: 20em;
15 | margin: 2px;
16 | }
17 |
18 | #txt
19 | {
20 | font-weight: 100;
21 | font-family: Verdana, Geneva, Tahoma, sans-serif;
22 | }
--------------------------------------------------------------------------------
/Samples/sp-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Docs/CommandLine.md:
--------------------------------------------------------------------------------
1 | # Command line
2 |
3 | **Generate the SP keys**
4 |
5 | keygen.bat -h sp.samltools.com -e urn:msingh.samltools:sp -y 10
6 |
7 | The `-h` parameter is the hostname, the domain of the Service Provider and the `-e` parameter is the *EntityID* of the Service Provider.
8 |
9 | **Sign a file with a private key**
10 |
11 | xmlsec.exe --sign --privkey-pem sp-key.pem sign1-tmpl.xml > signed.xml
12 |
13 | **Validate a file with a public certificate**
14 |
15 | xmlsec.exe --verify --pubkey-cert-pem sp-cert.pem signed.xml
16 |
17 | **convert a PEM certificate to a DER certificate**
18 |
19 | openssl x509 -inform pem -in Certificate.pem -outform der -out Certificate.der
20 |
21 | **To convert a PEM private key to a DER private key**
22 |
23 | openssl rsa -inform pem -in PrivateKey.pem -outform der -out PrivateKey.der
24 |
--------------------------------------------------------------------------------
/Docs/Spid.md:
--------------------------------------------------------------------------------
1 | # Spid
2 |
3 | ## Documentazione ufficiale
4 |
5 | https://docs.italia.it/italia/spid/spid-regole-tecniche/it/stabile/single-sign-on.html
6 | https://docs.italia.it/italia/spid/spid-regole-tecniche/it/stabile/metadata.html
7 | https://www.spid.gov.it/wp-content/uploads/2021/07/SPID_QAD.pdf
8 |
9 | ## Tools
10 |
11 | Ambiente Demo SPID:
12 | https://demo.spid.gov.it/
13 |
14 | SAML tools:
15 | https://www.samltool.com/online_tools.php
16 |
17 | ## SP Metadata
18 |
19 | * I metadati devono contente il tag con l'elenco di tutti gli attributi di cui hanno bisogno
20 | * Devono essere firmati
21 | * Devono avere la sezione
22 |
23 | ## AuthnRequest
24 |
25 | * AuthnContextClassRef deve essere:
26 | * https://www.spid.gov.it/SpidL1
27 | * https://www.spid.gov.it/SpidL2
28 | * https://www.spid.gov.it/SpidL3
29 |
30 | ## Todo
31 |
32 | * Generate metadata
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 |
25 | # Delphi compiler-generated binaries (safe to delete)
26 | *.exe
27 | *.dll
28 | *.bpl
29 | *.bpi
30 | *.dcp
31 | *.so
32 | *.apk
33 | *.drc
34 | *.map
35 | *.dres
36 | *.rsm
37 | *.tds
38 | *.dcu
39 | *.lib
40 |
41 | # Delphi autogenerated files (duplicated info)
42 | *.cfg
43 | *Resource.rc
44 | Win32
45 | Linux64
46 |
47 | # Delphi local files (user-specific info)
48 | *.local
49 | *.identcache
50 | *.projdata
51 | *.tvsconfig
52 | *.dsk
53 |
54 | # Delphi history and backups
55 | __history/
56 | __recovery/
57 | *.~*
58 |
59 | # Castalia statistics file
60 | *.stat
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Test/SAML.Test.Encrypt.pas:
--------------------------------------------------------------------------------
1 | unit SAML.Test.Encrypt;
2 |
3 | interface
4 |
5 | uses
6 | System.Classes,
7 | System.SysUtils,
8 | DUnitX.TestFramework,
9 | SAML.XML.Utils,
10 | SAML.Test.Consts;
11 |
12 | type
13 | [TestFixture]
14 | TTestEncrypt = class
15 | public
16 | [Setup]
17 | procedure Setup;
18 | [TearDown]
19 | procedure TearDown;
20 | [Test]
21 | procedure EncryptXML;
22 | [Test]
23 | procedure DecryptXML;
24 | end;
25 |
26 |
27 | implementation
28 |
29 | { TTestSignature }
30 |
31 | procedure TTestEncrypt.DecryptXML;
32 | var
33 | LXMLDocument: IXMLSecDocument;
34 | LEncryptionContext: IEncryptionContext;
35 | LDataNode: IXMLSecNode;
36 | begin
37 | LXMLDocument := TXMLSecDocument.Create(TStringStream.Create(XMLEncrypted), True);
38 | //LXMLDocument.AddIDAttr('Id', 'EncryptedKey', 'http://www.w3.org/2001/04/xmlenc#');
39 |
40 | LEncryptionContext := TEncryptionContext.Create;
41 | LEncryptionContext.LoadKey(TStringStream.Create(PrivateKey), TKeyDataFormat.Pem, True);
42 | LEncryptionContext.Decrypt(LXMLDocument);
43 |
44 | if not LXMLDocument.TryFindNode('Data', 'urn:envelope', LDataNode) then
45 | begin
46 | Assert.Fail('"Data" node not found');
47 | end;
48 | Assert.AreEqual('Hello,World!', TrimAll(LDataNode.Text));
49 | end;
50 |
51 | procedure TTestEncrypt.EncryptXML;
52 | var
53 | LXMLDocument: IXMLSecDocument;
54 | LEncryptionContext: IEncryptionContext;
55 | begin
56 | LXMLDocument := TXMLSecDocument.Create(TStringStream.Create(XMLEncTemplate), True);
57 |
58 | LEncryptionContext := TEncryptionContext.Create;
59 | LEncryptionContext.LoadKey(TStringStream.Create(PublicKey), TKeyDataFormat.CertPem, True);
60 |
61 | Assert.WillRaise(
62 | procedure
63 | begin
64 | LEncryptionContext.Encrypt(LXMLDocument);
65 | end,
66 | ESAMLNotImplemented
67 | );
68 |
69 | end;
70 |
71 | procedure TTestEncrypt.Setup;
72 | begin
73 |
74 | end;
75 |
76 | procedure TTestEncrypt.TearDown;
77 | begin
78 |
79 | end;
80 |
81 | initialization
82 | TDUnitX.RegisterTestFixture(TTestEncrypt);
83 |
84 | end.
85 |
--------------------------------------------------------------------------------
/Samples/sp-authnrequest-signed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | urn:test.lucaminuti:sp
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | VfQSZu2jOwms42DLW4UFRYZlk5o=
14 |
15 |
16 | dzxGb07U8ksQXMYzLAaPPt0vh0ECyvZBP3LQ35LcGHwxoo9xh4Gbp885VQxpNKNQ
17 | E3aqMs0YgqkPoRUfsq1hZE7tbe5c1cnahFDGPyUT+yHIi3ecvhWeNy9Fx2r0bBMZ
18 | VqwBwsJK56ATIR/Uwl69hvNvBEzXMohA5n6e8sRKIPinLqlQMtm0WXW9l7DePEmE
19 | 0+MW8jlbOYQt1Byk4kwg/0HLw0DaGw6gGg5ouHnh1kyET81n/nyb8q/DubFnTyKh
20 | BIyFSK9EBieCipBif812mBgKBu8nwCcoe9HyCisUethKwS901u1adaPWbL66w+3F
21 | tkEJWIPLS0Cfw5lmhOjDtNHPxKg3poevAmE/Af5TE8h2LjJtrpIozyqzhT3SpHOO
22 | VQ7pnoW8DehMwIFlRd+Wkp8G7nCpaYgBXjTM5BFt/ALNVyTKdX2vW1brY13fajKf
23 | acov8JWccBTJX4nruNlbaS4TUivyQ0ztrobcQAMRy2khcz4em2a35Z0ax0+5eoGo
24 |
25 |
26 |
27 |
28 |
29 |
30 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Demos/Demos.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {A725B9B2-8229-4D96-8F73-7B24A69D6E1C}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Default.Personality.12
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Test/SAML.Test.Signature.pas:
--------------------------------------------------------------------------------
1 | unit SAML.Test.Signature;
2 |
3 | interface
4 |
5 | uses
6 | System.Classes,
7 | System.SysUtils,
8 | DUnitX.TestFramework,
9 | SAML.XML.Utils,
10 | SAML.Test.Consts;
11 |
12 | type
13 | [TestFixture]
14 | TTestSignature = class
15 | public
16 | [Setup]
17 | procedure Setup;
18 | [TearDown]
19 | procedure TearDown;
20 | [Test]
21 | procedure SignXML;
22 | [Test]
23 | procedure VerifyXML;
24 | [Test]
25 | procedure VerifyWrongXML;
26 | end;
27 |
28 | implementation
29 |
30 | procedure TTestSignature.Setup;
31 | begin
32 | end;
33 |
34 | procedure TTestSignature.TearDown;
35 | begin
36 | end;
37 |
38 | procedure TTestSignature.VerifyWrongXML;
39 | var
40 | LModifiedXML: string;
41 | LXMLDocument: IXMLSecDocument;
42 | LSignatureContext: ISignatureContext;
43 | begin
44 | LModifiedXML := StringReplace(XMLSigned, 'Hello', 'Ciao', [rfReplaceAll, rfIgnoreCase]);
45 |
46 | LXMLDocument := TXMLSecDocument.Create(TStringStream.Create(LModifiedXML), True);
47 |
48 | LSignatureContext := TSignatureContext.Create;
49 | LSignatureContext.LoadKey(TStringStream.Create(PublicKey), TKeyDataFormat.CertPem, True);
50 |
51 | Assert.IsFalse(LSignatureContext.Verify(LXMLDocument));
52 | end;
53 |
54 | procedure TTestSignature.VerifyXML;
55 | var
56 | LXMLDocument: IXMLSecDocument;
57 | LSignatureContext: ISignatureContext;
58 | begin
59 | LXMLDocument := TXMLSecDocument.Create(TStringStream.Create(XMLSigned), True);
60 |
61 | LSignatureContext := TSignatureContext.Create;
62 | LSignatureContext.LoadKey(TStringStream.Create(PublicKey), TKeyDataFormat.CertPem, True);
63 |
64 | Assert.IsTrue(LSignatureContext.Verify(LXMLDocument));
65 | end;
66 |
67 | procedure TTestSignature.SignXML;
68 | var
69 | LXMLDocument: IXMLSecDocument;
70 | LSignatureContext: ISignatureContext;
71 | LSigatureValueNode: IXMLSecNode;
72 | begin
73 | LXMLDocument := TXMLSecDocument.Create(TStringStream.Create(XMLSignTemplate), True);
74 |
75 | LSignatureContext := TSignatureContext.Create;
76 | LSignatureContext.LoadKey(TStringStream.Create(PrivateKey), TKeyDataFormat.Pem, True);
77 | LSignatureContext.Sign(LXMLDocument);
78 |
79 | if not LXMLDocument.TryFindNode('SignatureValue', 'http://www.w3.org/2000/09/xmldsig#', LSigatureValueNode) then
80 | begin
81 | Assert.Fail('"SignatureValue" node not found');
82 | end;
83 | Assert.AreEqual(SignatureValue, TrimAll(LSigatureValueNode.Text));
84 | end;
85 |
86 | initialization
87 | TDUnitX.RegisterTestFixture(TTestSignature);
88 |
89 | end.
90 |
--------------------------------------------------------------------------------
/Demos/bin/sp-key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIG5AIBAAKCAYEAv3lOMK4NNihmzXuKWKDVpkRMDI1LaZrQDs4zH//C5S/WxIRO
3 | jp1lsafbcgjFlLHHZKTk9tm+DpxoN+D7FbXQLiZ59Bp1Jwur2g8YzuKAKd6fX35O
4 | V4CpYkk+7avujedgWmrsYa6Nxd+pcGzKBqr5q2fQIkfqLb6OZ5DEjZo/ipHCSq1/
5 | GZpPO/5+f6YYd7KsWSj/JU1Unlw4V/LE/ISKmoDrPvAKCYbkcCY0BCNeoFl1G6KX
6 | 75Ny00fgI4lwTUHgyUhwX6gvHmstmQOqZP59RacRpQHIRI2U1bQtnybiBXH509DU
7 | 5T2z+sJU+LSGbnASZO0/PD8nIHJ7RHamTni6UkyfZRiZs6/DpYVNeZc+NGwjA1qi
8 | xf6Rgjw0YaAaX/7K8k52o6PGvWAbmttJw/d0F1F0jtd+jLXMDY1pX69LoHGZsBzm
9 | HnRe1bnzrVHa2oJtQTwNCByVIqdauSErXijGB7sGBtyX94pD+r9vf+rmGQet85Wb
10 | DYhbCmGY+LCrQ6elAgMBAAECggGBAJtgluDN/Q6bzoCk5elx6q4X8halejLiXEAH
11 | eFlZNRDCt2eVbiIw+9skueFZ2OwHMCUt4lem7qHwrmnZ+ibt+VfaBVDfP35F7Fjx
12 | s1H/X72aWH4ngu9jCxElGxnHUbh5sCjvZ48FFSsjit4eifrLN/uuLKoE7bXdUrYc
13 | NkQqjbGnAqGTFPbzz6SBqqlvYZ+QsGdR62qbzDUN5PMJoGzCKa+jOkNCiwKcIjgX
14 | 6FILWbiJn4yjbuQNJTrqsqpj12v6LkKf8AWtaOR2Rt11UsIKygvMTAaoXTtIQoES
15 | ZMK+Vde4JU3MGfi/epzH9Ds1U+UncPNOHIGjWkrM13Lb8KHJ8dWkzsrm9YNhvabS
16 | flkmVgJ3M+2wuG3K0uZ2INO+FTlVOyxUSjdKsfZLq62Vb68cyOhEPkPX51nQkzPb
17 | l/v23e3W1H0auB5StiGzdgcEBXEQWCFm7Zm8Q39keGt9u3yUJ7LkBpngS386b02f
18 | GFtNR7oOEdmyYeraQolJzGw9GOQrQQKBwQD+UPkJWkMcLwtf4waGp8b7aXQHUSl7
19 | +1kurzeKJy/mBqgAGKj/eKWd+MNWzbp+IOYkByKbPXUET/7bM/vyX7HyARej9kC1
20 | LX4t2jbo5+nzvsfgvR8LuGjwMAwQvhPcwQ+kM54Azhsz2CaEJORNZBKt0gBoU15u
21 | vVDOQndn9oLflKteHCeX1+a2BMO9sI5aRyLb+GyPeY7dfQjzJH8txZgWXhgQH1uB
22 | dHnZu7OqezjudlJwynHYF7FBAlfl8eXCFqkCgcEAwL3TBRnHEb+eALrSED1By/Ax
23 | ktkB44e4lGfLzZGHDznjWB39uIib+CtoC+QMK3thiYDEFnNxXY52+5k8nBGLYvzT
24 | KqaYmagcgpg4/AuhWCcBQBJe0GRACSRfpQ9OxLvMh83QwNkmLMOWz96LuDF4eV4m
25 | d5svz5rIkl9nbE31wfdseh03SS9XZgwB+RMBP6IiLIGLf+9agsfBf6OzrXUm/xo+
26 | WjbGQmV46aLm+0EL35dbEbXC5K9vsBu/s36tUPKdAoHAEI3gyBUSDUGasfErOZSu
27 | RStGHDvSQXnJAlrxeJK4cXa5dNgmGAsYbMIGpR3bJ96oXGwCeqxzc4ZphodJvSsx
28 | gBlGGqwq5iBB+GYd8Oc3uWAPzrdA0Bh+7DOUdXqJ/HKsu/mILXE9IBDP4QYtvkPn
29 | W10yHZhfq0GzgtmcwC2xszAQP54BjcbGA88nlq9pdMLwp/TxzB0TiaNb88fKZ4ZX
30 | Mg2J73K7GCAm1l97gHto50zYbPMgmfpg1WR7qEIovIuRAoHAagxHvge340kWC3q/
31 | N9YsjKRE8nJaOrGjWmxd02ad9D+6mfIudskbYAmp/tjj5UzGltx1h5DPMFXBm59t
32 | nMV+duF64n21et3niedteyh/Bry3UGSLLIfsP9t2kKACi/Z0i8gvctxHx9t58DeX
33 | kqoNimHGMor9XHHip768bffbH3Ueh3XpxGe649f5gez2A+gWe3xvn923ZDu6eJs+
34 | slLCORxccFCw9zlTtOE/y8C3YrepkO38JM1uW2x5Jq6td9t1AoHBAIES+XoxMkzl
35 | MUVKr403PRzdy86bqNZi2e5EQa6uu0mw5Utdx2zT9Z+q5xv1XvwwGFJsKU6IUf4t
36 | /tQLkmuiNZ4n0C5vFeSXkYjEZT5r45m6kn9YLPCgrtuvSs+0miyzzm/8rRRWpGoP
37 | NXPdtUjVs8nX3QXl3vpZO4YQtvo2wYcCZmvXGqByp8HwpebJDcCgssCynS4PzlR+
38 | wbJliOLtF7azoZJQ02HWqRukrzn/rcowrza+/XPo4HGnxfSKzitHOQ==
39 | -----END RSA PRIVATE KEY-----
40 |
--------------------------------------------------------------------------------
/Demos/XmlSec/XmlSecDemo.dpr:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | program XmlSecDemo;
24 |
25 | uses
26 | Vcl.Forms,
27 | SAML.XML.MainForm in 'SAML.XML.MainForm.pas' {chkSignatureTemplate},
28 | SAML.XML.Utils in '..\..\Sources\SAML.XML.Utils.pas',
29 | libexslt in '..\..\Sources\bindings\libexslt.pas',
30 | libxml2 in '..\..\Sources\bindings\libxml2.pas',
31 | libxmlsec in '..\..\Sources\bindings\libxmlsec.pas',
32 | libxslt in '..\..\Sources\bindings\libxslt.pas',
33 | Vcl.Themes,
34 | Vcl.Styles;
35 |
36 | {$R *.res}
37 |
38 | begin
39 | ReportMemoryLeaksOnShutdown := True;
40 | Application.Initialize;
41 | Application.MainFormOnTaskbar := True;
42 | TStyleManager.TrySetStyle('Sapphire Kamri');
43 | Application.CreateForm(TMainForm, MainForm);
44 | Application.Run;
45 | end.
46 |
--------------------------------------------------------------------------------
/Demos/Metadata/MetadataDemo.dpr:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | program MetadataDemo;
24 |
25 | uses
26 | Vcl.Forms,
27 | SAML.Forms.Main in 'SAML.Forms.Main.pas' {MainForm},
28 | SAML.Core in '..\..\Sources\SAML.Core.pas',
29 | SAML.Metadata in '..\..\Sources\SAML.Metadata.pas',
30 | SAML.XML.Utils in '..\..\Sources\SAML.XML.Utils.pas',
31 | libexslt in '..\..\Sources\bindings\libexslt.pas',
32 | libxml2 in '..\..\Sources\bindings\libxml2.pas',
33 | libxmlsec in '..\..\Sources\bindings\libxmlsec.pas',
34 | libxslt in '..\..\Sources\bindings\libxslt.pas',
35 | SAML.Config in '..\..\Sources\SAML.Config.pas';
36 |
37 | {$R *.res}
38 |
39 | begin
40 | Application.Initialize;
41 | Application.MainFormOnTaskbar := True;
42 | Application.CreateForm(TMainForm, MainForm);
43 | Application.Run;
44 | end.
45 |
--------------------------------------------------------------------------------
/Test/SAML.Test.App.dpr:
--------------------------------------------------------------------------------
1 | program SAML.Test.App;
2 |
3 | {$IFNDEF TESTINSIGHT}
4 | {$APPTYPE CONSOLE}
5 | {$ENDIF}
6 | {$STRONGLINKTYPES ON}
7 | uses
8 | System.SysUtils,
9 | {$IFDEF TESTINSIGHT}
10 | TestInsight.DUnitX,
11 | {$ELSE}
12 | DUnitX.Loggers.Console,
13 | DUnitX.Loggers.Xml.NUnit,
14 | {$ENDIF }
15 | DUnitX.TestFramework,
16 | SAML.Test.Signature in 'SAML.Test.Signature.pas',
17 | SAML.Config in '..\Sources\SAML.Config.pas',
18 | SAML.Core in '..\Sources\SAML.Core.pas',
19 | SAML.Metadata in '..\Sources\SAML.Metadata.pas',
20 | SAML.Request in '..\Sources\SAML.Request.pas',
21 | SAML.XML.Utils in '..\Sources\SAML.XML.Utils.pas',
22 | libexslt in '..\Sources\bindings\libexslt.pas',
23 | libxml2 in '..\Sources\bindings\libxml2.pas',
24 | libxmlsec in '..\Sources\bindings\libxmlsec.pas',
25 | libxslt in '..\Sources\bindings\libxslt.pas',
26 | SAML.Test.Consts in 'SAML.Test.Consts.pas',
27 | SAML.Test.Encrypt in 'SAML.Test.Encrypt.pas';
28 |
29 | {$IFNDEF TESTINSIGHT}
30 | var
31 | runner: ITestRunner;
32 | results: IRunResults;
33 | logger: ITestLogger;
34 | nunitLogger : ITestLogger;
35 | {$ENDIF}
36 | begin
37 | {$IFDEF TESTINSIGHT}
38 | TestInsight.DUnitX.RunRegisteredTests;
39 | {$ELSE}
40 | try
41 | //Check command line options, will exit if invalid
42 | TDUnitX.CheckCommandLine;
43 | //Create the test runner
44 | runner := TDUnitX.CreateRunner;
45 | //Tell the runner to use RTTI to find Fixtures
46 | runner.UseRTTI := True;
47 | //When true, Assertions must be made during tests;
48 | runner.FailsOnNoAsserts := False;
49 |
50 | //tell the runner how we will log things
51 | //Log to the console window if desired
52 | if TDUnitX.Options.ConsoleMode <> TDunitXConsoleMode.Off then
53 | begin
54 | logger := TDUnitXConsoleLogger.Create(TDUnitX.Options.ConsoleMode = TDunitXConsoleMode.Quiet);
55 | runner.AddLogger(logger);
56 | end;
57 | //Generate an NUnit compatible XML File
58 | nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile);
59 | runner.AddLogger(nunitLogger);
60 |
61 | //Run tests
62 | results := runner.Execute;
63 | if not results.AllPassed then
64 | System.ExitCode := EXIT_ERRORS;
65 |
66 | {$IFNDEF CI}
67 | //We don't want this happening when running under CI.
68 | if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then
69 | begin
70 | System.Write('Done.. press key to quit.');
71 | System.Readln;
72 | end;
73 | {$ENDIF}
74 | except
75 | on E: Exception do
76 | System.Writeln(E.ClassName, ': ', E.Message);
77 | end;
78 | {$ENDIF}
79 | end.
80 |
--------------------------------------------------------------------------------
/Demos/SAML/SPDemo.dpr:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | program SPDemo;
24 |
25 | uses
26 | Vcl.Forms,
27 | SAML.Form.Main in 'SAML.Form.Main.pas' {MainForm},
28 | SAML.XML.Utils in '..\..\Sources\SAML.XML.Utils.pas',
29 | libexslt in '..\..\Sources\bindings\libexslt.pas',
30 | libxml2 in '..\..\Sources\bindings\libxml2.pas',
31 | libxmlsec in '..\..\Sources\bindings\libxmlsec.pas',
32 | libxslt in '..\..\Sources\bindings\libxslt.pas',
33 | Vcl.Themes,
34 | Vcl.Styles,
35 | SAML.Config in '..\..\Sources\SAML.Config.pas',
36 | SAML.http.Server in 'SAML.http.Server.pas' {modHttpServer: TDataModule},
37 | SAML.Metadata in '..\..\Sources\SAML.Metadata.pas',
38 | SAML.Request in '..\..\Sources\SAML.Request.pas',
39 | SAML.Core in '..\..\Sources\SAML.Core.pas';
40 |
41 | {$R *.res}
42 |
43 | begin
44 | Application.Initialize;
45 | Application.MainFormOnTaskbar := True;
46 | TStyleManager.TrySetStyle('Sapphire Kamri');
47 | Application.CreateForm(TMainForm, MainForm);
48 | Application.Run;
49 | end.
50 |
--------------------------------------------------------------------------------
/Demos/SAML/pages/sp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | SAML Service Provider Home
8 |
9 |
10 |
11 |
12 |
13 | SAML Service Provider Home
14 |
15 |
16 | Show SAML AuthnRequest
17 |
18 |
19 | SAML Single Logout
20 |
21 |
22 |
23 |
24 |
25 |
26 |
Send the request to configured Single Sign On URL of the Identity Provider
27 |
28 |
29 | Send Request
30 |
31 |
32 |
33 |
38 |
39 |
40 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/Sources/SAML.inc:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea S.r.l. }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | { R E A D M E }
24 | { }
25 | { In this file you can change some settings used for DLL binding. }
26 | { You can use the default if you download 1.2.18 32bit version from: }
27 | { https://www.zlatkovic.com/pub/libxml/ }
28 | { Or the 64bit 1.3.3 version from: }
29 | { https://www.aleksey.com/xmlsec/download/win64/ }
30 | { }
31 | {******************************************************************************}
32 |
33 | // For the NON win32 target use xmlsec 1.3
34 | {$IFNDEF WIN32}
35 | {$DEFINE USE_XMLSEC1_3}
36 | {$ENDIF}
37 |
38 | {$DEFINE USE_VS_LIBS}
39 |
40 | // For old release in win32 use 32bit time_t
41 | {$IFNDEF USE_XMLSEC1_3}
42 | {$IFDEF WIN32}
43 | // for MinGW runtime
44 | {$DEFINE _USE_32BIT_TIME_T}
45 | {$ENDIF}
46 | {$ENDIF}
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Docs/APIDoc.md:
--------------------------------------------------------------------------------
1 | # API Documentation
2 |
3 | ## XML Handling
4 |
5 | The challenging part of SAML is the handling of *XML cryptography*. Every XML it's cipher with some cryptographic algorithm. This project uses the standard XmlSec library to handle these functions. In the binding folder, you can find the low-level API translated from C to Pascal. But I recommend using the wrapper in `SAML.XML.Utils` unit.
6 |
7 | Every object in this unit has an *interface* wrapper so you can create the objects without the need to destroy it. Furthermore when you pass a stream to an object (e.g. a key to a context) you can delegate the responsibility to destroy the stream to the object itself.
8 |
9 | With the following code when the *LSignatureContext* has done its work it automatically destry the *LByteStream*.
10 |
11 | ```pascal
12 | LSignatureContext.LoadKey(LByteStream, TKeyDataFormat.Der, True);
13 | ```
14 |
15 | Here you can find an example of how to sign a XML file; for other examples you can check the *XmlSecDemo* project.
16 |
17 | **Sign a document**
18 |
19 | ```pascal
20 | procedure TMainForm.btnSignClick(Sender: TObject);
21 | var
22 | // Reference to XML document
23 | LXMLDocument: IXMLSecDocument;
24 | // The main "context" that holds the keys for signing and cipher
25 | LSignatureContext: ISignatureContext;
26 | begin
27 | // The IXMLSecDocument reads the data from a stream and can
28 | // handle the life cycle of it
29 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
30 | // Set the ID of the XML to find the XML fragment to sign
31 | LXMLDocument.AddIDAttr('ID', 'AuthnRequest', 'urn:oasis:names:tc:SAML:2.0:protocol');
32 |
33 | // Create the SignatureContext
34 | LSignatureContext := TSignatureContext.Create;
35 | // Add a private to the context
36 | LSignatureContext.LoadKey(TFileStream.Create(edtPrivateKeyName.Text, fmOpenRead), TKeyDataFormat(edtPrivateKeyFormat.ItemIndex), True);
37 | // Sign the document
38 | LSignatureContext.Sign(LXMLDocument);
39 |
40 | // Retrieve the signed XML as string
41 | memOutput.Text := LXMLDocument.ToXML;
42 | // And save the signed XML to a file
43 | LXMLDocument.SaveToFile(edtOutputXMLName.Text);
44 | end;
45 | ```
46 |
47 | ## SAML Message
48 |
49 | The unit `SAML.Request` contains the classes to handle `requests` and `reponses`. If you need to create a new SAML request you can use the helper class `TSAMLRequestBuilder` that use a fluent interface:
50 |
51 | ```pascal
52 | function BuildAuthnRequest(const AIssuer: string): string;
53 | begin
54 | Result := TSAMLAuthnRequest.New
55 | .SetID('SAML_' + IntToStr(Random(1000000000)))
56 | .SetIssuer(AIssuer)
57 | .SetSigned(True)
58 | .SetProtocolBinding(TSAML.BINDINGS_HTTP_POST)
59 | .AsXML;
60 | end;
61 | ```
62 |
63 | Then you can sign the request with the `SAML.XML.Utils` unit.
64 |
65 | ## SAML Metadata
66 |
67 | To securely interoperate SAML uses XML metadata that describes both the Service Provider and Identity Provider. `Delphi SAML` provides a class to read and create these files. You can use a builder with a fluent interface like the example below:
68 |
69 | ```pascal
70 | LMetadata := TSAMLMetadata.New
71 | .SetEntityID('urn:test.samltest:sp')
72 | .SetProtocolBinding(TSAML.BINDINGS_HTTP_POST)
73 | .SetCacheDuration('PT604800S')
74 | ...
75 | .AsXML;
76 | ```
--------------------------------------------------------------------------------
/Sources/bindings/libexslt.pas:
--------------------------------------------------------------------------------
1 | {This file generated automatically from libexslt-api.xml}
2 | {For libexslt version: 0.8.13}
3 | Unit libexslt;
4 |
5 | interface
6 |
7 | {$INCLUDE ../SAML.inc}
8 |
9 | {$ALIGN 8}
10 | {$MINENUMSIZE 4}
11 |
12 | uses libxml2, libxslt;
13 |
14 | const
15 | {$IFDEF MSWINDOWS}
16 | LIBEXSLT_SO = {$IFDEF USE_VS_LIBS}'libexslt.dll'{$ELSE}'libexslt-0.dll'{$ENDIF};
17 | {$ELSE}
18 | LIBEXSLT_SO = 'libexslt.so';
19 | {$ENDIF}
20 |
21 | //type
22 |
23 |
24 | procedure exsltCommonRegister (); cdecl; external LIBEXSLT_SO;
25 | procedure exsltCryptoRegister (); cdecl; external LIBEXSLT_SO;
26 | procedure exsltDateRegister (); cdecl; external LIBEXSLT_SO;
27 | procedure exsltDynRegister (); cdecl; external LIBEXSLT_SO;
28 | procedure exsltFuncRegister (); cdecl; external LIBEXSLT_SO;
29 | procedure exsltMathRegister (); cdecl; external LIBEXSLT_SO;
30 | procedure exsltRegisterAll (); cdecl; external LIBEXSLT_SO;
31 | procedure exsltSaxonRegister (); cdecl; external LIBEXSLT_SO;
32 | procedure exsltSetsRegister (); cdecl; external LIBEXSLT_SO;
33 | procedure exsltStrRegister (); cdecl; external LIBEXSLT_SO;
34 | function exsltLibexsltVersion(): Longint; cdecl;
35 | function exsltLibraryVersion(): PChar; cdecl;
36 | function exsltLibxmlVersion(): Longint; cdecl;
37 | function exsltLibxsltVersion(): Longint; cdecl;
38 |
39 | implementation
40 | uses
41 | {$IFDEF MSWINDOWS}
42 | Windows,
43 | {$ENDIF}
44 | SysUtils;
45 |
46 | var
47 | libHandle: THandle;
48 |
49 | // Utility function to make sure procedure entry points are not null
50 |
51 | procedure CheckForNil(ptr: Pointer; name:string);
52 | begin
53 | if not Assigned(ptr) then
54 | raise Exception.Create('"' + name + '" could not be loaded from the dynamic library ' + LIBEXSLT_SO);
55 | end;
56 |
57 | var
58 | pexsltLibexsltVersion: PInteger;
59 |
60 | function exsltLibexsltVersion: Longint;
61 | begin
62 | CheckForNil(pexsltLibexsltVersion, 'exsltLibexsltVersion');
63 | Result := pexsltLibexsltVersion^;
64 | end;
65 |
66 | var
67 | pexsltLibraryVersion: PPChar;
68 |
69 | function exsltLibraryVersion: PChar;
70 | begin
71 | CheckForNil(pexsltLibraryVersion, 'exsltLibraryVersion');
72 | Result := pexsltLibraryVersion^;
73 | end;
74 |
75 | var
76 | pexsltLibxmlVersion: PInteger;
77 |
78 | function exsltLibxmlVersion: Longint;
79 | begin
80 | CheckForNil(pexsltLibxmlVersion, 'exsltLibxmlVersion');
81 | Result := pexsltLibxmlVersion^;
82 | end;
83 |
84 | var
85 | pexsltLibxsltVersion: PInteger;
86 |
87 | function exsltLibxsltVersion: Longint;
88 | begin
89 | CheckForNil(pexsltLibxsltVersion, 'exsltLibxsltVersion');
90 | Result := pexsltLibxsltVersion^;
91 | end;
92 |
93 |
94 |
95 | initialization
96 | // The Delphi 'external' directive can be used for functions and procedures,
97 | // but here we need to obtain the addresses of POINTERS to functions. We can
98 | // get to these addresses (and also those of other data values exported from
99 | // the DLL) by using GetProcAddress.
100 | libHandle := LoadLibrary(LIBEXSLT_SO);
101 | if libHandle <> 0 then
102 | begin
103 | pexsltLibexsltVersion := PInteger(GetProcAddress(libHandle, 'exsltLibexsltVersion'));
104 | pexsltLibraryVersion := PPChar(GetProcAddress(libHandle, 'exsltLibraryVersion'));
105 | pexsltLibxmlVersion := PInteger(GetProcAddress(libHandle, 'exsltLibxmlVersion'));
106 | pexsltLibxsltVersion := PInteger(GetProcAddress(libHandle, 'exsltLibxsltVersion'));
107 |
108 | FreeLibrary(libHandle);
109 | end;
110 |
111 | end.
112 |
--------------------------------------------------------------------------------
/Demos/bin/keygen.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal
3 |
4 | set DAYS=
5 | set YEARS=
6 | set FQDN=
7 | set ENTITYID=
8 | set TEMP_DOMAIN_NAME=
9 | set PARAM=
10 | set PREFIX=
11 | set OUT=%~dp0
12 |
13 | :opt_start
14 | set PARAM=%1
15 |
16 | if not defined PARAM goto opt_end
17 | if %1==-o goto opt_out
18 | if %1==-n goto opt_prefix
19 | if %1==-h goto opt_fqdn
20 | if %1==-e goto opt_entityid
21 | if %1==-y goto opt_years
22 | if %1==-f goto opt_force
23 | goto usage
24 | :opt_end
25 |
26 | if not defined PREFIX set PREFIX=sp
27 |
28 | if exist "%OUT%\%PREFIX%-key.pem" goto protect
29 | if exist "%OUT%\%PREFIX%-cert.pem" goto protect
30 |
31 | if not defined YEARS set YEARS=10
32 | set /a DAYS=%YEARS%*365
33 |
34 | if not defined FQDN goto guess_fqdn
35 |
36 | :generate
37 | set PATH=%PATH%;%ProgramFiles%\Shibboleth\SP\lib\
38 | set CNF="%OUT%\%PREFIX%-cert.cnf"
39 | echo # OpenSSL configuration file for creating keypair >%CNF%
40 | echo [req] >>%CNF%
41 | echo prompt=no >>%CNF%
42 | echo default_bits=3072 >>%CNF%
43 | echo encrypt_key=no >>%CNF%
44 | echo default_md=sha256 >>%CNF%
45 | echo distinguished_name=dn >>%CNF%
46 | echo # PrintableStrings only >>%CNF%
47 | echo string_mask=MASK:0002 >>%CNF%
48 | echo x509_extensions=ext >>%CNF%
49 | echo [dn] >>%CNF%
50 | echo CN=%FQDN% >>%CNF%
51 | echo [ext] >>%CNF%
52 | if defined ENTITYID (echo subjectAltName=DNS:%FQDN%,URI:%ENTITYID% >>%CNF%) else (echo subjectAltName=DNS:%FQDN% >>%CNF%)
53 | echo subjectKeyIdentifier=hash >>%CNF%
54 | openssl.exe req -config %CNF% -new -x509 -days %DAYS% -keyout "%OUT%\%PREFIX%-key.pem" -out "%OUT%\%PREFIX%-cert.pem"
55 | openssl x509 -in "%OUT%\%PREFIX%-cert.pem" -out "%OUT%\%PREFIX%-cert.crt"
56 |
57 | del %CNF%
58 | exit /b
59 |
60 | :protect
61 | echo The files %OUT%\%PREFIX%-key.pem and/or %OUT%\%PREFIX%-cert.pem already exist!
62 | echo Use -f option to force recreation of keypair.
63 | exit /b
64 |
65 | :opt_out
66 | set OUT=%2
67 | shift
68 | shift
69 | goto opt_start
70 |
71 | :opt_prefix
72 | set PREFIX=%2
73 | shift
74 | shift
75 | goto opt_start
76 |
77 | :opt_force
78 | if exist "%OUT%\%PREFIX%-key.pem" del "%OUT%\%PREFIX%-key.pem"
79 | if exist "%OUT%\%PREFIX%-cert.pem" del "%OUT%\%PREFIX%-cert.pem"
80 | shift
81 | goto opt_start
82 |
83 | :opt_fqdn
84 | set FQDN=%2
85 | shift
86 | shift
87 | goto opt_start
88 |
89 | :opt_entityid
90 | set ENTITYID=%2
91 | shift
92 | shift
93 | goto opt_start
94 |
95 | :opt_years
96 | set YEARS=%2
97 | shift
98 | shift
99 | goto opt_start
100 |
101 | :usage
102 | echo usage: keygen [-h hostname for cert] [-y years to issue cert] [-e entityID to embed in cert] [-n filename prefix] [-o output dir]
103 | exit /b
104 |
105 | :guess_fqdn
106 | for /F "tokens=2 delims=:" %%i in ('"ipconfig /all | findstr /c:"Primary DNS Suffix" /c:"Primary Dns Suffix""') do set TEMP_DOMAIN_NAME=%%i
107 | if defined TEMP_DOMAIN_NAME set FQDN=%TEMP_DOMAIN_NAME: =%
108 | set TEMP_DOMAIN_NAME=
109 | if defined USERDNSDOMAIN set FQDN=%USERDNSDOMAIN%
110 |
111 | for /F %%i in ('hostname') do set HOST=%%i
112 | if defined FQDN (set FQDN=%HOST%.%FQDN%) else (set FQDN=%HOST%)
113 |
114 | echo >"%FQDN%"
115 | for /F %%i in ('dir /b/l %FQDN%') do set FQDN=%%i
116 | del %FQDN%
117 | goto generate
118 |
--------------------------------------------------------------------------------
/Sources/SAML.Core.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea S.r.l. }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | unit SAML.Core;
24 |
25 | interface
26 |
27 | uses
28 | System.Classes, System.SysUtils, System.NetEncoding;
29 |
30 | type
31 | ESAMLError = class(Exception)
32 | end;
33 |
34 | TSAML = class
35 | const
36 | BINDINGS_HTTP_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST';
37 | BINDINGS_HTTP_REDIRECT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect';
38 |
39 | AUTHCONTEXT_PasswordProtectedTransport = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport';
40 | AUTHCONTEXT_SpidL1 = 'https://www.spid.gov.it/SpidL1';
41 | AUTHCONTEXT_SpidL2 = 'https://www.spid.gov.it/SpidL2';
42 | AUTHCONTEXT_SpidL3 = 'https://www.spid.gov.it/SpidL3';
43 | end;
44 |
45 | function Base64EncodeStr(const ABytes: TBytes): string;
46 |
47 | function PemToDer(APemCertificate: TBytes): TBytes;
48 |
49 | function GetGuid: string;
50 |
51 | implementation
52 |
53 | uses
54 | IdSSLOpenSSL, IdSSLOpenSSLHeaders;
55 |
56 | function GetGuid: string;
57 | begin
58 | Result := GUIDToString(TGUID.NewGuid);
59 | Result := StringReplace(Result, '{', '', []);
60 | Result := StringReplace(Result, '}', '', []);
61 | end;
62 |
63 | function PemToDer(APemCertificate: TBytes): TBytes;
64 | var
65 | BIOBuffer: PBIO;
66 | X509Certificate: PX509;
67 | LDerCertificate: PByte;
68 | LDerCertificateLen: Integer;
69 | begin
70 | IdSSLOpenSSL.LoadOpenSSLLibrary;
71 |
72 | BIOBuffer := BIO_new_mem_buf(@APemCertificate[0], Length(APemCertificate));
73 | if not Assigned(BIOBuffer) then
74 | raise ESAMLError.Create('Invalid certificate buffer');
75 |
76 | try
77 | X509Certificate := PEM_read_bio_X509(BIOBuffer, nil, nil, nil);
78 | if not Assigned(X509Certificate) then
79 | raise ESAMLError.Create('Invalid certificate');
80 | try
81 | LDerCertificate := nil;
82 | LDerCertificateLen := i2d_X509(X509Certificate, @LDerCertificate);
83 | if LDerCertificateLen > 0 then
84 | begin
85 | SetLength(Result, LDerCertificateLen);
86 | Move(LDerCertificate^, Result[0], LDerCertificateLen);
87 | end;
88 |
89 | finally
90 | X509_free(X509Certificate);
91 | end;
92 | finally
93 | BIO_free(BIOBuffer);
94 | end;
95 | end;
96 |
97 |
98 | function Base64EncodeStr(const ABytes: TBytes): string;
99 | const
100 | BASE64_NO_LINE_BREAK = 0;
101 | var
102 | Base64: TBase64Encoding;
103 | begin
104 | Base64 := TBase64Encoding.Create(BASE64_NO_LINE_BREAK);
105 | try
106 | Result := Base64.EncodeBytesToString(ABytes);
107 | finally
108 | Base64.Free;
109 | end;
110 | end;
111 |
112 | end.
113 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Delphi SAML implementation
2 |
3 | [](https://opensource.org/licenses/Apache-2.0)
4 |
5 | **Delphi SAML** is a SAML implementation written on top of [xmlsec](https://www.aleksey.com/xmlsec/). The basic idea behind the code comes from [samltools](https://github.com/monmohan/samltools).
6 |
7 | Supported Delphi versions: from Delphi 10.1 to Delphi 13
8 |
9 | 
10 |
11 | ## How to setup a service provider locally?
12 |
13 | * Clone the repo
14 | * Copy all the DLL in the Demos\bin folder (see *installation*)
15 | * Setup a loopback mapping to "sp.samltools.com". On windows:
16 | * Open `C:\Windows\System32\drivers\etc\hosts`
17 | * Add `127.0.0.1 sp.samltools.com`
18 | * Compile Demos\SAML\SPDemo.dpr
19 | * Run it
20 | * Choose `idp-auth0.ini` in Identity Provider settings
21 | * Choose `sp-auth0.ini` in Serivce Provider settings
22 | * Click `Open Browser` and follow the instructions
23 |
24 | ## Demo
25 |
26 | 
27 |
28 | ## Installation
29 |
30 | Download the zip files for your platform and extract all DLLs into the demos\bin folder.
31 | You can found the precompiled binaries of the DLL here:
32 |
33 | * *32bit*: https://www.zlatkovic.com/pub/libxml/
34 | * *64bit*: https://www.aleksey.com/xmlsec/download/win64/
35 |
36 | The required DLL are:
37 |
38 | * `libxmlsec.dll`: main DLL
39 | * `libxml2.dll`: to handle XML
40 | * `iconv.dll`: to convert between charsets
41 | * `libxmlsec-mscrypto.dll`: if you want to use cryptographics functions from *msCrypto* (install msCrypto from MS)
42 | * `libxmlsec-openssl.dll`: or if you want to use cryptographics functions from *OpenSSL*
43 | * `libeay32.dll`
44 | * `ssleay32.dll`
45 | * `zlib1.dll`: compression... but I'm not sure who need it
46 | * `libexslt.dll`: xsl transformations (optional)
47 | * `libxslt.dll`: xsl transformations (optional)
48 |
49 | If you want you can extract `xmlsec.exe` and `openssl.exe`. The first can be used to test XML signing and encryption, and the second to handle certificates and cryptography.
50 |
51 | ## TODO
52 |
53 | * 📌 Better metadata support
54 | * ✨ Identity provider implementation
55 | * ✨ Basic key format conversion (PEM, DER, ...)
56 |
57 | ## Documentation
58 |
59 | `Delphi SAML` consists of some modules:
60 |
61 | * The cryptographic units: used to handle signing and encryption
62 | * The SAML message units: to build request and parse response
63 | * The metadata unit: to read and write metadata
64 | * The demos: to see how `Delphi SAML` works
65 |
66 | If you need more help you can read the [API documentation](Docs/APIDoc.md).
67 |
68 | ## License
69 |
70 | `Delphi SAML` is released under the term of the *Apache License*. Here follows the licenses of all dependencies:
71 |
72 | | Library | License | Using with proprietary applications/libraries |
73 | | --- | --- | ---- |
74 | | xmlsec-core | MIT license | Yes |
75 | | xmlsec-openssl | OpenSSL License | Yes |
76 | | xmlsec-mscrypto | Microsoft licensing: The libraries are part of MS Windows, and are also distributed with Internet Explorer. | Unknown |
77 | | libxml2 | MIT license | Yes |
78 | | iconv | LGPL | Yes |
79 | | openssl | Apache-2.0 license | Yes |
80 | | zlib1 | Zlib license | Yes |
81 | | libexslt | MIT License | Yes |
82 | | libxslt | MIT License | Yes |
83 |
84 | ## Resources
85 |
86 | SAML documentation:
87 |
88 | * http://docs.oasis-open.org/security/saml/v2.0/saml-2.0-os.zip
89 | * https://developer.okta.com/docs/concepts/saml/
90 | * https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/overview
91 | * https://en.wikipedia.org/wiki/SAML_2.0
92 |
93 | XML-Sec API:
94 |
95 | * https://www.aleksey.com/xmlsec/api/
96 |
97 | Resources:
98 |
99 | * https://samltest.id/
100 | * https://www.samltool.com/online_tools.php
101 | * https://github.com/monmohan/samltools
102 |
103 |
104 | ## Generate the keys
105 |
106 | If you want to sign you request you need a private and a public key. You can generate both with this command:
107 |
108 | ```
109 | keygen.bat -h sp.samltools.com -e urn:msingh.samltools:sp -y 10
110 | ```
111 |
112 | See [command line](Docs/CommandLine.md) for further detail.
113 |
114 | Release Notes:
115 | ver.1.3.0 - 13 Mar 2023
116 | - 64bit support
117 | - support for xmlsec 1.3
118 | - New SAML.inc file to use the right version of the DLLs bindings
119 | - Better demo
120 | - Support for encrypted private keys
121 |
122 | ver.1.2.0 - 11 Jul 2023
123 | - Certificates and keys can be loaded from a buffer
124 | - SP configuration improvement: NameIdFormat, Comparison, IssuerNameQualifier, IssuerFormat
125 | - Support for signatures in nodes different from the root node
126 |
127 | ver.1.1.0 - 1 Apr 2023
128 | - SPID support (Italy's public digital identity)
129 | - Support for HTTP-POST binding
130 | - New AuthnRequest attribute "AuthnContext"
131 |
132 | ver.1.0.0 - 24 Oct 2022
133 | - First stable version
134 |
135 |
--------------------------------------------------------------------------------
/Samples/sp-metadata-with-keys.xml:
--------------------------------------------------------------------------------
1 |
5 |
8 |
9 |
10 |
11 | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVEekNDQW5lZ0F3SUJBZ0lKQVBnN1BUUUFudERvTUEwR0NTcUdTSWIzRFFFQkN3VUFNQnN4R1RBWEJnTlYKQkFNVEVITndMbXgxWTJGdGFXNTFkR2t1YVhRd0hoY05Nakl3T1RJeE1Ea3dNRFU0V2hjTk16SXdPVEU0TURrdwpNRFU0V2pBYk1Sa3dGd1lEVlFRREV4QnpjQzVzZFdOaGJXbHVkWFJwTG1sME1JSUJvakFOQmdrcWhraUc5dzBCCkFRRUZBQU9DQVk4QU1JSUJpZ0tDQVlFQXYzbE9NSzROTmlobXpYdUtXS0RWcGtSTURJMUxhWnJRRHM0ekgvL0MKNVMvV3hJUk9qcDFsc2FmYmNnakZsTEhIWktUazl0bStEcHhvTitEN0ZiWFFMaVo1OUJwMUp3dXIyZzhZenVLQQpLZDZmWDM1T1Y0Q3BZa2srN2F2dWplZGdXbXJzWWE2TnhkK3BjR3pLQnFyNXEyZlFJa2ZxTGI2T1o1REVqWm8vCmlwSENTcTEvR1pwUE8vNStmNllZZDdLc1dTai9KVTFVbmx3NFYvTEUvSVNLbW9EclB2QUtDWWJrY0NZMEJDTmUKb0ZsMUc2S1g3NU55MDBmZ0k0bHdUVUhneVVod1g2Z3ZIbXN0bVFPcVpQNTlSYWNScFFISVJJMlUxYlF0bnliaQpCWEg1MDlEVTVUMnorc0pVK0xTR2JuQVNaTzAvUEQ4bklISjdSSGFtVG5pNlVreWZaUmlaczYvRHBZVk5lWmMrCk5Hd2pBMXFpeGY2UmdqdzBZYUFhWC83SzhrNTJvNlBHdldBYm10dEp3L2QwRjFGMGp0ZCtqTFhNRFkxcFg2OUwKb0hHWnNCem1IblJlMWJuenJWSGEyb0p0UVR3TkNCeVZJcWRhdVNFclhpakdCN3NHQnR5WDk0cEQrcjl2ZitybQpHUWV0ODVXYkRZaGJDbUdZK0xDclE2ZWxBZ01CQUFHalZqQlVNRE1HQTFVZEVRUXNNQ3FDRUhOd0xteDFZMkZ0CmFXNTFkR2t1YVhTR0ZuVnlianAwWlhOMExteDFZMkZ0YVc1MWRHazZjM0F3SFFZRFZSME9CQllFRk5TU0lxYUUKNmVRTFo2MkVwVGFkbkFPZnR6ajdNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJnUUNUYTlQTXdYSXgzQzBubC9CbApzMk5QSGtIWjdETnAxZHpNN2ZhL3ZiZERiZ01wM2VtZ1RSUldIYUttTk5ReHl2NGhvc0RiUmpiTWhYeGNyM280ClNXVjJCa1dDM0RkaXlpajJZQzVnOFlvQ0pxK0Y5b0ZYWmN0eUxKUERpeDhmUlFVOFBINFI3SHMxYllmcU9YaTEKMGg0VmNqa3hNbzhRb2IrOGczdGN4SnNRMDJTWTBCRytzY1Z0R0dBdlBwYlY4SXpJM3pVMjNpbTFuSFhWbjVwMApoTzA4ZzgrNThGVW9aTFhXT1JhM09IVGxkeWtrRGRRUE9oMjRwTU1qVHVJY28yZXo5Uzk0RWVaK2FuRHAzbElLCjIxZzYxMEJ3QWhFcm1aNTNFeVJvWFpjZTBWU0ZIeHZmbTdWUnNqRGNlVm9INHFUSnRINTNsZFdpZkFsN3N3a3IKd0NCUG05am9wSHdyMURTYXZ4RzRwb2ovM3gyZ3lJcld4UEJDdkorUzB1RndFbWY0MmhlTmdwRzVrSUdDaCsrQwpyNWZ0S3crdU1SL2RaZkxXaDh5d2E2S3paVDlnMG8yc1dFU0t4RXB3ejFwdnZPL1pERUxianh3UWFhMG1vdGZOClM0WFl3WnRkKzYxUTNDNldxalNkbzRkUndHS1lBMEk4MXB3YVRSTGxpY0VwTVhJPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
12 |
13 |
14 |
15 |
16 |
17 |
18 | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVEekNDQW5lZ0F3SUJBZ0lKQVBnN1BUUUFudERvTUEwR0NTcUdTSWIzRFFFQkN3VUFNQnN4R1RBWEJnTlYKQkFNVEVITndMbXgxWTJGdGFXNTFkR2t1YVhRd0hoY05Nakl3T1RJeE1Ea3dNRFU0V2hjTk16SXdPVEU0TURrdwpNRFU0V2pBYk1Sa3dGd1lEVlFRREV4QnpjQzVzZFdOaGJXbHVkWFJwTG1sME1JSUJvakFOQmdrcWhraUc5dzBCCkFRRUZBQU9DQVk4QU1JSUJpZ0tDQVlFQXYzbE9NSzROTmlobXpYdUtXS0RWcGtSTURJMUxhWnJRRHM0ekgvL0MKNVMvV3hJUk9qcDFsc2FmYmNnakZsTEhIWktUazl0bStEcHhvTitEN0ZiWFFMaVo1OUJwMUp3dXIyZzhZenVLQQpLZDZmWDM1T1Y0Q3BZa2srN2F2dWplZGdXbXJzWWE2TnhkK3BjR3pLQnFyNXEyZlFJa2ZxTGI2T1o1REVqWm8vCmlwSENTcTEvR1pwUE8vNStmNllZZDdLc1dTai9KVTFVbmx3NFYvTEUvSVNLbW9EclB2QUtDWWJrY0NZMEJDTmUKb0ZsMUc2S1g3NU55MDBmZ0k0bHdUVUhneVVod1g2Z3ZIbXN0bVFPcVpQNTlSYWNScFFISVJJMlUxYlF0bnliaQpCWEg1MDlEVTVUMnorc0pVK0xTR2JuQVNaTzAvUEQ4bklISjdSSGFtVG5pNlVreWZaUmlaczYvRHBZVk5lWmMrCk5Hd2pBMXFpeGY2UmdqdzBZYUFhWC83SzhrNTJvNlBHdldBYm10dEp3L2QwRjFGMGp0ZCtqTFhNRFkxcFg2OUwKb0hHWnNCem1IblJlMWJuenJWSGEyb0p0UVR3TkNCeVZJcWRhdVNFclhpakdCN3NHQnR5WDk0cEQrcjl2ZitybQpHUWV0ODVXYkRZaGJDbUdZK0xDclE2ZWxBZ01CQUFHalZqQlVNRE1HQTFVZEVRUXNNQ3FDRUhOd0xteDFZMkZ0CmFXNTFkR2t1YVhTR0ZuVnlianAwWlhOMExteDFZMkZ0YVc1MWRHazZjM0F3SFFZRFZSME9CQllFRk5TU0lxYUUKNmVRTFo2MkVwVGFkbkFPZnR6ajdNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJnUUNUYTlQTXdYSXgzQzBubC9CbApzMk5QSGtIWjdETnAxZHpNN2ZhL3ZiZERiZ01wM2VtZ1RSUldIYUttTk5ReHl2NGhvc0RiUmpiTWhYeGNyM280ClNXVjJCa1dDM0RkaXlpajJZQzVnOFlvQ0pxK0Y5b0ZYWmN0eUxKUERpeDhmUlFVOFBINFI3SHMxYllmcU9YaTEKMGg0VmNqa3hNbzhRb2IrOGczdGN4SnNRMDJTWTBCRytzY1Z0R0dBdlBwYlY4SXpJM3pVMjNpbTFuSFhWbjVwMApoTzA4ZzgrNThGVW9aTFhXT1JhM09IVGxkeWtrRGRRUE9oMjRwTU1qVHVJY28yZXo5Uzk0RWVaK2FuRHAzbElLCjIxZzYxMEJ3QWhFcm1aNTNFeVJvWFpjZTBWU0ZIeHZmbTdWUnNqRGNlVm9INHFUSnRINTNsZFdpZkFsN3N3a3IKd0NCUG05am9wSHdyMURTYXZ4RzRwb2ovM3gyZ3lJcld4UEJDdkorUzB1RndFbWY0MmhlTmdwRzVrSUdDaCsrQwpyNWZ0S3crdU1SL2RaZkxXaDh5d2E2S3paVDlnMG8yc1dFU0t4RXB3ejFwdnZPL1pERUxianh3UWFhMG1vdGZOClM0WFl3WnRkKzYxUTNDNldxalNkbzRkUndHS1lBMEk4MXB3YVRSTGxpY0VwTVhJPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
19 |
20 |
21 |
22 | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
23 |
26 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Docs/Samples.md:
--------------------------------------------------------------------------------
1 | # Low level samples
2 |
3 | ## Sign a file
4 |
5 | ```pascal
6 | function sign_file(tmpl_file: PAnsiChar; key_file: PAnsiChar): string;
7 | var
8 | doc: xmlDocPtr;
9 | node: xmlNodePtr;
10 | dsigCtx: xmlSecDSigCtxPtr;
11 | PResult :xmlCharPtr;
12 | ResLength: Integer;
13 | //res: Integer;
14 | begin
15 | doc := nil;
16 | //node := nil;
17 | dsigCtx := nil;
18 | //Result := -1;
19 |
20 | assert(tmpl_file <> nil);
21 | assert(key_file <> nil);
22 |
23 | try
24 |
25 | xmlSetGenericErrorFunc(nil, Callback);
26 |
27 | XmlCryptInit;
28 |
29 | //res = xmlSecCryptoDLLoadLibrary('libxmlsec-openssl.dll');
30 | // if xmlSecCryptoDLLoadLibrary('openssl') < 0 then
31 | // begin
32 | // raise ESignError.Create('Error: unable to load default xmlsec-crypto library');
33 | // end;
34 |
35 | // load template
36 | doc := xmlParseFile(tmpl_file);
37 | if (doc = nil) or (xmlDocGetRootElement(doc) = nil) then
38 | begin
39 | raise ESignError.CreateFmt('Error: unable to parse file "%s"', [tmpl_file]);
40 | end;
41 |
42 | // find start node */
43 | node := xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
44 | if node = nil then
45 | begin
46 | raise ESignError.CreateFmt('Error: start node not found in "%s"', [tmpl_file]);
47 | end;
48 |
49 | // create signature context, we don't need keys manager in this example */
50 | dsigCtx := xmlSecDSigCtxCreate(nil);
51 | if dsigCtx = nil then
52 | begin
53 | raise ESignError.Create('Error: failed to create signature context');
54 | end;
55 |
56 | // load private key, assuming that there is not password */
57 | dsigCtx.signKey := xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, nil, nil, nil);
58 | if dsigCtx.signKey = nil then
59 | begin
60 | raise ESignError.CreateFmt('Error: failed to load private pem key from "%s"', [key_file]);
61 | end;
62 |
63 | // set key name to the file name, this is just an example! */
64 | if xmlSecKeySetName(dsigCtx.signKey, PAnsiChar(key_file)) < 0 then
65 | begin
66 | raise ESignError.CreateFmt('Error: failed to set key name for key from "%s"', [key_file]);
67 | end;
68 |
69 | // sign the template */
70 | if xmlSecDSigCtxSign(dsigCtx, node) < 0 then
71 | begin
72 | raise ESignError.Create('Error: signature failed');
73 | end;
74 |
75 | // print signed document to stdout
76 | //xmlDocDump(nil, doc); // TODO: nil => stdout
77 | //xmlSaveFile('output.xml', doc);
78 |
79 | //xmlDocDumpFormatMemoryEnc(doc, @PResult, @ResLength, doc.encoding, 1);
80 | xmlDocDumpFormatMemoryEnc(doc, @PResult, @ResLength, 'UTF8', 1);
81 |
82 | //OutputDebugStringA(PResult);
83 | Result := UTF8ToString(PResult);
84 |
85 | // success
86 | //Result := 0;
87 | finally
88 | // cleanup
89 | if dsigCtx <> nil then
90 | begin
91 | xmlSecDSigCtxDestroy(dsigCtx);
92 | end;
93 |
94 | if doc <> nil then
95 | begin
96 | xmlFreeDoc(doc);
97 | end;
98 | XmlCryptShutdown;
99 | end;
100 | end;
101 | ```
102 |
103 | ## Verify a file
104 |
105 | ```pascal
106 | function verify_file(const xml_file, key_file: PAnsiChar): Boolean;
107 | var
108 | doc: xmlDocPtr;
109 | node: xmlNodePtr;
110 | dsigCtx: xmlSecDSigCtxPtr;
111 | begin
112 | doc := nil;
113 | //node := nil;
114 | dsigCtx := nil;
115 |
116 | assert(xml_file <> nil);
117 | assert(key_file <> nil);
118 |
119 | try
120 |
121 | xmlSetGenericErrorFunc(nil, Callback);
122 |
123 | XmlCryptInit;
124 |
125 |
126 | (* load file *)
127 | doc := xmlParseFile(xml_file);
128 | if (doc = nil) or (xmlDocGetRootElement(doc) = nil) then
129 | begin
130 | raise ESignError.CreateFmt('Error: unable to parse file "%s"', [xml_file]);
131 | end;
132 |
133 | (* find start node *)
134 | node := xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
135 | if node = nil then
136 | begin
137 | raise ESignError.CreateFmt('Error: start node not found in "%s"', [xml_file]);
138 | end;
139 |
140 | (* create signature context, we don't need keys manager in this example *)
141 | dsigCtx := xmlSecDSigCtxCreate(nil);
142 | if dsigCtx = nil then
143 | begin
144 | raise ESignError.Create('Error: failed to create signature context');
145 | end;
146 |
147 | (* load public key *)
148 | dsigCtx.signKey := xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatCertPem, nil, nil, nil);
149 | if dsigCtx.signKey = nil then
150 | begin
151 | raise ESignError.CreateFmt('Error: failed to load public pem key from "%s"', [key_file]);
152 | end;
153 |
154 | (* set key name to the file name, this is just an example! *)
155 | if xmlSecKeySetName(dsigCtx.signKey, key_file) < 0 then
156 | begin
157 | raise ESignError.CreateFmt('Error: failed to set key name for key from "%s', [key_file]);
158 | end;
159 |
160 | (* Verify signature *)
161 | if xmlSecDSigCtxVerify(dsigCtx, node) < 0 then
162 | begin
163 | raise ESignError.Create('Error: signature verify');
164 | end;
165 |
166 | (* print verification result to stdout *)
167 | Result := dsigCtx.status = xmlSecDSigStatusSucceeded;
168 |
169 | finally
170 | (* cleanup *)
171 | if dsigCtx <> nil then
172 | xmlSecDSigCtxDestroy(dsigCtx);
173 |
174 | if doc <> nil then
175 | xmlFreeDoc(doc);
176 |
177 | XmlCryptShutdown;
178 | end;
179 | end;
180 | ```
181 |
182 |
--------------------------------------------------------------------------------
/README.htm:
--------------------------------------------------------------------------------
1 |
32 | Delphi SAML implementation
33 |
34 | Delphi SAML is a SAML implementation written on top of xmlsec . The basic idea behind the code comes from samltools .
35 | Supported Delphi versions: from Delphi 10.1 to Delphi 13
36 |
37 | How to setup a service provider locally?
38 |
39 | Clone the repo
40 | Copy all the DLL in the Demos\bin folder (see installation )
41 | Setup a loopback mapping to “sp.samltools.com”. On windows:
42 | Open C:\Windows\System32\drivers\etc\hosts
43 | Add 127.0.0.1 sp.samltools.com
44 | Compile Demos\SAML\SPDemo.dpr
45 | Run it
46 | Choose idp-auth0.ini in Identity Provider settings
47 | Choose sp-auth0.ini in Serivce Provider settings
48 | Click Open Browser and follow the instructions
49 |
50 | Demo
51 |
52 | Installation
53 | Download the zip files for your platform and extract all DLLs into the demos\bin folder.
54 | You can found the precompiled binaries of the DLL here:
55 |
56 | 32bit : https://www.zlatkovic.com/pub/libxml/
57 | 64bit : https://www.aleksey.com/xmlsec/download/win64/
58 |
59 | The required DLL are:
60 |
61 | libxmlsec.dll: main DLL
62 | libxml2.dll: to handle XML
63 | iconv.dll: to convert between charsets
64 |
65 |
66 | libxmlsec-mscrypto.dll: if you want to use cryptographics functions from msCrypto (install msCrypto from MS)
67 | libxmlsec-openssl.dll: or if you want to use cryptographics functions from OpenSSL
68 | libeay32.dll
69 | ssleay32.dll
70 |
71 |
72 |
73 |
74 | zlib1.dll: compression… but I'm not sure who need it
75 | libexslt.dll: xsl transformations (optional)
76 | libxslt.dll: xsl transformations (optional)
77 |
78 | If you want you can extract xmlsec.exe and openssl.exe. The first can be used to test XML signing and encryption, and the second to handle certificates and cryptography.
79 | TODO
80 |
81 | 📌 Better metadata support
82 | ✨ Identity provider implementation
83 | ✨ Basic key format conversion (PEM, DER, …)
84 |
85 | Documentation
86 | Delphi SAML consists of some modules:
87 |
88 | The cryptographic units: used to handle signing and encryption
89 | The SAML message units: to build request and parse response
90 | The metadata unit: to read and write metadata
91 | The demos: to see how Delphi SAML works
92 |
93 | If you need more help you can read the API documentation .
94 | License
95 | Delphi SAML is released under the term of the Apache License . Here follows the licenses of all dependencies:
96 |
97 |
98 | Library
99 | License
100 | Using with proprietary applications/libraries
101 |
102 |
103 | xmlsec-core
104 | MIT license
105 | Yes
106 |
107 |
108 | xmlsec-openssl
109 | OpenSSL License
110 | Yes
111 |
112 |
113 | xmlsec-mscrypto
114 | Microsoft licensing: The libraries are part of MS Windows, and are also distributed with Internet Explorer.
115 | Unknown
116 |
117 |
118 | libxml2
119 | MIT license
120 | Yes
121 |
122 |
123 | iconv
124 | LGPL
125 | Yes
126 |
127 |
128 | openssl
129 | Apache-2.0 license
130 | Yes
131 |
132 |
133 | zlib1
134 | Zlib license
135 | Yes
136 |
137 |
138 | libexslt
139 | MIT License
140 | Yes
141 |
142 |
143 | libxslt
144 | MIT License
145 | Yes
146 |
147 |
148 | Resources
149 | SAML documentation:
150 |
151 | http://docs.oasis-open.org/security/saml/v2.0/saml-2.0-os.zip
152 | https://developer.okta.com/docs/concepts/saml/
153 | https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/overview
154 | https://en.wikipedia.org/wiki/SAML_2.0
155 |
156 | XML-Sec API:
157 |
158 | https://www.aleksey.com/xmlsec/api/
159 |
160 | Resources:
161 |
162 | https://samltest.id/
163 | https://www.samltool.com/online_tools.php
164 | https://github.com/monmohan/samltools
165 |
166 | Generate the keys
167 | If you want to sign you request you need a private and a public key. You can generate both with this command:
168 | keygen.bat -h sp.samltools.com -e urn:msingh.samltools:sp -y 10
169 |
170 | See command line for further detail.
171 | Release Notes:
172 | ver.1.3.0 - 13 Mar 2023
173 |
174 | 64bit support
175 | support for xmlsec 1.3
176 | New SAML.inc file to use the right version of the DLLs bindings
177 | Better demo
178 | Support for encrypted private keys
179 |
180 | ver.1.2.0 - 11 Jul 2023
181 |
182 | Certificates and keys can be loaded from a buffer
183 | SP configuration improvement: NameIdFormat, Comparison, IssuerNameQualifier, IssuerFormat
184 | Support for signatures in nodes different from the root node
185 |
186 | ver.1.1.0 - 1 Apr 2023
187 |
188 | SPID support (Italy's public digital identity)
189 | Support for HTTP-POST binding
190 | New AuthnRequest attribute “AuthnContext”
191 |
192 | ver.1.0.0 - 24 Oct 2022
193 |
194 | First stable version
195 |
196 |
--------------------------------------------------------------------------------
/Samples/assertion-samltest.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 | https://samltest.id/saml/idp
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 |
22 |
23 | 0b0Z8FcQOeF0BQW9qzEnmFHCJYSTZ2LuwaNfQ5D698o=
24 |
25 |
26 | EcJzEv3FyNizpJRmIfU4LA1UmmsYFLhcrd0zvVUZTtWQX9nEIZUOQj/tQAQ8QLiCPdEWoNIpm4eApGZL0NU1CMcbUN1Z7Cb+GQLRwP8GlwxE9oimw5StQhDRWOjOQBjqbYI80/HTTlGPG7BszsCSh3hYghrX4GUc1hF+cP7fhrR5qotq2wOQ6idsks5poVcYqp26q95rf+DDy5Xy6NF+9AEIjLJvEu02JnHus3VzZB/Db6aQu6XR9CLlTOfjB1Roxmq5cbzjjklMSS9wQav6+vKZ0JWGyMwpYJOnZg0pNqsGV1BoWgcVjiDDFtneA2sXKritDX7gEMnfJNc5OjrH2Q==
27 |
28 |
29 | MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEBCwUAMBYxFDAS
30 | BgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4MDgyNDIxMTQwOVowFjEUMBIG
31 | A1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFK
32 | s71ufbQwoQoW7qkNAJRIANGA4iM0ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyj
33 | xj0uJ4lArgkr4AOEjj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVN
34 | c1klbN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF/cL5fOpd
35 | Va54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8nspXiH/MZW8o2cqWRkrw3
36 | MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0GA1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE
37 | 4k2ZNTA0BgNVHREELTArggtzYW1sdGVzdC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lk
38 | cDANBgkqhkiG9w0BAQsFAAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3
39 | YaMb2RSn7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHTTNiL
40 | ArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nblD1JJKSQ3AdhxK/we
41 | P3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcUZOpx4swtgGdeoSpeRyrtMvRwdcci
42 | NBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 | https://samltest.id/saml/idp
54 |
55 | AAdzZWNyZXQx2MBz+72EffcuUFEz3OMXkLO6V4xaSTgFBKUtpCxzHGUGoetH6geS08EXqTEm9QYebzZhI2OlKTk6DCQRpX9fTBFe54ANLYAVYOpMfCCVS/YkSHNARqW/Fxiq
59 |
60 |
64 |
65 |
66 |
68 |
69 | urn:test.lucaminuti:sp
70 |
71 |
72 |
74 |
75 |
76 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
77 |
78 |
79 |
80 |
83 | Ambassador
84 | None
85 |
86 |
88 | msmith@samltest.id
90 |
91 |
94 | morty
95 |
96 |
99 | +1-555-555-5505
100 |
101 |
104 | janitor@samltest.id
106 |
107 |
110 | msmith@samltest.id
111 |
112 |
115 | Smith
116 |
117 |
120 | Morty Smith
121 |
122 |
125 | Mortimer
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/Samples/idp-metadata-samltest.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
16 | samltest.id
17 |
19 |
20 | SAMLtest IdP
21 | A free and basic IdP for testing SAML deployments
22 | https://samltest.id/saml/logo.png
24 |
25 |
26 |
27 |
28 |
29 |
30 | MIIDETCCAfmgAwIBAgIUZRpDhkNKl5eWtJqk0Bu1BgTTargwDQYJKoZIhvcNAQEL
31 | BQAwFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwHhcNMTgwODI0MjExNDEwWhcNMzgw
32 | ODI0MjExNDEwWjAWMRQwEgYDVQQDDAtzYW1sdGVzdC5pZDCCASIwDQYJKoZIhvcN
33 | AQEBBQADggEPADCCAQoCggEBAJrh9/PcDsiv3UeL8Iv9rf4WfLPxuOm9W6aCntEA
34 | 8l6c1LQ1Zyrz+Xa/40ZgP29ENf3oKKbPCzDcc6zooHMji2fBmgXp6Li3fQUzu7yd
35 | +nIC2teejijVtrNLjn1WUTwmqjLtuzrKC/ePoZyIRjpoUxyEMJopAd4dJmAcCq/K
36 | k2eYX9GYRlqvIjLFoGNgy2R4dWwAKwljyh6pdnPUgyO/WjRDrqUBRFrLQJorR2kD
37 | c4seZUbmpZZfp4MjmWMDgyGM1ZnR0XvNLtYeWAyt0KkSvFoOMjZUeVK/4xR74F8e
38 | 8ToPqLmZEg9ZUx+4z2KjVK00LpdRkH9Uxhh03RQ0FabHW6UCAwEAAaNXMFUwHQYD
39 | VR0OBBYEFJDbe6uSmYQScxpVJhmt7PsCG4IeMDQGA1UdEQQtMCuCC3NhbWx0ZXN0
40 | LmlkhhxodHRwczovL3NhbWx0ZXN0LmlkL3NhbWwvaWRwMA0GCSqGSIb3DQEBCwUA
41 | A4IBAQBNcF3zkw/g51q26uxgyuy4gQwnSr01Mhvix3Dj/Gak4tc4XwvxUdLQq+jC
42 | cxr2Pie96klWhY/v/JiHDU2FJo9/VWxmc/YOk83whvNd7mWaNMUsX3xGv6AlZtCO
43 | L3JhCpHjiN+kBcMgS5jrtGgV1Lz3/1zpGxykdvS0B4sPnFOcaCwHe2B9SOCWbDAN
44 | JXpTjz1DmJO4ImyWPJpN1xsYKtm67Pefxmn0ax0uE2uuzq25h0xbTkqIQgJzyoE/
45 | DPkBFK1vDkMfAW11dQ0BXatEnW7Gtkc0lh2/PIbHWj4AzxYMyBf5Gy6HSVOftwjC
46 | voQR2qr2xJBixsg+MIORKtmKHLfU
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEB
56 | CwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4
57 | MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3
58 | DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFKs71ufbQwoQoW7qkNAJRIANGA4iM0
59 | ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyjxj0uJ4lArgkr4AOE
60 | jj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVNc1kl
61 | bN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF
62 | /cL5fOpdVa54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8n
63 | spXiH/MZW8o2cqWRkrw3MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0G
64 | A1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE4k2ZNTA0BgNVHREELTArggtzYW1sdGVz
65 | dC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsF
66 | AAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3YaMb2RSn
67 | 7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHT
68 | TNiLArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nbl
69 | D1JJKSQ3AdhxK/weP3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcU
70 | ZOpx4swtgGdeoSpeRyrtMvRwdcciNBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu
71 | 3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | MIIDEjCCAfqgAwIBAgIVAPVbodo8Su7/BaHXUHykx0Pi5CFaMA0GCSqGSIb3DQEB
81 | CwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4
82 | MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3
83 | DQEBAQUAA4IBDwAwggEKAoIBAQCQb+1a7uDdTTBBFfwOUun3IQ9nEuKM98SmJDWa
84 | MwM877elswKUTIBVh5gB2RIXAPZt7J/KGqypmgw9UNXFnoslpeZbA9fcAqqu28Z4
85 | sSb2YSajV1ZgEYPUKvXwQEmLWN6aDhkn8HnEZNrmeXihTFdyr7wjsLj0JpQ+VUlc
86 | 4/J+hNuU7rGYZ1rKY8AA34qDVd4DiJ+DXW2PESfOu8lJSOteEaNtbmnvH8KlwkDs
87 | 1NvPTsI0W/m4SK0UdXo6LLaV8saIpJfnkVC/FwpBolBrRC/Em64UlBsRZm2T89ca
88 | uzDee2yPUvbBd5kLErw+sC7i4xXa2rGmsQLYcBPhsRwnmBmlAgMBAAGjVzBVMB0G
89 | A1UdDgQWBBRZ3exEu6rCwRe5C7f5QrPcAKRPUjA0BgNVHREELTArggtzYW1sdGVz
90 | dC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsF
91 | AAOCAQEABZDFRNtcbvIRmblnZItoWCFhVUlq81ceSQddLYs8DqK340//hWNAbYdj
92 | WcP85HhIZnrw6NGCO4bUipxZXhiqTA/A9d1BUll0vYB8qckYDEdPDduYCOYemKkD
93 | dmnHMQWs9Y6zWiYuNKEJ9mf3+1N8knN/PK0TYVjVjXAf2CnOETDbLtlj6Nqb8La3
94 | sQkYmU+aUdopbjd5JFFwbZRaj6KiHXHtnIRgu8sUXNPrgipUgZUOVhP0C0N5OfE4
95 | JW8ZBrKgQC/6vJ2rSa9TlzI6JAa5Ww7gMXMP9M+cJUNQklcq+SBnTK8G+uBHgPKR
96 | zBDsMIEzRtQZm4GIoHJae4zmnCekkQ==
97 |
98 |
99 |
100 |
101 |
103 |
106 |
108 |
110 |
112 |
114 |
115 |
117 |
119 |
121 |
123 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/Demos/XmlSec/SAML.XML.MainForm.dfm:
--------------------------------------------------------------------------------
1 | object MainForm: TMainForm
2 | Left = 0
3 | Top = 0
4 | Caption = 'XmlSec DEMO'
5 | ClientHeight = 647
6 | ClientWidth = 953
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -13
11 | Font.Name = 'Segoe UI'
12 | Font.Style = []
13 | OnCreate = FormCreate
14 | TextHeight = 17
15 | object Label1: TLabel
16 | Left = 8
17 | Top = 79
18 | Width = 62
19 | Height = 17
20 | Caption = 'Input XML:'
21 | end
22 | object Label2: TLabel
23 | Left = 8
24 | Top = 456
25 | Width = 63
26 | Height = 17
27 | Caption = 'public Key:'
28 | end
29 | object Label3: TLabel
30 | Left = 488
31 | Top = 82
32 | Width = 73
33 | Height = 17
34 | Caption = 'Output XML:'
35 | end
36 | object Label4: TLabel
37 | Left = 8
38 | Top = 359
39 | Width = 67
40 | Height = 17
41 | Caption = 'Private Key:'
42 | end
43 | object Label5: TLabel
44 | Left = 8
45 | Top = 412
46 | Width = 44
47 | Height = 17
48 | Caption = 'Format:'
49 | end
50 | object Label6: TLabel
51 | Left = 8
52 | Top = 506
53 | Width = 44
54 | Height = 17
55 | Caption = 'Format:'
56 | end
57 | object Label7: TLabel
58 | Left = 8
59 | Top = 551
60 | Width = 147
61 | Height = 17
62 | Caption = 'Root node (ns:tagName):'
63 | end
64 | object memInput: TMemo
65 | Left = 8
66 | Top = 130
67 | Width = 450
68 | Height = 225
69 | Font.Charset = DEFAULT_CHARSET
70 | Font.Color = clWindowText
71 | Font.Height = -13
72 | Font.Name = 'Courier New'
73 | Font.Style = []
74 | Lines.Strings = (
75 | 'Memo1')
76 | ParentFont = False
77 | ReadOnly = True
78 | ScrollBars = ssBoth
79 | TabOrder = 0
80 | WordWrap = False
81 | end
82 | object edtInputXMLName: TComboBox
83 | Left = 8
84 | Top = 99
85 | Width = 361
86 | Height = 25
87 | TabOrder = 1
88 | OnChange = edtInputXMLNameChange
89 | end
90 | object edtPublicKeyName: TComboBox
91 | Left = 8
92 | Top = 477
93 | Width = 450
94 | Height = 25
95 | TabOrder = 2
96 | end
97 | object edtPrivateKeyName: TComboBox
98 | Left = 8
99 | Top = 381
100 | Width = 450
101 | Height = 25
102 | TabOrder = 3
103 | end
104 | object memOutput: TMemo
105 | Left = 488
106 | Top = 128
107 | Width = 450
108 | Height = 227
109 | Font.Charset = DEFAULT_CHARSET
110 | Font.Color = clWindowText
111 | Font.Height = -13
112 | Font.Name = 'Courier New'
113 | Font.Style = []
114 | Lines.Strings = (
115 | 'Memo1')
116 | ParentFont = False
117 | ReadOnly = True
118 | ScrollBars = ssBoth
119 | TabOrder = 4
120 | WordWrap = False
121 | end
122 | object edtPrivateKeyFormat: TComboBox
123 | Left = 8
124 | Top = 431
125 | Width = 450
126 | Height = 25
127 | Style = csDropDownList
128 | TabOrder = 6
129 | Items.Strings = (
130 | ' Unknown = 0'
131 | 'Binary = 1'
132 | 'Pem = 2'
133 | 'Der = 3'
134 | 'Pkcs8Pem = 4'
135 | 'Pkcs8Der = 5'
136 | 'Pkcs12 = 6'
137 | 'CertPem = 7'
138 | 'CertDer = 8')
139 | end
140 | object edtPublicKeyFormat: TComboBox
141 | Left = 8
142 | Top = 527
143 | Width = 450
144 | Height = 25
145 | Style = csDropDownList
146 | TabOrder = 5
147 | Items.Strings = (
148 | ' Unknown = 0'
149 | 'Binary = 1'
150 | 'Pem = 2'
151 | 'Der = 3'
152 | 'Pkcs8Pem = 4'
153 | 'Pkcs8Der = 5'
154 | 'Pkcs12 = 6'
155 | 'CertPem = 7'
156 | 'CertDer = 8')
157 | end
158 | object edtOutputXMLName: TComboBox
159 | Left = 488
160 | Top = 99
161 | Width = 360
162 | Height = 25
163 | TabOrder = 7
164 | end
165 | object btnInputXMLView: TButton
166 | Left = 382
167 | Top = 97
168 | Width = 75
169 | Height = 25
170 | Caption = 'View'
171 | TabOrder = 8
172 | OnClick = btnInputXMLViewClick
173 | end
174 | object btnOutputXMLView: TButton
175 | Left = 863
176 | Top = 97
177 | Width = 75
178 | Height = 25
179 | Caption = 'View'
180 | TabOrder = 9
181 | OnClick = btnOutputXMLViewClick
182 | end
183 | object boxFooter: TPanel
184 | Left = 0
185 | Top = 602
186 | Width = 953
187 | Height = 45
188 | Align = alBottom
189 | BevelOuter = bvNone
190 | Caption = 'boxFooter'
191 | ShowCaption = False
192 | TabOrder = 10
193 | object btnSign: TButton
194 | AlignWithMargins = True
195 | Left = 3
196 | Top = 3
197 | Width = 113
198 | Height = 39
199 | Align = alLeft
200 | Caption = 'Sign request'
201 | TabOrder = 0
202 | OnClick = btnSignClick
203 | end
204 | object btnVerify: TButton
205 | AlignWithMargins = True
206 | Left = 122
207 | Top = 3
208 | Width = 175
209 | Height = 39
210 | Align = alLeft
211 | Caption = 'Verify response with key'
212 | TabOrder = 1
213 | OnClick = btnVerifyClick
214 | end
215 | object btnEncrypt: TButton
216 | AlignWithMargins = True
217 | Left = 501
218 | Top = 3
219 | Width = 113
220 | Height = 39
221 | Margins.Left = 20
222 | Align = alLeft
223 | Caption = 'Encrypt'
224 | TabOrder = 2
225 | OnClick = btnEncryptClick
226 | end
227 | object btnDecrypt: TButton
228 | AlignWithMargins = True
229 | Left = 620
230 | Top = 3
231 | Width = 113
232 | Height = 39
233 | Align = alLeft
234 | Caption = 'Decrypt'
235 | TabOrder = 3
236 | OnClick = btnDecryptClick
237 | end
238 | object btnVerifyKeyEmb: TButton
239 | AlignWithMargins = True
240 | Left = 303
241 | Top = 3
242 | Width = 175
243 | Height = 39
244 | Align = alLeft
245 | Caption = 'Verify response without key'
246 | TabOrder = 4
247 | OnClick = btnVerifyKeyEmbClick
248 | end
249 | end
250 | object boxHeader: TPanel
251 | Left = 0
252 | Top = 0
253 | Width = 953
254 | Height = 66
255 | Align = alTop
256 | BevelOuter = bvNone
257 | Caption = 'boxHeader'
258 | Font.Charset = DEFAULT_CHARSET
259 | Font.Color = clWindowText
260 | Font.Height = -13
261 | Font.Name = 'Segoe UI'
262 | Font.Style = []
263 | ParentFont = False
264 | ShowCaption = False
265 | TabOrder = 11
266 | object Label10: TLabel
267 | Left = 15
268 | Top = 16
269 | Width = 33
270 | Height = 33
271 | Caption = #59607
272 | Font.Charset = DEFAULT_CHARSET
273 | Font.Color = clWindowText
274 | Font.Height = -33
275 | Font.Name = 'Segoe MDL2 Assets'
276 | Font.Style = []
277 | ParentFont = False
278 | end
279 | object Label11: TLabel
280 | Left = 77
281 | Top = 17
282 | Width = 200
283 | Height = 37
284 | Caption = 'XMLSEC - DEMO'
285 | Font.Charset = DEFAULT_CHARSET
286 | Font.Color = clWindowText
287 | Font.Height = -27
288 | Font.Name = 'Segoe UI'
289 | Font.Style = []
290 | ParentFont = False
291 | end
292 | end
293 | object cmbRoot: TComboBox
294 | Left = 8
295 | Top = 571
296 | Width = 450
297 | Height = 25
298 | TabOrder = 12
299 | Text = 'urn:oasis:names:tc:SAML:2.0:protocol:AuthnRequest'
300 | Items.Strings = (
301 | 'urn:oasis:names:tc:SAML:2.0:protocol:AuthnRequest'
302 | 'urn:oasis:names:tc:SAML:2.0:metadata:EntityDescriptor'
303 | 'urn:oasis:names:tc:SAML:2.0:protocol:Response'
304 | 'urn:oasis:names:tc:SAML:2.0:assertion:Assertion')
305 | end
306 | object memLog: TMemo
307 | Left = 495
308 | Top = 381
309 | Width = 450
310 | Height = 215
311 | Font.Charset = DEFAULT_CHARSET
312 | Font.Color = clWindowText
313 | Font.Height = -13
314 | Font.Name = 'Courier New'
315 | Font.Style = []
316 | ParentFont = False
317 | ReadOnly = True
318 | ScrollBars = ssBoth
319 | TabOrder = 13
320 | WordWrap = False
321 | end
322 | object chkAddSignatureTemplate: TCheckBox
323 | Left = 256
324 | Top = 360
325 | Width = 201
326 | Height = 17
327 | Caption = 'Add signature template'
328 | Checked = True
329 | State = cbChecked
330 | TabOrder = 14
331 | end
332 | end
333 |
--------------------------------------------------------------------------------
/Demos/Metadata/SAML.Forms.Main.dfm:
--------------------------------------------------------------------------------
1 | object MainForm: TMainForm
2 | Left = 0
3 | Top = 0
4 | Caption = 'Metadata - Demo'
5 | ClientHeight = 603
6 | ClientWidth = 801
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -12
11 | Font.Name = 'Segoe UI'
12 | Font.Style = []
13 | OnCreate = FormCreate
14 | OnDestroy = FormDestroy
15 | OnResize = FormResize
16 | TextHeight = 15
17 | object boxHeader: TPanel
18 | Left = 0
19 | Top = 0
20 | Width = 801
21 | Height = 66
22 | Align = alTop
23 | BevelOuter = bvNone
24 | Caption = 'boxHeader'
25 | Font.Charset = DEFAULT_CHARSET
26 | Font.Color = clWindowText
27 | Font.Height = -13
28 | Font.Name = 'Segoe UI'
29 | Font.Style = []
30 | ParentFont = False
31 | ShowCaption = False
32 | TabOrder = 0
33 | ExplicitWidth = 797
34 | object Label10: TLabel
35 | Left = 15
36 | Top = 16
37 | Width = 33
38 | Height = 33
39 | Caption = #59607
40 | Font.Charset = DEFAULT_CHARSET
41 | Font.Color = clWindowText
42 | Font.Height = -33
43 | Font.Name = 'Segoe MDL2 Assets'
44 | Font.Style = []
45 | ParentFont = False
46 | end
47 | object Label11: TLabel
48 | Left = 77
49 | Top = 17
50 | Width = 216
51 | Height = 37
52 | Caption = 'Metadata - DEMO'
53 | Font.Charset = DEFAULT_CHARSET
54 | Font.Color = clWindowText
55 | Font.Height = -27
56 | Font.Name = 'Segoe UI'
57 | Font.Style = []
58 | ParentFont = False
59 | end
60 | end
61 | object pgcMain: TPageControl
62 | Left = 0
63 | Top = 66
64 | Width = 801
65 | Height = 537
66 | ActivePage = tabWriter
67 | Align = alClient
68 | TabOrder = 1
69 | ExplicitWidth = 797
70 | ExplicitHeight = 536
71 | object tabReader: TTabSheet
72 | Caption = 'Reader'
73 | object Panel1: TPanel
74 | Left = 0
75 | Top = 0
76 | Width = 793
77 | Height = 63
78 | Align = alTop
79 | BevelOuter = bvNone
80 | Caption = 'Panel1'
81 | ShowCaption = False
82 | TabOrder = 0
83 | object Label12: TLabel
84 | Left = 16
85 | Top = 10
86 | Width = 72
87 | Height = 15
88 | Caption = 'Metadata file:'
89 | end
90 | object edtMetatadata: TComboBox
91 | Left = 16
92 | Top = 31
93 | Width = 296
94 | Height = 23
95 | Style = csDropDownList
96 | TabOrder = 0
97 | OnChange = edtMetatadataChange
98 | Items.Strings = (
99 | 'Unknown = 0'
100 | 'Binary = 1'
101 | 'Pem = 2'
102 | 'Der = 3'
103 | 'Pkcs8Pem = 4'
104 | 'Pkcs8Der = 5'
105 | 'Pkcs12 = 6'
106 | 'CertPem = 7'
107 | 'CertDer = 8')
108 | end
109 | object btnOpenFile: TButton
110 | Left = 318
111 | Top = 30
112 | Width = 91
113 | Height = 25
114 | Caption = 'Open file...'
115 | TabOrder = 1
116 | OnClick = btnOpenFileClick
117 | end
118 | end
119 | object grdValues: TStringGrid
120 | Left = 0
121 | Top = 63
122 | Width = 793
123 | Height = 371
124 | Align = alClient
125 | FixedCols = 0
126 | FixedRows = 0
127 | TabOrder = 1
128 | OnDrawCell = grdValuesDrawCell
129 | OnKeyPress = lstValuesKeyPress
130 | end
131 | object Panel2: TPanel
132 | Left = 0
133 | Top = 434
134 | Width = 793
135 | Height = 73
136 | Align = alBottom
137 | BevelOuter = bvNone
138 | Caption = 'Panel2'
139 | ShowCaption = False
140 | TabOrder = 2
141 | object Label1: TLabel
142 | Left = 16
143 | Top = 18
144 | Width = 27
145 | Height = 15
146 | Caption = 'Keys:'
147 | end
148 | object edtKeys: TComboBox
149 | Left = 16
150 | Top = 39
151 | Width = 425
152 | Height = 23
153 | Style = csDropDownList
154 | TabOrder = 0
155 | Items.Strings = (
156 | 'Unknown = 0'
157 | 'Binary = 1'
158 | 'Pem = 2'
159 | 'Der = 3'
160 | 'Pkcs8Pem = 4'
161 | 'Pkcs8Der = 5'
162 | 'Pkcs12 = 6'
163 | 'CertPem = 7'
164 | 'CertDer = 8')
165 | end
166 | object btnSave: TButton
167 | Left = 454
168 | Top = 39
169 | Width = 99
170 | Height = 25
171 | Caption = 'Save key to file...'
172 | TabOrder = 1
173 | OnClick = btnSaveClick
174 | end
175 | end
176 | end
177 | object tabWriter: TTabSheet
178 | Caption = 'Writer'
179 | ImageIndex = 1
180 | object Label9: TLabel
181 | Left = 24
182 | Top = 18
183 | Width = 72
184 | Height = 15
185 | Caption = 'Metadata file:'
186 | end
187 | object btnNew: TButton
188 | Left = 544
189 | Top = 91
190 | Width = 105
191 | Height = 25
192 | Caption = 'New'
193 | TabOrder = 0
194 | OnClick = btnNewClick
195 | end
196 | object btnWriterSave: TButton
197 | Left = 544
198 | Top = 122
199 | Width = 105
200 | Height = 37
201 | Caption = 'Save'
202 | TabOrder = 1
203 | OnClick = btnWriterSaveClick
204 | end
205 | object cmbIniFiles: TComboBox
206 | Left = 24
207 | Top = 39
208 | Width = 296
209 | Height = 23
210 | Style = csDropDownList
211 | TabOrder = 2
212 | OnChange = cmbIniFilesChange
213 | end
214 | object btnIniFile: TButton
215 | Left = 326
216 | Top = 38
217 | Width = 91
218 | Height = 25
219 | Caption = 'Open file...'
220 | TabOrder = 3
221 | end
222 | object GroupBox1: TGroupBox
223 | Left = 24
224 | Top = 82
225 | Width = 497
226 | Height = 319
227 | Caption = 'Metadata'
228 | TabOrder = 4
229 | object Label2: TLabel
230 | Left = 62
231 | Top = 32
232 | Width = 44
233 | Height = 15
234 | Alignment = taRightJustify
235 | Caption = 'EntityID:'
236 | end
237 | object Label3: TLabel
238 | Left = 57
239 | Top = 72
240 | Width = 49
241 | Height = 15
242 | Alignment = taRightJustify
243 | Caption = 'Location:'
244 | end
245 | object Label4: TLabel
246 | Left = 14
247 | Top = 115
248 | Width = 92
249 | Height = 15
250 | Alignment = taRightJustify
251 | Caption = 'Protocol binding:'
252 | end
253 | object Label5: TLabel
254 | Left = 23
255 | Top = 152
256 | Width = 84
257 | Height = 15
258 | Alignment = taRightJustify
259 | Caption = 'Cache duration:'
260 | end
261 | object Label6: TLabel
262 | Left = 17
263 | Top = 188
264 | Width = 90
265 | Height = 15
266 | Alignment = taRightJustify
267 | Caption = 'Valid unit (years):'
268 | end
269 | object Label7: TLabel
270 | Left = 50
271 | Top = 228
272 | Width = 57
273 | Height = 15
274 | Alignment = taRightJustify
275 | Caption = 'Certificate:'
276 | end
277 | object Label8: TLabel
278 | Left = 66
279 | Top = 267
280 | Width = 41
281 | Height = 15
282 | Alignment = taRightJustify
283 | Caption = 'Format:'
284 | end
285 | object edtEntityID: TEdit
286 | Left = 112
287 | Top = 29
288 | Width = 353
289 | Height = 23
290 | TabOrder = 0
291 | end
292 | object edtLocation: TEdit
293 | Left = 112
294 | Top = 69
295 | Width = 353
296 | Height = 23
297 | TabOrder = 1
298 | end
299 | object edtProtocolBinding: TComboBox
300 | Left = 112
301 | Top = 112
302 | Width = 353
303 | Height = 23
304 | TabOrder = 2
305 | Items.Strings = (
306 | 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
307 | 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect')
308 | end
309 | object edtCacheDuration: TEdit
310 | Left = 113
311 | Top = 149
312 | Width = 352
313 | Height = 23
314 | TabOrder = 3
315 | Text = 'PT604800S'
316 | end
317 | object edtValidUntil: TEdit
318 | Left = 113
319 | Top = 185
320 | Width = 352
321 | Height = 23
322 | TabOrder = 4
323 | Text = '10'
324 | end
325 | object edtCertificate: TEdit
326 | Left = 113
327 | Top = 225
328 | Width = 352
329 | Height = 23
330 | TabOrder = 5
331 | end
332 | object edtCerificateFormat: TComboBox
333 | Left = 113
334 | Top = 264
335 | Width = 353
336 | Height = 23
337 | Style = csDropDownList
338 | ItemIndex = 0
339 | TabOrder = 6
340 | Text = 'DER'
341 | Items.Strings = (
342 | 'DER'
343 | 'PEM')
344 | end
345 | end
346 | end
347 | end
348 | object SaveDialog1: TSaveDialog
349 | DefaultExt = 'der'
350 | Filter = 'DER file (*.der)|*.der'
351 | Left = 376
352 | Top = 152
353 | end
354 | object OpenDialog1: TOpenDialog
355 | Filter =
356 | 'XML Files (*.xml)|*.xml|SP ini files (*.ini)|*.ini|All files (*.' +
357 | '*)|*.*'
358 | Left = 316
359 | Top = 292
360 | end
361 | object dlgSaveMetadata: TSaveDialog
362 | DefaultExt = 'xml'
363 | Filter = 'XML File (*.xml)|*.xml'
364 | Title = 'Save Metadata'
365 | Left = 524
366 | Top = 236
367 | end
368 | end
369 |
--------------------------------------------------------------------------------
/Test/SAML.Test.Consts.pas:
--------------------------------------------------------------------------------
1 | unit SAML.Test.Consts;
2 |
3 | interface
4 |
5 | uses
6 | System.SysUtils;
7 |
8 | const
9 | XMLSignTemplate =
10 | ' ' + #13 +
11 | ' ' + #13 +
12 | ' Hello, World!' + #13 +
13 | ' ' + #13 +
14 | ' ' + #13 +
15 | ' ' + #13 +
16 | ' ' + #13 +
17 | ' ' + #13 +
18 | ' ' + #13 +
19 | ' ' + #13 +
20 | ' ' + #13 +
21 | ' ' + #13 +
22 | ' ' + #13 +
23 | ' ' + #13 +
24 | ' ' + #13 +
25 | ' ' + #13 +
26 | ' ' + #13 +
27 | ' ' + #13 +
28 | ' ' + #13 +
29 | ' ' + #13 +
30 | ' ' + #13 +
31 | ' ';
32 |
33 | XMLSigned =
34 | '' + #13#10 +
35 | '' + #13#10 +
36 | ' ' + #13#10 +
37 | ' Hello, World!' + #13#10 +
38 | ' ' + #13#10 +
39 | ' ' + #13#10 +
40 | ' ' + #13#10 +
41 | ' ' + #13#10 +
42 | ' ' + #13#10 +
43 | ' ' + #13#10 +
44 | ' ' + #13#10 +
45 | ' ' + #13#10 +
46 | ' ' + #13#10 +
47 | ' ' + #13#10 +
48 | ' 4WlH37+hQdyyonZrHkx329A8wWY= ' + #13#10 +
49 | ' ' + #13#10 +
50 | ' ' + #13#10 +
51 | ' vfY9SnfUw6JOIIsEsKzUYF0m7kKPfSp8yTMwfb0jYhHACpo1j+ZdHk0/dV8GRN/U' + #13#10 +
52 | '1x1yWCat0wyzLOkQnPUeUYUeLejgFrmqQLnLOZhEFy/OoWL0vZVw0YVUaBkPrwPe' + #13#10 +
53 | 'UzeA2uUa6dXObZTb25+rntRsgdo2VGk5YSU8yLRxuWhIibYR4qVl9mX0EVUAwp38' + #13#10 +
54 | 'zrj+khdORPFbICavOV5Lew3xbIOooZrYm8Af2lbEk/7pBEFm4NDHtVLNniN/HYSp' + #13#10 +
55 | 'YdShHaMSA2aC4TqFhmcQtN0AkDPUTzML9x5XIZl8bTFXYeKBYj2BwGafH1VoYLPz' + #13#10 +
56 | 'Z6IHl6Hg6OwTSN1puJA7UX55bKI/lUwBSxwklrplmzmnaGa9LEvTaHlZ/LOR2IEK' + #13#10 +
57 | '5Un+O4UHQfbDVvsIKhbU6dJHaiigyvZuBFjv8WiaOnncwAyGg91uBqq4tT8aDdQc' + #13#10 +
58 | 'XoruuXAlR0Zskw3/qvoJ1FbtC7pN1mSaSoYPDznaJN7IjK2/jIUrcYfMj01Qq3rj ' + #13#10 +
59 | ' ' + #13#10 +
60 | ' ' + #13#10 +
61 | ' ' + #13#10 +
62 | ' ' + #13#10 +
63 | ' ' + #13#10;
64 |
65 | XMLEncTemplate =
66 | '' + #13#10 +
67 | '' + #13#10 +
68 | ' ' + #13#10 +
69 | ' ' + #13#10 +
70 | ' ' + #13#10 +
71 | ' ' + #13#10 +
72 | ' ' + #13#10 +
73 | ' ' + #13#10 +
74 | ' ' + #13#10 +
75 | ' ' + #13#10;
76 |
77 | XMLEncrypted =
78 | '' + #13#10 +
79 | '' + #13#10 +
80 | ' ' + #13#10 +
81 | ' ' + #13#10 +
82 | ' ' + #13#10 +
83 | ' ' + #13#10 +
84 | ' ' + #13#10 +
85 | ' ' + #13#10 +
86 | ' ' + #13#10 +
87 | ' ' + #13#10 +
88 | ' dIz2g2EtXTkuCQIAyrHAS3vFRIn1w+v3gv7gIcT5Hi7dFRH2odD44tkmN8K+wFJq' + #13#10 +
89 | 'xSiOdCMNGqkFqC5JQHB+z6tjmuWoFIXfiJBDPTDzbxTZqKqOmJqU/ZfbEDkYCBk/' + #13#10 +
90 | 'G6+MtvbL7seV3CP9GsnUcIEuu9kuNdnFD9H3Mmr9QPQzGHqhgbjKoDZG4lW8vG4y' + #13#10 +
91 | 'x+5/DXBLkNiV3bFVSAnxUOxw3Kzqh/QTNla2PAFsUEP8he9jabxOPQCg69jX91oQ' + #13#10 +
92 | '3++k2I5lwYxC7cRm4SOLHeR7z1+XDPU12UdFvdaVUd6Yyb9vE0/KypOBUsRXVhUN' + #13#10 +
93 | 'BsxRLx4AupP5dbrT7LmXMbuD/nGaCmHEBk5a4KYkdmFsf26ZGQBVDuA828IR5Hhe' + #13#10 +
94 | '61kzil1+rpKmjWTavnBTIM8wPJloNEBZRwZdbFKM1YEtjkfPfjGyohYDHmZ0Bnv3' + #13#10 +
95 | '1SRaN+DxQ+ppamlR8i+v5Q4WcHhttSNJcLTuTNv2I6zMPSTCMZ1M3N1gvrx/c6Ze ' + #13#10 +
96 | ' ' + #13#10 +
97 | ' ' + #13#10 +
98 | ' ' + #13#10 +
99 | ' ' + #13#10 +
100 | ' sYyVnSCN/JPoh11zNcWJS/YdUUelNjqCedORuz3ewHUZfhNKP6VWe/4QRfTjZKKb' + #13#10 +
101 | 'VwAsq/qtP/qf73/9tgCcQ3ls92UI5IiK63UuMGAtaNXoXd+YeNTY2Q== ' + #13#10 +
102 | ' ' + #13#10 +
103 | ' ' + #13#10;
104 |
105 | PrivateKey =
106 | '-----BEGIN RSA PRIVATE KEY-----' + #13#10 +
107 | 'MIIG5AIBAAKCAYEAv3lOMK4NNihmzXuKWKDVpkRMDI1LaZrQDs4zH//C5S/WxIRO' + #13#10 +
108 | 'jp1lsafbcgjFlLHHZKTk9tm+DpxoN+D7FbXQLiZ59Bp1Jwur2g8YzuKAKd6fX35O' + #13#10 +
109 | 'V4CpYkk+7avujedgWmrsYa6Nxd+pcGzKBqr5q2fQIkfqLb6OZ5DEjZo/ipHCSq1/' + #13#10 +
110 | 'GZpPO/5+f6YYd7KsWSj/JU1Unlw4V/LE/ISKmoDrPvAKCYbkcCY0BCNeoFl1G6KX' + #13#10 +
111 | '75Ny00fgI4lwTUHgyUhwX6gvHmstmQOqZP59RacRpQHIRI2U1bQtnybiBXH509DU' + #13#10 +
112 | '5T2z+sJU+LSGbnASZO0/PD8nIHJ7RHamTni6UkyfZRiZs6/DpYVNeZc+NGwjA1qi' + #13#10 +
113 | 'xf6Rgjw0YaAaX/7K8k52o6PGvWAbmttJw/d0F1F0jtd+jLXMDY1pX69LoHGZsBzm' + #13#10 +
114 | 'HnRe1bnzrVHa2oJtQTwNCByVIqdauSErXijGB7sGBtyX94pD+r9vf+rmGQet85Wb' + #13#10 +
115 | 'DYhbCmGY+LCrQ6elAgMBAAECggGBAJtgluDN/Q6bzoCk5elx6q4X8halejLiXEAH' + #13#10 +
116 | 'eFlZNRDCt2eVbiIw+9skueFZ2OwHMCUt4lem7qHwrmnZ+ibt+VfaBVDfP35F7Fjx' + #13#10 +
117 | 's1H/X72aWH4ngu9jCxElGxnHUbh5sCjvZ48FFSsjit4eifrLN/uuLKoE7bXdUrYc' + #13#10 +
118 | 'NkQqjbGnAqGTFPbzz6SBqqlvYZ+QsGdR62qbzDUN5PMJoGzCKa+jOkNCiwKcIjgX' + #13#10 +
119 | '6FILWbiJn4yjbuQNJTrqsqpj12v6LkKf8AWtaOR2Rt11UsIKygvMTAaoXTtIQoES' + #13#10 +
120 | 'ZMK+Vde4JU3MGfi/epzH9Ds1U+UncPNOHIGjWkrM13Lb8KHJ8dWkzsrm9YNhvabS' + #13#10 +
121 | 'flkmVgJ3M+2wuG3K0uZ2INO+FTlVOyxUSjdKsfZLq62Vb68cyOhEPkPX51nQkzPb' + #13#10 +
122 | 'l/v23e3W1H0auB5StiGzdgcEBXEQWCFm7Zm8Q39keGt9u3yUJ7LkBpngS386b02f' + #13#10 +
123 | 'GFtNR7oOEdmyYeraQolJzGw9GOQrQQKBwQD+UPkJWkMcLwtf4waGp8b7aXQHUSl7' + #13#10 +
124 | '+1kurzeKJy/mBqgAGKj/eKWd+MNWzbp+IOYkByKbPXUET/7bM/vyX7HyARej9kC1' + #13#10 +
125 | 'LX4t2jbo5+nzvsfgvR8LuGjwMAwQvhPcwQ+kM54Azhsz2CaEJORNZBKt0gBoU15u' + #13#10 +
126 | 'vVDOQndn9oLflKteHCeX1+a2BMO9sI5aRyLb+GyPeY7dfQjzJH8txZgWXhgQH1uB' + #13#10 +
127 | 'dHnZu7OqezjudlJwynHYF7FBAlfl8eXCFqkCgcEAwL3TBRnHEb+eALrSED1By/Ax' + #13#10 +
128 | 'ktkB44e4lGfLzZGHDznjWB39uIib+CtoC+QMK3thiYDEFnNxXY52+5k8nBGLYvzT' + #13#10 +
129 | 'KqaYmagcgpg4/AuhWCcBQBJe0GRACSRfpQ9OxLvMh83QwNkmLMOWz96LuDF4eV4m' + #13#10 +
130 | 'd5svz5rIkl9nbE31wfdseh03SS9XZgwB+RMBP6IiLIGLf+9agsfBf6OzrXUm/xo+' + #13#10 +
131 | 'WjbGQmV46aLm+0EL35dbEbXC5K9vsBu/s36tUPKdAoHAEI3gyBUSDUGasfErOZSu' + #13#10 +
132 | 'RStGHDvSQXnJAlrxeJK4cXa5dNgmGAsYbMIGpR3bJ96oXGwCeqxzc4ZphodJvSsx' + #13#10 +
133 | 'gBlGGqwq5iBB+GYd8Oc3uWAPzrdA0Bh+7DOUdXqJ/HKsu/mILXE9IBDP4QYtvkPn' + #13#10 +
134 | 'W10yHZhfq0GzgtmcwC2xszAQP54BjcbGA88nlq9pdMLwp/TxzB0TiaNb88fKZ4ZX' + #13#10 +
135 | 'Mg2J73K7GCAm1l97gHto50zYbPMgmfpg1WR7qEIovIuRAoHAagxHvge340kWC3q/' + #13#10 +
136 | 'N9YsjKRE8nJaOrGjWmxd02ad9D+6mfIudskbYAmp/tjj5UzGltx1h5DPMFXBm59t' + #13#10 +
137 | 'nMV+duF64n21et3niedteyh/Bry3UGSLLIfsP9t2kKACi/Z0i8gvctxHx9t58DeX' + #13#10 +
138 | 'kqoNimHGMor9XHHip768bffbH3Ueh3XpxGe649f5gez2A+gWe3xvn923ZDu6eJs+' + #13#10 +
139 | 'slLCORxccFCw9zlTtOE/y8C3YrepkO38JM1uW2x5Jq6td9t1AoHBAIES+XoxMkzl' + #13#10 +
140 | 'MUVKr403PRzdy86bqNZi2e5EQa6uu0mw5Utdx2zT9Z+q5xv1XvwwGFJsKU6IUf4t' + #13#10 +
141 | '/tQLkmuiNZ4n0C5vFeSXkYjEZT5r45m6kn9YLPCgrtuvSs+0miyzzm/8rRRWpGoP' + #13#10 +
142 | 'NXPdtUjVs8nX3QXl3vpZO4YQtvo2wYcCZmvXGqByp8HwpebJDcCgssCynS4PzlR+' + #13#10 +
143 | 'wbJliOLtF7azoZJQ02HWqRukrzn/rcowrza+/XPo4HGnxfSKzitHOQ==' + #13#10 +
144 | '-----END RSA PRIVATE KEY-----' + #13#10;
145 |
146 | PublicKey =
147 | '-----BEGIN CERTIFICATE-----' + #13#10 +
148 | 'MIIEDzCCAnegAwIBAgIJAPg7PTQAntDoMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV' + #13#10 +
149 | 'BAMTEHNwLmx1Y2FtaW51dGkuaXQwHhcNMjIwOTIxMDkwMDU4WhcNMzIwOTE4MDkw' + #13#10 +
150 | 'MDU4WjAbMRkwFwYDVQQDExBzcC5sdWNhbWludXRpLml0MIIBojANBgkqhkiG9w0B' + #13#10 +
151 | 'AQEFAAOCAY8AMIIBigKCAYEAv3lOMK4NNihmzXuKWKDVpkRMDI1LaZrQDs4zH//C' + #13#10 +
152 | '5S/WxIROjp1lsafbcgjFlLHHZKTk9tm+DpxoN+D7FbXQLiZ59Bp1Jwur2g8YzuKA' + #13#10 +
153 | 'Kd6fX35OV4CpYkk+7avujedgWmrsYa6Nxd+pcGzKBqr5q2fQIkfqLb6OZ5DEjZo/' + #13#10 +
154 | 'ipHCSq1/GZpPO/5+f6YYd7KsWSj/JU1Unlw4V/LE/ISKmoDrPvAKCYbkcCY0BCNe' + #13#10 +
155 | 'oFl1G6KX75Ny00fgI4lwTUHgyUhwX6gvHmstmQOqZP59RacRpQHIRI2U1bQtnybi' + #13#10 +
156 | 'BXH509DU5T2z+sJU+LSGbnASZO0/PD8nIHJ7RHamTni6UkyfZRiZs6/DpYVNeZc+' + #13#10 +
157 | 'NGwjA1qixf6Rgjw0YaAaX/7K8k52o6PGvWAbmttJw/d0F1F0jtd+jLXMDY1pX69L' + #13#10 +
158 | 'oHGZsBzmHnRe1bnzrVHa2oJtQTwNCByVIqdauSErXijGB7sGBtyX94pD+r9vf+rm' + #13#10 +
159 | 'GQet85WbDYhbCmGY+LCrQ6elAgMBAAGjVjBUMDMGA1UdEQQsMCqCEHNwLmx1Y2Ft' + #13#10 +
160 | 'aW51dGkuaXSGFnVybjp0ZXN0Lmx1Y2FtaW51dGk6c3AwHQYDVR0OBBYEFNSSIqaE' + #13#10 +
161 | '6eQLZ62EpTadnAOftzj7MA0GCSqGSIb3DQEBCwUAA4IBgQCTa9PMwXIx3C0nl/Bl' + #13#10 +
162 | 's2NPHkHZ7DNp1dzM7fa/vbdDbgMp3emgTRRWHaKmNNQxyv4hosDbRjbMhXxcr3o4' + #13#10 +
163 | 'SWV2BkWC3Ddiyij2YC5g8YoCJq+F9oFXZctyLJPDix8fRQU8PH4R7Hs1bYfqOXi1' + #13#10 +
164 | '0h4VcjkxMo8Qob+8g3tcxJsQ02SY0BG+scVtGGAvPpbV8IzI3zU23im1nHXVn5p0' + #13#10 +
165 | 'hO08g8+58FUoZLXWORa3OHTldykkDdQPOh24pMMjTuIco2ez9S94EeZ+anDp3lIK' + #13#10 +
166 | '21g610BwAhErmZ53EyRoXZce0VSFHxvfm7VRsjDceVoH4qTJtH53ldWifAl7swkr' + #13#10 +
167 | 'wCBPm9jopHwr1DSavxG4poj/3x2gyIrWxPBCvJ+S0uFwEmf42heNgpG5kIGCh++C' + #13#10 +
168 | 'r5ftKw+uMR/dZfLWh8ywa6KzZT9g0o2sWESKxEpwz1pvvO/ZDELbjxwQaa0motfN' + #13#10 +
169 | 'S4XYwZtd+61Q3C6WqjSdo4dRwGKYA0I81pwaTRLlicEpMXI=' + #13#10 +
170 | '-----END CERTIFICATE-----' + #13#10;
171 |
172 | const
173 | SignatureValue =
174 | 'vfY9SnfUw6JOIIsEsKzUYF0m7kKPfSp8yTMwfb0jYhHACpo1j+ZdHk0/dV8GRN/U' +
175 | '1x1yWCat0wyzLOkQnPUeUYUeLejgFrmqQLnLOZhEFy/OoWL0vZVw0YVUaBkPrwPe' +
176 | 'UzeA2uUa6dXObZTb25+rntRsgdo2VGk5YSU8yLRxuWhIibYR4qVl9mX0EVUAwp38' +
177 | 'zrj+khdORPFbICavOV5Lew3xbIOooZrYm8Af2lbEk/7pBEFm4NDHtVLNniN/HYSp' +
178 | 'YdShHaMSA2aC4TqFhmcQtN0AkDPUTzML9x5XIZl8bTFXYeKBYj2BwGafH1VoYLPz' +
179 | 'Z6IHl6Hg6OwTSN1puJA7UX55bKI/lUwBSxwklrplmzmnaGa9LEvTaHlZ/LOR2IEK' +
180 | '5Un+O4UHQfbDVvsIKhbU6dJHaiigyvZuBFjv8WiaOnncwAyGg91uBqq4tT8aDdQc' +
181 | 'XoruuXAlR0Zskw3/qvoJ1FbtC7pN1mSaSoYPDznaJN7IjK2/jIUrcYfMj01Qq3rj';
182 |
183 | function TrimAll(const AText: string): string;
184 |
185 | implementation
186 |
187 | function TrimAll(const AText: string): string;
188 | begin
189 | Result := StringReplace(AText, ' ', '', [rfReplaceAll]);
190 | Result := StringReplace(Result, #13, '', [rfReplaceAll]);
191 | Result := StringReplace(Result, #10, '', [rfReplaceAll]);
192 | Result := StringReplace(Result, #9, '', [rfReplaceAll]);
193 | end;
194 |
195 | end.
196 |
--------------------------------------------------------------------------------
/Demos/SAML/SAML.Form.Main.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | unit SAML.Form.Main;
24 |
25 | interface
26 |
27 | uses
28 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
29 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent,
30 | IdCustomTCPServer, IdCustomHTTPServer, IdHTTPServer, Vcl.StdCtrls, Xml.xmldom,
31 | Xml.XMLIntf, Xml.XMLDoc, DateUtils, ZLib, NetEncoding, ShellApi, IdContext,
32 | Xml.omnixmldom, ActiveX, IOUtils, IdGlobalProtocols, Vcl.ExtCtrls,
33 | Vcl.ComCtrls,
34 |
35 | SAML.Config, SAML.http.Server;
36 |
37 | type
38 | TMainForm = class(TForm)
39 | OpenDialog1: TOpenDialog;
40 | pgcConfig: TPageControl;
41 | tabIdP: TTabSheet;
42 | tabServiceProvider: TTabSheet;
43 | grpIdPSettings: TGroupBox;
44 | Label1: TLabel;
45 | Label4: TLabel;
46 | Label5: TLabel;
47 | Label6: TLabel;
48 | edtSSOUrl: TEdit;
49 | edtSLOUrl: TEdit;
50 | edtIdPEntityID: TEdit;
51 | edtIdPSignPubKey: TEdit;
52 | GroupBox2: TGroupBox;
53 | Label2: TLabel;
54 | Label3: TLabel;
55 | Label7: TLabel;
56 | Label8: TLabel;
57 | edtSPEntityID: TEdit;
58 | edtSPHomePage: TEdit;
59 | edtSpSignPrivKey: TComboBox;
60 | edtSpSignPubKey: TComboBox;
61 | boxFooter: TPanel;
62 | btnStart: TButton;
63 | Button1: TButton;
64 | boxHeader: TPanel;
65 | Label10: TLabel;
66 | Label11: TLabel;
67 | grpIdPPresets: TGroupBox;
68 | btnIdPFromFile: TButton;
69 | edtIdPPresets: TComboBox;
70 | Label12: TLabel;
71 | edtIdPEncPubKey: TEdit;
72 | Label9: TLabel;
73 | grpSPPresets: TGroupBox;
74 | Label13: TLabel;
75 | btnSPFromFile: TButton;
76 | edtSPPresets: TComboBox;
77 | edtSPAssertionUrl: TEdit;
78 | Label14: TLabel;
79 | Label15: TLabel;
80 | Label16: TLabel;
81 | edtSpEncPrivKey: TComboBox;
82 | edtSpEncPubKey: TComboBox;
83 | Label17: TLabel;
84 | edtPort: TEdit;
85 | chkWantAuthnRequestsSigned: TCheckBox;
86 | Label18: TLabel;
87 | cmbAuthContext: TComboBox;
88 | TabLog: TTabSheet;
89 | MemoLog: TMemo;
90 | procedure btnStartClick(Sender: TObject);
91 | procedure Button1Click(Sender: TObject);
92 | procedure FormCreate(Sender: TObject);
93 | procedure edtIdPPresetsChange(Sender: TObject);
94 | procedure btnIdPFromFileClick(Sender: TObject);
95 | procedure btnSPFromFileClick(Sender: TObject);
96 | procedure edtSPPresetsChange(Sender: TObject);
97 | procedure edtSPEntityIDChange(Sender: TObject);
98 | procedure edtSPHomePageChange(Sender: TObject);
99 | procedure edtSPAssertionUrlChange(Sender: TObject);
100 | procedure edtSpSignPrivKeyChange(Sender: TObject);
101 | procedure edtSpSignPubKeyChange(Sender: TObject);
102 | procedure edtSpEncPrivKeyChange(Sender: TObject);
103 | procedure edtSpEncPubKeyChange(Sender: TObject);
104 | procedure cmbAuthContextChange(Sender: TObject);
105 | private
106 | FHttpServer: TmodHttpServer;
107 | procedure LoadIdPPresets;
108 | procedure LoadSPPresets;
109 | procedure LoadIdPSetting(const AFileName: string);
110 | procedure LoadSPSetting(const AFileName: string);
111 | procedure LoadCerts;
112 | procedure AppendFileToCombo(AComboBox: TComboBox;
113 | const ASearchPattern: string);
114 | public
115 | procedure Log(const AMessage: string);
116 | constructor Create(AOwner: TComponent); override;
117 | destructor Destroy; override;
118 | end;
119 |
120 | var
121 | MainForm: TMainForm;
122 |
123 | implementation
124 |
125 | uses
126 | System.Types,
127 | SAML.Core, SAML.XML.Utils;
128 |
129 | {$R *.dfm}
130 |
131 | procedure TMainForm.btnIdPFromFileClick(Sender: TObject);
132 | begin
133 | if OpenDialog1.Execute(Handle) then
134 | begin
135 | LoadIdPSetting(OpenDialog1.FileName);
136 | end;
137 | end;
138 |
139 | procedure TMainForm.btnSPFromFileClick(Sender: TObject);
140 | begin
141 | if OpenDialog1.Execute(Handle) then
142 | begin
143 | LoadSPSetting(OpenDialog1.FileName);
144 | end;
145 | end;
146 |
147 | procedure TMainForm.btnStartClick(Sender: TObject);
148 | begin
149 | if edtSSOUrl.Text = '' then
150 | raise Exception.Create('Choose a IDP');
151 | FHttpServer.Port := StrToInt(edtPort.Text);
152 | FHttpServer.Start;
153 | ShellExecute(Handle, 'open', PChar(FHttpServer.SPConfig.HomeUrl), '', '', SW_NORMAL);
154 | end;
155 |
156 | procedure TMainForm.Button1Click(Sender: TObject);
157 | begin
158 | FHttpServer.Port := StrToInt(edtPort.Text);
159 | FHttpServer.Start;
160 | end;
161 |
162 | procedure TMainForm.cmbAuthContextChange(Sender: TObject);
163 | begin
164 | FHttpServer.SPConfig.AuthnContextClassRef := cmbAuthContext.Text;
165 | end;
166 |
167 | constructor TMainForm.Create(AOwner: TComponent);
168 | begin
169 | inherited;
170 | FHttpServer := TmodHttpServer.Create(nil);
171 |
172 | TXMLSec.RegisterErrorCallback(
173 | procedure (const ASecError: TXMLSecError)
174 | begin
175 | MainForm.Log(ASecError.ErrorMessage);
176 | end
177 | );
178 | end;
179 |
180 | destructor TMainForm.Destroy;
181 | begin
182 | FHttpServer.Free;
183 | inherited;
184 | end;
185 |
186 | procedure TMainForm.edtIdPPresetsChange(Sender: TObject);
187 | begin
188 | LoadIdPSetting(TPath.Combine(ExtractFilePath(Application.ExeName), edtIdPPresets.Text));
189 | end;
190 |
191 | procedure TMainForm.edtSPAssertionUrlChange(Sender: TObject);
192 | begin
193 | FHttpServer.SPConfig.AssertionUrl := edtSPAssertionUrl.Text;
194 | end;
195 |
196 | procedure TMainForm.edtSpEncPrivKeyChange(Sender: TObject);
197 | begin
198 | FHttpServer.SPConfig.EncPrivKeyFile := edtSpEncPrivKey.Text;
199 | end;
200 |
201 | procedure TMainForm.edtSpEncPubKeyChange(Sender: TObject);
202 | begin
203 | FHttpServer.SPConfig.EncPubKeyFile := edtSpEncPubKey.Text;
204 | end;
205 |
206 | procedure TMainForm.edtSPEntityIDChange(Sender: TObject);
207 | begin
208 | FHttpServer.SPConfig.EntityId := edtSPEntityID.Text;
209 | end;
210 |
211 | procedure TMainForm.edtSPHomePageChange(Sender: TObject);
212 | begin
213 | FHttpServer.SPConfig.HomeUrl := edtSPHomePage.Text;
214 | end;
215 |
216 | procedure TMainForm.edtSPPresetsChange(Sender: TObject);
217 | begin
218 | LoadSPSetting(TPath.Combine(ExtractFilePath(Application.ExeName), edtSPPresets.Text));
219 | end;
220 |
221 | procedure TMainForm.edtSpSignPrivKeyChange(Sender: TObject);
222 | begin
223 | FHttpServer.SPConfig.SignPrivKeyFile := edtSpSignPrivKey.Text;
224 | end;
225 |
226 | procedure TMainForm.edtSpSignPubKeyChange(Sender: TObject);
227 | begin
228 | FHttpServer.SPConfig.SignPubKeyFile := edtSpSignPubKey.Text;
229 | end;
230 |
231 | procedure TMainForm.FormCreate(Sender: TObject);
232 | begin
233 | pgcConfig.ActivePageIndex := 0;
234 | LoadIdPPresets;
235 | LoadSPPresets;
236 | LoadCerts;
237 | end;
238 |
239 | procedure TMainForm.LoadCerts;
240 | begin
241 | AppendFileToCombo(edtSpSignPrivKey, '*.pem');
242 | AppendFileToCombo(edtSpSignPrivKey, '*.der');
243 | AppendFileToCombo(edtSpSignPrivKey, '*.key');
244 |
245 | AppendFileToCombo(edtSpEncPrivKey, '*.pem');
246 | AppendFileToCombo(edtSpEncPrivKey, '*.der');
247 | AppendFileToCombo(edtSpEncPrivKey, '*.key');
248 |
249 | AppendFileToCombo(edtSpSignPubKey, '*.pem');
250 | AppendFileToCombo(edtSpSignPubKey, '*.der');
251 | AppendFileToCombo(edtSpSignPubKey, '*.crt');
252 |
253 | AppendFileToCombo(edtSpEncPubKey, '*.pem');
254 | AppendFileToCombo(edtSpEncPubKey, '*.der');
255 | AppendFileToCombo(edtSpEncPubKey, '*.crt');
256 | end;
257 |
258 | procedure TMainForm.AppendFileToCombo(AComboBox: TComboBox; const ASearchPattern: string);
259 | var
260 | LFiles: TStringDynArray;
261 | LFileName: string;
262 | begin
263 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), ASearchPattern);
264 | for LFileName in LFiles do
265 | AComboBox.Items.Add(ExtractFileName(LFileName));
266 | end;
267 |
268 |
269 | procedure TMainForm.LoadIdPPresets;
270 | begin
271 | AppendFileToCombo(edtIdPPresets, 'idp-*.ini');
272 | AppendFileToCombo(edtIdPPresets, 'idp-*.xml');
273 | end;
274 |
275 | procedure TMainForm.LoadIdPSetting(const AFileName: string);
276 | begin
277 | FHttpServer.IdPConfig.LoadFromFile(AFileName);
278 | edtIdPEntityID.Text := FHttpServer.IdPConfig.EntityId;
279 | edtSSOUrl.Text := FHttpServer.IdPConfig.SSOUrl;
280 | edtSLOUrl.Text := FHttpServer.IdPConfig.SLOUrl;
281 | edtIdPSignPubKey.Text := FHttpServer.IdPConfig.SignPubKeyFile;
282 | edtIdPEncPubKey.Text := FHttpServer.IdPConfig.EncPubKeyFile;
283 | chkWantAuthnRequestsSigned.Checked := FHttpServer.IdPConfig.WantAuthnRequestsSigned;
284 |
285 | if not FHttpServer.IdPConfig.SigningCertificate.IsEmpty then
286 | edtIdpSignPubKey.Text := '';
287 | if not FHttpServer.IdPConfig.EncryptionCertificate.IsEmpty then
288 | edtIdpEncPubKey.Text := '';
289 | end;
290 |
291 | procedure TMainForm.LoadSPPresets;
292 | begin
293 | AppendFileToCombo(edtSPPresets, 'sp-*.ini');
294 | AppendFileToCombo(edtSPPresets, 'sp-*.xml');
295 | end;
296 |
297 | procedure TMainForm.LoadSPSetting(const AFileName: string);
298 | begin
299 | FHttpServer.SPConfig.LoadFromFile(AFileName);
300 | edtSPEntityID.Text := FHttpServer.SPConfig.EntityId;
301 | edtSPHomePage.Text := FHttpServer.SPConfig.HomeUrl;
302 | edtSPAssertionUrl.Text := FHttpServer.SPConfig.AssertionUrl;
303 | edtSpSignPrivKey.Text := FHttpServer.SPConfig.SignPrivKeyFile;
304 | edtSpSignPubKey.Text := FHttpServer.SPConfig.SignPubKeyFile;
305 | edtSpEncPrivKey.Text := FHttpServer.SPConfig.EncPrivKeyFile;
306 | edtSpEncPubKey.Text := FHttpServer.SPConfig.EncPubKeyFile;
307 | cmbAuthContext.Text := FHttpServer.SPConfig.AuthnContextClassRef;
308 |
309 | if not FHttpServer.SPConfig.SigningCertificate.IsEmpty then
310 | edtSpSignPubKey.Text := '';
311 | if not FHttpServer.SPConfig.EncryptionCertificate.IsEmpty then
312 | edtSpEncPubKey.Text := '';
313 | end;
314 |
315 | procedure TMainForm.Log(const AMessage: string);
316 | begin
317 | TThread.Queue(nil,
318 | procedure
319 | begin
320 | MemoLog.Lines.Add(AMessage);
321 | end);
322 | end;
323 |
324 | initialization
325 |
326 | Randomize;
327 |
328 | end.
329 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Demos/XmlSec/XmlSecDemo.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {9C14EE12-BB73-45D5-B197-A6854C40A272}
4 | 20.3
5 | VCL
6 | True
7 | Debug
8 | Win64
9 | 3
10 | Application
11 | XmlSecDemo.dpr
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | true
50 | Cfg_2
51 | true
52 | true
53 |
54 |
55 | true
56 | Cfg_2
57 | true
58 | true
59 |
60 |
61 | false
62 | false
63 | false
64 | false
65 | false
66 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
67 | $(BDS)\bin\delphi_PROJECTICON.ico
68 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
69 | 1040
70 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
71 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
72 | XmlSecDemo
73 | ..\bin
74 | "Sapphire Kamri|VCLSTYLE|$(BDSCOMMONDIR)\Styles\SapphireKamri.vsf"
75 | .\$(Platform)\$(Config)
76 |
77 |
78 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;SynEdit_R11;appanalytics;IndyProtocols;vclx;FrameViewer11;ChromeTabs_R;IndyIPClient;dbxcds;vcledge;IOCore;ISVcl8;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;IOXML;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;VirtualTreesR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;IOFireDAC;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;ISFLib8;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;ISRtl8;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)
79 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
80 | Debug
81 | true
82 | 1033
83 | none
84 | $(BDS)\bin\default_app.manifest
85 |
86 |
87 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;VirtualTreesR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)
88 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
89 | Debug
90 | true
91 | 1033
92 | $(BDS)\bin\default_app.manifest
93 | ..\bin64
94 | none
95 |
96 |
97 | DEBUG;$(DCC_Define)
98 | true
99 | false
100 | true
101 | true
102 | true
103 | true
104 | true
105 |
106 |
107 | false
108 | PerMonitorV2
109 | true
110 | 1033
111 |
112 |
113 | PerMonitorV2
114 | true
115 | 1033
116 |
117 |
118 | false
119 | RELEASE;$(DCC_Define)
120 | 0
121 | 0
122 |
123 |
124 | PerMonitorV2
125 |
126 |
127 | PerMonitorV2
128 |
129 |
130 |
131 | MainSource
132 |
133 |
134 |
135 | dfm
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | Base
144 |
145 |
146 | Cfg_1
147 | Base
148 |
149 |
150 | Cfg_2
151 | Base
152 |
153 |
154 |
155 | Delphi.Personality.12
156 | Application
157 |
158 |
159 |
160 | XmlSecDemo.dpr
161 |
162 |
163 |
164 |
165 |
166 | True
167 | True
168 |
169 |
170 | 12
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/Demos/Metadata/MetadataDemo.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {0E6E5F85-EB90-4662-9AFE-EB886A02088B}
4 | 20.3
5 | VCL
6 | True
7 | Debug
8 | Win64
9 | 3
10 | Application
11 | MetadataDemo.dpr
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | true
50 | Cfg_2
51 | true
52 | true
53 |
54 |
55 | true
56 | Cfg_2
57 | true
58 | true
59 |
60 |
61 | .\$(Platform)\$(Config)
62 | ..\bin
63 | false
64 | false
65 | false
66 | false
67 | false
68 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
69 | $(BDS)\bin\delphi_PROJECTICON.ico
70 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
71 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
72 | MetadataDemo
73 | 1040
74 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
75 |
76 |
77 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;SynEdit_R11;appanalytics;IndyProtocols;vclx;FrameViewer11;ChromeTabs_R;IndyIPClient;dbxcds;vcledge;IOCore;ISVcl8;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;IOXML;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;VirtualTreesR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;IOFireDAC;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;ISFLib8;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;ISRtl8;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)
78 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
79 | Debug
80 | true
81 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
82 | 1033
83 | $(BDS)\bin\default_app.manifest
84 |
85 |
86 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;VirtualTreesR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)
87 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
88 | Debug
89 | true
90 | 1033
91 | $(BDS)\bin\default_app.manifest
92 |
93 |
94 | DEBUG;$(DCC_Define)
95 | true
96 | false
97 | true
98 | true
99 | true
100 | true
101 | true
102 |
103 |
104 | false
105 | PerMonitorV2
106 | true
107 | 1033
108 |
109 |
110 | true
111 | PerMonitorV2
112 |
113 |
114 | false
115 | RELEASE;$(DCC_Define)
116 | 0
117 | 0
118 |
119 |
120 | PerMonitorV2
121 |
122 |
123 | true
124 | PerMonitorV2
125 |
126 |
127 |
128 | MainSource
129 |
130 |
131 |
132 | dfm
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | Cfg_2
144 | Base
145 |
146 |
147 | Base
148 |
149 |
150 | Cfg_1
151 | Base
152 |
153 |
154 |
155 | Delphi.Personality.12
156 | Application
157 |
158 |
159 |
160 | MetadataDemo.dpr
161 |
162 |
163 |
164 |
165 | True
166 | True
167 |
168 |
169 | 12
170 |
171 |
172 |
173 |
174 |
--------------------------------------------------------------------------------
/Demos/SAML/SAML.Form.Main.dfm:
--------------------------------------------------------------------------------
1 | object MainForm: TMainForm
2 | Left = 0
3 | Top = 0
4 | Caption = 'SAML - ServiceProvider'
5 | ClientHeight = 736
6 | ClientWidth = 455
7 | Color = clBtnFace
8 | Font.Charset = DEFAULT_CHARSET
9 | Font.Color = clWindowText
10 | Font.Height = -13
11 | Font.Name = 'Segoe UI'
12 | Font.Style = []
13 | Position = poScreenCenter
14 | StyleElements = [seClient, seBorder]
15 | OnCreate = FormCreate
16 | TextHeight = 17
17 | object pgcConfig: TPageControl
18 | AlignWithMargins = True
19 | Left = 3
20 | Top = 69
21 | Width = 449
22 | Height = 604
23 | ActivePage = tabIdP
24 | Align = alClient
25 | TabOrder = 0
26 | object tabIdP: TTabSheet
27 | Caption = 'Identity Provider'
28 | object grpIdPSettings: TGroupBox
29 | AlignWithMargins = True
30 | Left = 3
31 | Top = 93
32 | Width = 435
33 | Height = 364
34 | Align = alTop
35 | Caption = 'IdP settings'
36 | TabOrder = 1
37 | object Label1: TLabel
38 | Left = 24
39 | Top = 71
40 | Width = 48
41 | Height = 17
42 | Caption = 'SSO Url:'
43 | end
44 | object Label4: TLabel
45 | Left = 24
46 | Top = 119
47 | Width = 47
48 | Height = 17
49 | Caption = 'SLO Url:'
50 | end
51 | object Label5: TLabel
52 | Left = 24
53 | Top = 21
54 | Width = 47
55 | Height = 17
56 | Caption = 'Entity ID'
57 | end
58 | object Label6: TLabel
59 | Left = 24
60 | Top = 167
61 | Width = 75
62 | Height = 17
63 | Caption = 'Sign PubKey:'
64 | end
65 | object Label9: TLabel
66 | Left = 24
67 | Top = 225
68 | Width = 70
69 | Height = 17
70 | Caption = 'Enc PubKey:'
71 | end
72 | object edtSSOUrl: TEdit
73 | Left = 24
74 | Top = 92
75 | Width = 321
76 | Height = 25
77 | TabOrder = 1
78 | end
79 | object edtSLOUrl: TEdit
80 | Left = 24
81 | Top = 140
82 | Width = 321
83 | Height = 25
84 | TabOrder = 2
85 | end
86 | object edtIdPEntityID: TEdit
87 | Left = 24
88 | Top = 42
89 | Width = 321
90 | Height = 25
91 | TabOrder = 0
92 | end
93 | object edtIdPSignPubKey: TEdit
94 | Left = 24
95 | Top = 190
96 | Width = 321
97 | Height = 25
98 | TabOrder = 3
99 | end
100 | object edtIdPEncPubKey: TEdit
101 | Left = 24
102 | Top = 248
103 | Width = 321
104 | Height = 25
105 | TabOrder = 4
106 | end
107 | object chkWantAuthnRequestsSigned: TCheckBox
108 | Left = 24
109 | Top = 279
110 | Width = 296
111 | Height = 17
112 | Caption = 'WantAuthnRequestsSigned'
113 | TabOrder = 5
114 | end
115 | end
116 | object grpIdPPresets: TGroupBox
117 | AlignWithMargins = True
118 | Left = 3
119 | Top = 3
120 | Width = 435
121 | Height = 84
122 | Align = alTop
123 | Caption = 'Presets'
124 | TabOrder = 0
125 | object Label12: TLabel
126 | Left = 24
127 | Top = 26
128 | Width = 60
129 | Height = 17
130 | Caption = 'Preset file:'
131 | end
132 | object btnIdPFromFile: TButton
133 | Left = 326
134 | Top = 48
135 | Width = 19
136 | Height = 27
137 | Caption = '...'
138 | TabOrder = 1
139 | OnClick = btnIdPFromFileClick
140 | end
141 | object edtIdPPresets: TComboBox
142 | Left = 24
143 | Top = 49
144 | Width = 296
145 | Height = 25
146 | Style = csDropDownList
147 | TabOrder = 0
148 | OnChange = edtIdPPresetsChange
149 | end
150 | end
151 | end
152 | object tabServiceProvider: TTabSheet
153 | Caption = 'Service Provider'
154 | ImageIndex = 1
155 | object GroupBox2: TGroupBox
156 | AlignWithMargins = True
157 | Left = 3
158 | Top = 93
159 | Width = 435
160 | Height = 460
161 | Align = alTop
162 | Caption = 'Service provider'
163 | TabOrder = 0
164 | object Label2: TLabel
165 | Left = 16
166 | Top = 25
167 | Width = 47
168 | Height = 17
169 | Caption = 'Entity ID'
170 | end
171 | object Label3: TLabel
172 | Left = 16
173 | Top = 77
174 | Width = 72
175 | Height = 17
176 | Caption = 'Home page:'
177 | end
178 | object Label7: TLabel
179 | Left = 16
180 | Top = 184
181 | Width = 74
182 | Height = 17
183 | Caption = 'Sign PrivKey:'
184 | end
185 | object Label8: TLabel
186 | Left = 16
187 | Top = 232
188 | Width = 75
189 | Height = 17
190 | Caption = 'Sign PubKey:'
191 | end
192 | object Label14: TLabel
193 | Left = 16
194 | Top = 132
195 | Width = 91
196 | Height = 17
197 | Caption = 'Assertion page:'
198 | end
199 | object Label15: TLabel
200 | Left = 16
201 | Top = 286
202 | Width = 69
203 | Height = 17
204 | Caption = 'Enc PrivKey:'
205 | end
206 | object Label16: TLabel
207 | Left = 16
208 | Top = 334
209 | Width = 66
210 | Height = 17
211 | Caption = 'Enc PutKey:'
212 | end
213 | object Label18: TLabel
214 | Left = 16
215 | Top = 387
216 | Width = 80
217 | Height = 17
218 | Caption = 'AuthnContext:'
219 | end
220 | object edtSPEntityID: TEdit
221 | Left = 16
222 | Top = 46
223 | Width = 321
224 | Height = 25
225 | TabOrder = 0
226 | OnChange = edtSPEntityIDChange
227 | end
228 | object edtSPHomePage: TEdit
229 | Left = 16
230 | Top = 99
231 | Width = 321
232 | Height = 25
233 | TabOrder = 1
234 | OnChange = edtSPHomePageChange
235 | end
236 | object edtSpSignPrivKey: TComboBox
237 | Left = 16
238 | Top = 205
239 | Width = 321
240 | Height = 25
241 | TabOrder = 2
242 | OnChange = edtSpSignPrivKeyChange
243 | end
244 | object edtSpSignPubKey: TComboBox
245 | Left = 16
246 | Top = 255
247 | Width = 321
248 | Height = 25
249 | TabOrder = 3
250 | OnChange = edtSpSignPubKeyChange
251 | end
252 | object edtSPAssertionUrl: TEdit
253 | Left = 16
254 | Top = 155
255 | Width = 321
256 | Height = 25
257 | TabOrder = 4
258 | OnChange = edtSPAssertionUrlChange
259 | end
260 | object edtSpEncPrivKey: TComboBox
261 | Left = 16
262 | Top = 303
263 | Width = 321
264 | Height = 25
265 | TabOrder = 5
266 | OnChange = edtSpEncPrivKeyChange
267 | end
268 | object edtSpEncPubKey: TComboBox
269 | Left = 16
270 | Top = 355
271 | Width = 321
272 | Height = 25
273 | TabOrder = 6
274 | OnChange = edtSpEncPubKeyChange
275 | end
276 | object cmbAuthContext: TComboBox
277 | Left = 16
278 | Top = 410
279 | Width = 321
280 | Height = 25
281 | TabOrder = 7
282 | OnChange = cmbAuthContextChange
283 | Items.Strings = (
284 |
285 | 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTranspor' +
286 | 't'
287 | 'https://www.spid.gov.it/SpidL1'
288 | 'https://www.spid.gov.it/SpidL2'
289 | 'https://www.spid.gov.it/SpidL3')
290 | end
291 | end
292 | object grpSPPresets: TGroupBox
293 | AlignWithMargins = True
294 | Left = 3
295 | Top = 3
296 | Width = 435
297 | Height = 84
298 | Align = alTop
299 | Caption = 'Presets'
300 | TabOrder = 1
301 | object Label13: TLabel
302 | Left = 24
303 | Top = 26
304 | Width = 60
305 | Height = 17
306 | Caption = 'Preset file:'
307 | end
308 | object btnSPFromFile: TButton
309 | Left = 326
310 | Top = 48
311 | Width = 19
312 | Height = 27
313 | Caption = '...'
314 | TabOrder = 1
315 | OnClick = btnSPFromFileClick
316 | end
317 | object edtSPPresets: TComboBox
318 | Left = 24
319 | Top = 49
320 | Width = 296
321 | Height = 25
322 | Style = csDropDownList
323 | TabOrder = 0
324 | OnChange = edtSPPresetsChange
325 | end
326 | end
327 | end
328 | object TabLog: TTabSheet
329 | Caption = 'TabLog'
330 | ImageIndex = 2
331 | object MemoLog: TMemo
332 | Left = 0
333 | Top = 0
334 | Width = 441
335 | Height = 572
336 | Align = alClient
337 | Font.Charset = DEFAULT_CHARSET
338 | Font.Color = clWindowText
339 | Font.Height = -13
340 | Font.Name = 'Consolas'
341 | Font.Style = []
342 | ParentFont = False
343 | ReadOnly = True
344 | ScrollBars = ssBoth
345 | TabOrder = 0
346 | WordWrap = False
347 | end
348 | end
349 | end
350 | object boxFooter: TPanel
351 | Left = 0
352 | Top = 676
353 | Width = 455
354 | Height = 60
355 | Align = alBottom
356 | BevelOuter = bvNone
357 | Caption = 'boxFooter'
358 | ShowCaption = False
359 | TabOrder = 1
360 | object Label17: TLabel
361 | Left = 15
362 | Top = 3
363 | Width = 27
364 | Height = 17
365 | Caption = 'Port:'
366 | end
367 | object btnStart: TButton
368 | Left = 92
369 | Top = 3
370 | Width = 258
371 | Height = 46
372 | Caption = 'Open browser'
373 | TabOrder = 0
374 | OnClick = btnStartClick
375 | end
376 | object Button1: TButton
377 | Left = 356
378 | Top = 3
379 | Width = 89
380 | Height = 46
381 | Caption = 'Start server'
382 | TabOrder = 1
383 | OnClick = Button1Click
384 | end
385 | object edtPort: TEdit
386 | Left = 15
387 | Top = 24
388 | Width = 71
389 | Height = 25
390 | NumbersOnly = True
391 | TabOrder = 2
392 | Text = '4567'
393 | end
394 | end
395 | object boxHeader: TPanel
396 | Left = 0
397 | Top = 0
398 | Width = 455
399 | Height = 66
400 | Align = alTop
401 | BevelOuter = bvNone
402 | Caption = 'boxHeader'
403 | Font.Charset = DEFAULT_CHARSET
404 | Font.Color = clWindowText
405 | Font.Height = -13
406 | Font.Name = 'Segoe UI'
407 | Font.Style = []
408 | ParentFont = False
409 | ShowCaption = False
410 | TabOrder = 2
411 | object Label10: TLabel
412 | Left = 15
413 | Top = 16
414 | Width = 33
415 | Height = 33
416 | Caption = #59607
417 | Font.Charset = DEFAULT_CHARSET
418 | Font.Color = clWindowText
419 | Font.Height = -33
420 | Font.Name = 'Segoe MDL2 Assets'
421 | Font.Style = []
422 | ParentFont = False
423 | end
424 | object Label11: TLabel
425 | Left = 77
426 | Top = 12
427 | Width = 170
428 | Height = 37
429 | Caption = 'SAML - DEMO'
430 | Font.Charset = DEFAULT_CHARSET
431 | Font.Color = clWindowText
432 | Font.Height = -27
433 | Font.Name = 'Segoe UI'
434 | Font.Style = []
435 | ParentFont = False
436 | end
437 | end
438 | object OpenDialog1: TOpenDialog
439 | Left = 216
440 | Top = 208
441 | end
442 | end
443 |
--------------------------------------------------------------------------------
/Demos/XmlSec/SAML.XML.MainForm.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | unit SAML.XML.MainForm;
24 |
25 | interface
26 |
27 | uses
28 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
29 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, ZLib, System.IOUtils,
30 | Vcl.ExtCtrls, System.NetEncoding;
31 |
32 | type
33 | TMainForm = class(TForm)
34 | memInput: TMemo;
35 | edtInputXMLName: TComboBox;
36 | edtPublicKeyName: TComboBox;
37 | Label1: TLabel;
38 | Label2: TLabel;
39 | Label3: TLabel;
40 | Label4: TLabel;
41 | edtPrivateKeyName: TComboBox;
42 | memOutput: TMemo;
43 | Label5: TLabel;
44 | edtPrivateKeyFormat: TComboBox;
45 | Label6: TLabel;
46 | edtPublicKeyFormat: TComboBox;
47 | edtOutputXMLName: TComboBox;
48 | btnInputXMLView: TButton;
49 | btnOutputXMLView: TButton;
50 | boxFooter: TPanel;
51 | btnSign: TButton;
52 | btnVerify: TButton;
53 | btnEncrypt: TButton;
54 | btnDecrypt: TButton;
55 | boxHeader: TPanel;
56 | Label10: TLabel;
57 | Label11: TLabel;
58 | btnVerifyKeyEmb: TButton;
59 | Label7: TLabel;
60 | cmbRoot: TComboBox;
61 | memLog: TMemo;
62 | chkAddSignatureTemplate: TCheckBox;
63 | procedure btnSignClick(Sender: TObject);
64 | procedure btnVerifyClick(Sender: TObject);
65 | procedure btnDecryptClick(Sender: TObject);
66 | procedure FormCreate(Sender: TObject);
67 | procedure btnInputXMLViewClick(Sender: TObject);
68 | procedure btnOutputXMLViewClick(Sender: TObject);
69 | procedure btnEncryptClick(Sender: TObject);
70 | procedure btnVerifyKeyEmbClick(Sender: TObject);
71 | procedure edtInputXMLNameChange(Sender: TObject);
72 | private
73 | procedure Log(const AMessage: string);
74 | procedure ClearLog;
75 | procedure FillCombos;
76 | procedure FindRootNode(const AFileName: string);
77 | public
78 | { Public declarations }
79 | end;
80 |
81 | TNodeInfo = record
82 | Namespace: string;
83 | TagName: string;
84 | class operator Implicit(const AValue: string): TNodeInfo;
85 | class operator Implicit(const AValue: TNodeInfo): string;
86 | end;
87 |
88 | var
89 | MainForm: TMainForm;
90 |
91 | implementation
92 |
93 | {$R *.dfm}
94 |
95 | uses
96 | System.Types,
97 | SAML.XML.Utils;
98 |
99 | procedure TMainForm.btnEncryptClick(Sender: TObject);
100 | var
101 | LXMLDocument: IXMLSecDocument;
102 | LEncryptionContext: IEncryptionContext;
103 | begin
104 | ClearLog;
105 |
106 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
107 |
108 | LEncryptionContext := TEncryptionContext.Create;
109 | //LEncryptionContext.LoadKey(TFileStream.Create(edtPublicKeyName.Text, fmOpenRead), TKeyDataFormat(edtPublicKeyFormat.ItemIndex), True);
110 | LEncryptionContext.Encrypt(LXMLDocument);
111 |
112 | LXMLDocument.SaveToFile(edtOutputXMLName.Text);
113 | end;
114 |
115 | procedure TMainForm.btnInputXMLViewClick(Sender: TObject);
116 | begin
117 | memInput.Text := TFile.ReadAllText(edtInputXMLName.Text);
118 | end;
119 |
120 | procedure TMainForm.btnOutputXMLViewClick(Sender: TObject);
121 | begin
122 | memOutput.Text := TFile.ReadAllText(edtOutputXMLName.Text);
123 | end;
124 |
125 | procedure TMainForm.btnSignClick(Sender: TObject);
126 | var
127 | LXMLDocument: IXMLSecDocument;
128 | LIdNode: IXMLSecNode;
129 | LSignatureContext: ISignatureContext;
130 | LNodeInfo: TNodeInfo;
131 | begin
132 | ClearLog;
133 |
134 | LNodeInfo := cmbRoot.Text;
135 |
136 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
137 |
138 | if chkAddSignatureTemplate.Checked then
139 | begin
140 | if not LXMLDocument.TryFindNode(LNodeInfo.TagName, LNodeInfo.Namespace, LIdNode) then
141 | raise Exception.CreateFmt('Node %s:%s not found', [LNodeInfo.TagName, LNodeInfo.Namespace]);
142 |
143 | LXMLDocument.CheckSignatureTemplate(LIdNode.ID, [TTemplateOption.InjectCertificate]);
144 | end
145 | else
146 | LXMLDocument.CheckSignatureTemplate('', []);
147 |
148 | LXMLDocument.AddIDAttr('ID', LNodeInfo.TagName, LNodeInfo.Namespace);
149 |
150 | LSignatureContext := TSignatureContext.Create;
151 | LSignatureContext.LoadKey(TFileStream.Create(edtPrivateKeyName.Text, fmOpenRead), TKeyDataFormat(edtPrivateKeyFormat.ItemIndex), True);
152 |
153 | if edtPublicKeyName.Text <> '' then
154 | LSignatureContext.LoadCertificate(TFileStream.Create(edtPublicKeyName.Text, fmOpenRead), TKeyDataFormat(edtPublicKeyFormat.ItemIndex), True);
155 |
156 | LSignatureContext.Sign(LXMLDocument);
157 |
158 | memOutput.Text := LXMLDocument.ToXML;
159 |
160 | if edtOutputXMLName.Text <> '' then
161 | LXMLDocument.SaveToFile(edtOutputXMLName.Text);
162 | end;
163 |
164 | procedure TMainForm.btnVerifyClick(Sender: TObject);
165 | var
166 | LXMLDocument: IXMLSecDocument;
167 | LSignatureContext: ISignatureContext;
168 | LStatus: Boolean;
169 | LSignedNode: IXMLSecNode;
170 | LNodeInfo: TNodeInfo;
171 | begin
172 | ClearLog;
173 |
174 | if edtPublicKeyName.Text = '' then
175 | raise Exception.Create('Select a public key');
176 |
177 | LNodeInfo := cmbRoot.Text;
178 |
179 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
180 | LSignedNode := LXMLDocument.FindNode(LNodeInfo.TagName, LNodeInfo.Namespace);
181 |
182 | LXMLDocument.AddIDAttr('ID', LNodeInfo.TagName, LNodeInfo.Namespace);
183 |
184 | LSignatureContext := TSignatureContext.Create;
185 | LSignatureContext.LoadKey(TFileStream.Create(edtPublicKeyName.Text, fmOpenRead), TKeyDataFormat(edtPublicKeyFormat.ItemIndex), True);
186 | LStatus := LSignatureContext.Verify(LSignedNode);
187 |
188 | ShowMessage(BoolToStr(LStatus, True));
189 | end;
190 |
191 | procedure TMainForm.btnVerifyKeyEmbClick(Sender: TObject);
192 | var
193 | LXMLDocument: IXMLSecDocument;
194 | LSignatureContext: ISignatureContext;
195 | LStatus: Boolean;
196 | LSignedNode: IXMLSecNode;
197 | LKeyNode: IXMLSecNode;
198 | LKey: TBytes;
199 | LNodeInfo: TNodeInfo;
200 | begin
201 | ClearLog;
202 |
203 | LNodeInfo := cmbRoot.Text;
204 |
205 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
206 | LSignedNode := LXMLDocument.FindNode(LNodeInfo.TagName, LNodeInfo.Namespace);
207 |
208 | LXMLDocument.AddIDAttr('ID', LNodeInfo.TagName, LNodeInfo.Namespace);
209 |
210 | LKeyNode := LXMLDocument.FindNode('X509Certificate', 'http://www.w3.org/2000/09/xmldsig#');
211 | LKey := TNetEncoding.Base64.DecodeStringToBytes(LKeyNode.Text);
212 | if Length(LKey) = 0 then
213 | raise Exception.Create('No certificate found in signed XML');
214 |
215 | LSignatureContext := TSignatureContext.Create;
216 | LSignatureContext.LoadKey(TBytesStream.Create(LKey), TKeyDataFormat.CertDer, True);
217 | LStatus := LSignatureContext.Verify(LSignedNode);
218 |
219 | ShowMessage(BoolToStr(LStatus, True));
220 | end;
221 |
222 | procedure TMainForm.ClearLog;
223 | begin
224 | memLog.Clear;
225 | end;
226 |
227 | procedure TMainForm.FindRootNode(const AFileName: string);
228 | var
229 | LXMLDocument: IXMLSecDocument;
230 | LRootNode: IXMLSecNode;
231 | begin
232 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
233 | LRootNode := LXMLDocument.Root;
234 | cmbRoot.Text := LRootNode.Namespace + ':' + LRootNode.NodeName;
235 | end;
236 |
237 | procedure TMainForm.edtInputXMLNameChange(Sender: TObject);
238 | begin
239 | if FileExists(edtInputXMLName.Text) then
240 | FindRootNode(edtInputXMLName.Text);
241 | end;
242 |
243 | procedure TMainForm.btnDecryptClick(Sender: TObject);
244 | var
245 | LXMLDocument: IXMLSecDocument;
246 | LEncryptionContext: IEncryptionContext;
247 | begin
248 | ClearLog;
249 |
250 | LXMLDocument := TXMLSecDocument.Create(TFileStream.Create(edtInputXMLName.Text, fmOpenRead), True);
251 | LXMLDocument.AddIDAttr('Id', 'EncryptedKey', 'http://www.w3.org/2001/04/xmlenc#');
252 |
253 | LEncryptionContext := TEncryptionContext.Create;
254 | LEncryptionContext.LoadKey(TFileStream.Create(edtPrivateKeyName.Text, fmOpenRead), TKeyDataFormat(edtPrivateKeyFormat.ItemIndex), True);
255 | LEncryptionContext.Decrypt(LXMLDocument);
256 |
257 | LXMLDocument.SaveToFile(edtOutputXMLName.Text);
258 | end;
259 |
260 | procedure TMainForm.FillCombos;
261 | var
262 | LFiles: TStringDynArray;
263 | LFileName: string;
264 | begin
265 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.xml');
266 | for LFileName in LFiles do
267 | begin
268 | edtInputXMLName.Items.Add(ExtractFileName(LFileName));
269 | edtOutputXMLName.Items.Add(ExtractFileName(LFileName));
270 | end;
271 |
272 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.pem');
273 | for LFileName in LFiles do
274 | begin
275 | edtPublicKeyName.Items.Add(ExtractFileName(LFileName));
276 | edtPrivateKeyName.Items.Add(ExtractFileName(LFileName));
277 | end;
278 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.der');
279 | for LFileName in LFiles do
280 | begin
281 | edtPublicKeyName.Items.Add(ExtractFileName(LFileName));
282 | edtPrivateKeyName.Items.Add(ExtractFileName(LFileName));
283 | end;
284 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.crt');
285 | for LFileName in LFiles do
286 | begin
287 | edtPublicKeyName.Items.Add(ExtractFileName(LFileName));
288 | edtPrivateKeyName.Items.Add(ExtractFileName(LFileName));
289 | end;
290 | end;
291 |
292 | procedure TMainForm.FormCreate(Sender: TObject);
293 | begin
294 | edtPrivateKeyFormat.ItemIndex := 0;
295 | edtPublicKeyFormat.ItemIndex := 0;
296 | FillCombos;
297 |
298 | edtPrivateKeyFormat.ItemIndex := 2;
299 | edtPublicKeyFormat.ItemIndex := 7;
300 |
301 | TXMLSec.RegisterErrorCallback(
302 | procedure (const ASecError: TXMLSecError)
303 | begin
304 | MainForm.Log(ASecError.ErrorMessage);
305 | end
306 | );
307 | end;
308 |
309 | procedure TMainForm.Log(const AMessage: string);
310 | begin
311 | memLog.Lines.Add(AMessage);
312 | end;
313 |
314 | { TNodeInfo }
315 |
316 | class operator TNodeInfo.Implicit(const AValue: TNodeInfo): string;
317 | begin
318 | Result := AValue.Namespace + ':' + AValue.TagName;
319 | end;
320 |
321 | class operator TNodeInfo.Implicit(const AValue: string): TNodeInfo;
322 | var
323 | LIndex: Integer;
324 | begin
325 | LIndex := AValue.LastIndexOf(':');
326 | if LIndex >= 0 then
327 | begin
328 | Result.Namespace := AValue.Substring(0, LIndex);
329 | Result.TagName := AValue.Substring(LIndex + 1);
330 | end
331 | else
332 | begin
333 | Result.Namespace := '';
334 | Result.TagName := AValue;
335 | end;
336 | end;
337 |
338 | end.
339 |
--------------------------------------------------------------------------------
/Demos/SAML/SPDemo.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {2714F32A-EFD6-4263-A07C-9B9EFC7182D7}
4 | 20.3
5 | VCL
6 | True
7 | Debug
8 | Win64
9 | 3
10 | Application
11 | SPDemo.dpr
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Cfg_1
34 | true
35 | true
36 |
37 |
38 | true
39 | Cfg_1
40 | true
41 | true
42 |
43 |
44 | true
45 | Base
46 | true
47 |
48 |
49 | true
50 | Cfg_2
51 | true
52 | true
53 |
54 |
55 | true
56 | Cfg_2
57 | true
58 | true
59 |
60 |
61 | false
62 | false
63 | false
64 | false
65 | false
66 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
67 | $(BDS)\bin\delphi_PROJECTICON.ico
68 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
69 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
70 | 1040
71 | SPDemo
72 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
73 | "Sapphire Kamri|VCLSTYLE|$(BDSCOMMONDIR)\Styles\SapphireKamri.vsf"
74 | ..\bin
75 | .\$(Platform)\$(Config)
76 |
77 |
78 | JvNet;vclwinx;DataSnapServer;rbIDE2128;dacvcl280;ibdac280;rbTC2128;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;rbBDE2128;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;dac280;ibdacfmx280;bindcompvclwinx;FmxTeeUI;ibdacvcl280;unidac280;emsedge;bindcompfmx;DBXFirebirdDriver;JvBands;StyleControls_d11Alexandria;inetdb;JvAppFrm;ibmonitor;FireDACSqliteDriver;DbxClientDriver;BarcodeStudio_XE11;FireDACASADriver;Tee;soapmidas;JclVcl;vclactnband;TeeUI;fmxFireDAC;dbexpress;Jcl;JvManagedThreads;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;JvPascalInterpreter;dacfmx280;unidacvcl280;vcltouch;fmxase;JvPluginSystem;DBXOdbcDriver;JvDB;dbrtl;JvTimeFramework;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;VCLXDBGrid280;FireDACMSAccDriver;JvCustom;CustomIPTransport;FireDACMSSQLDriver;JvSystem;rbRCL2128;DataSnapIndy10ServerTransport;JclDeveloperTools;JvControls;BarcodeReportBuilder_XE11;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;JvCrypt;FireDACMongoDBDriver;JvJans;JvMM;IndySystem;JvWizards;FireDACTDataDriver;JvGlobus;vcldb;ibxbindings;JclContainers;JvPageComps;vclFireDAC;JvCore;vquery280;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;unidacfmx280;IndyCore;RESTBackendComponents;EasyLib.Core;bindcompdbx;rbCloudSC2128;rtl;FireDACMySQLDriver;FireDACADSDriver;rbUSERDesign2128;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;JvDotNetCtrls;JvHMI;DBXSybaseASEDriver;JvRuntimeDesign;rbTCUI2128;DBXDb2Driver;JvXPCtrls;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;JvStdCtrls;ibxpress;JvDlgs;JvDocking;bindcompvcl;dsnap;JvPrintPreview;JvCmp;crcontrols280;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;rbUSER2128;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)
79 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
80 | Debug
81 | true
82 | 1033
83 | $(BDS)\bin\default_app.manifest
84 | none
85 |
86 |
87 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;StyleControls_d11Alexandria;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)
88 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
89 | Debug
90 | true
91 | 1033
92 | $(BDS)\bin\default_app.manifest
93 | ..\bin64
94 | none
95 |
96 |
97 | DEBUG;$(DCC_Define)
98 | true
99 | false
100 | true
101 | true
102 | true
103 | true
104 | true
105 |
106 |
107 | false
108 | PerMonitorV2
109 | true
110 | 1033
111 |
112 |
113 | PerMonitorV2
114 |
115 |
116 | false
117 | RELEASE;$(DCC_Define)
118 | 0
119 | 0
120 |
121 |
122 | PerMonitorV2
123 | true
124 | 1033
125 |
126 |
127 | PerMonitorV2
128 |
129 |
130 |
131 | MainSource
132 |
133 |
134 |
135 | dfm
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | dfm
146 | TDataModule
147 |
148 |
149 |
150 |
151 |
152 | Cfg_2
153 | Base
154 |
155 |
156 | Base
157 |
158 |
159 | Cfg_1
160 | Base
161 |
162 |
163 |
164 | Delphi.Personality.12
165 | Application
166 |
167 |
168 |
169 | SPDemo.dpr
170 |
171 |
172 |
173 |
174 | True
175 | True
176 |
177 |
178 | 12
179 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/Demos/Metadata/SAML.Forms.Main.pas:
--------------------------------------------------------------------------------
1 | {******************************************************************************}
2 | { }
3 | { Delphi SAML }
4 | { Copyright (c) 2022-2025 Ethea }
5 | { Author: Luca Minuti }
6 | { https://github.com/EtheaDev/Delphi-SAML }
7 | { }
8 | {******************************************************************************}
9 | { }
10 | { Licensed under the Apache License, Version 2.0 (the "License"); }
11 | { you may not use this file except in compliance with the License. }
12 | { You may obtain a copy of the License at }
13 | { }
14 | { http://www.apache.org/licenses/LICENSE-2.0 }
15 | { }
16 | { Unless required by applicable law or agreed to in writing, software }
17 | { distributed under the License is distributed on an "AS IS" BASIS, }
18 | { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
19 | { See the License for the specific language governing permissions and }
20 | { limitations under the License. }
21 | { }
22 | {******************************************************************************}
23 | unit SAML.Forms.Main;
24 |
25 | interface
26 |
27 | uses
28 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
29 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, System.IOUtils, System.Generics.Collections,
30 | SAML.Metadata, Vcl.Grids, Vcl.ValEdit, Vcl.ComCtrls;
31 |
32 | type
33 | TMainForm = class(TForm)
34 | boxHeader: TPanel;
35 | Label10: TLabel;
36 | Label11: TLabel;
37 | SaveDialog1: TSaveDialog;
38 | pgcMain: TPageControl;
39 | tabReader: TTabSheet;
40 | Panel1: TPanel;
41 | Label12: TLabel;
42 | edtMetatadata: TComboBox;
43 | grdValues: TStringGrid;
44 | Panel2: TPanel;
45 | Label1: TLabel;
46 | edtKeys: TComboBox;
47 | btnSave: TButton;
48 | OpenDialog1: TOpenDialog;
49 | btnOpenFile: TButton;
50 | tabWriter: TTabSheet;
51 | btnNew: TButton;
52 | btnWriterSave: TButton;
53 | dlgSaveMetadata: TSaveDialog;
54 | Label9: TLabel;
55 | cmbIniFiles: TComboBox;
56 | btnIniFile: TButton;
57 | GroupBox1: TGroupBox;
58 | Label2: TLabel;
59 | Label3: TLabel;
60 | Label4: TLabel;
61 | Label5: TLabel;
62 | Label6: TLabel;
63 | Label7: TLabel;
64 | Label8: TLabel;
65 | edtEntityID: TEdit;
66 | edtLocation: TEdit;
67 | edtProtocolBinding: TComboBox;
68 | edtCacheDuration: TEdit;
69 | edtValidUntil: TEdit;
70 | edtCertificate: TEdit;
71 | edtCerificateFormat: TComboBox;
72 | procedure FormCreate(Sender: TObject);
73 | procedure FormDestroy(Sender: TObject);
74 | procedure btnSaveClick(Sender: TObject);
75 | procedure lstValuesKeyPress(Sender: TObject; var Key: Char);
76 | procedure AddValues(const AKey, AValue: string);
77 | procedure AddTitle(const ATitle: string);
78 | procedure grdValuesDrawCell(Sender: TObject; ACol, ARow: Integer;
79 | Rect: TRect; State: TGridDrawState);
80 | procedure FormResize(Sender: TObject);
81 | procedure edtMetatadataChange(Sender: TObject);
82 | procedure btnOpenFileClick(Sender: TObject);
83 | procedure btnNewClick(Sender: TObject);
84 | procedure btnWriterSaveClick(Sender: TObject);
85 | procedure cmbIniFilesChange(Sender: TObject);
86 | private
87 | FMetadata: TSAMLMetadata;
88 | FNewMetadata: TSAMLMetadata;
89 | procedure LoadXML;
90 | procedure LoadIni;
91 | procedure ParseXML(const AFileName: string);
92 | procedure ParseINI(const AFileName: string);
93 | procedure ParseEditINI(const AFileName: string);
94 | procedure ShowMetadata(AMetadata: TSAMLMetadata);
95 | public
96 | { Public declarations }
97 | end;
98 |
99 | var
100 | MainForm: TMainForm;
101 |
102 | implementation
103 |
104 | {$R *.dfm}
105 |
106 | uses
107 | System.Types,
108 | SAML.Config, SAML.Core, SAML.XML.Utils;
109 |
110 | procedure TMainForm.ShowMetadata(AMetadata: TSAMLMetadata);
111 | var
112 | LSSOPair: TPair;
113 | LKey: TKeyDescriptor;
114 | LConsumerService: TPair;
115 | LIndex: Integer;
116 | begin
117 | edtKeys.Clear;
118 | grdValues.ColCount := 2;
119 | grdValues.RowCount := 0;
120 |
121 | AddTitle('General');
122 | AddValues('EntityID', FMetadata.EntityID);
123 | if FMetadata.Kind = TMetadataKind.SP then
124 | begin
125 | AddValues('AuthnRequestsSigned', BoolToStr(FMetadata.AuthnRequestsSigned, True));
126 | AddValues('WantAssertionsSigned', BoolToStr(FMetadata.WantAssertionsSigned, True));
127 | end;
128 |
129 | if FMetadata.SSO.Count > 0 then
130 | begin
131 | AddTitle('SSO Service');
132 | for LSSOPair in FMetadata.SSO do
133 | begin
134 | AddValues(LSSOPair.Key, LSSOPair.Value);
135 | end;
136 | end;
137 |
138 | if FMetadata.SLO.Count > 0 then
139 | begin
140 | AddTitle('SLO Service');
141 | for LSSOPair in FMetadata.SLO do
142 | begin
143 | AddValues(LSSOPair.Key, LSSOPair.Value);
144 | end;
145 | end;
146 |
147 | if FMetadata.Keys.Count > 0 then
148 | begin
149 | AddTitle('KEYS');
150 | LIndex := 1;
151 | for LKey in FMetadata.Keys do
152 | begin
153 | AddValues('Key' + LIndex.ToString, LKey.Use);
154 | Inc(LIndex);
155 | edtKeys.Items.Add(LKey.Use);
156 | end;
157 | end;
158 |
159 | if FMetadata.ConsumerService.Count > 0 then
160 | begin
161 | AddTitle('ConsumerService');
162 | for LConsumerService in FMetadata.ConsumerService do
163 | begin
164 | AddValues(LConsumerService.Key, LConsumerService.Value);
165 | end;
166 | end;
167 | end;
168 |
169 | procedure TMainForm.ParseEditINI(const AFileName: string);
170 | var
171 | LSPConfig: TSAMLSPConfig;
172 | begin
173 | LSPConfig := TSAMLSPConfig.Create;
174 | try
175 | LSPConfig.LoadFromFile(AFileName);
176 | edtEntityID.Text := LSPConfig.EntityId;
177 | // FMetadata.AuthnRequestsSigned := LSPConfig.SignRequest;
178 | // FMetadata.ConsumerService.Add(TSAML.BINDINGS_HTTP_POST, LSPConfig.AssertionUrl);
179 | // FMetadata.ConsumerService.Add(TSAML.BINDINGS_HTTP_REDIRECT, LSPConfig.AssertionUrl);
180 | //
181 | // if LSPConfig.SignPubKeyFormat <> TKeyDataFormat.Der then
182 | // raise Exception.Create('The key must be in DER format');
183 | // LKeyFileName := TPath.Combine(ExtractFileDir(AFileName), LSPConfig.SignPubKeyFile);
184 | // LKeyData := TFile.ReadAllBytes(LKeyFileName);
185 | // FMetadata.Keys.Add(TKeyDescriptor.Create('signing', LKeyData));
186 | //
187 | // if LSPConfig.EncPubKeyFormat <> TKeyDataFormat.Der then
188 | // raise Exception.Create('The key must be in DER format');
189 | // LKeyFileName := TPath.Combine(ExtractFileDir(AFileName), LSPConfig.EncPubKeyFile);
190 | // LKeyData := TFile.ReadAllBytes(LKeyFileName);
191 | // FMetadata.Keys.Add(TKeyDescriptor.Create('encryption', LKeyData));
192 | finally
193 | LSPConfig.Free;
194 | end;
195 |
196 | end;
197 |
198 | procedure TMainForm.ParseINI(const AFileName: string);
199 | var
200 | LSPConfig: TSAMLSPConfig;
201 | LKeyData: TBytes;
202 | LKeyFileName: string;
203 | begin
204 | if Assigned(FMetadata) then
205 | FMetadata.Free;
206 |
207 | FMetadata := TSAMLMetadata.Create();
208 | try
209 | LSPConfig := TSAMLSPConfig.Create;
210 | try
211 | LSPConfig.LoadFromFile(AFileName);
212 | FMetadata.EntityID := LSPConfig.EntityId;
213 | FMetadata.AuthnRequestsSigned := LSPConfig.SignRequest;
214 | FMetadata.ConsumerService.Add(TSAML.BINDINGS_HTTP_POST, LSPConfig.AssertionUrl);
215 | FMetadata.ConsumerService.Add(TSAML.BINDINGS_HTTP_REDIRECT, LSPConfig.AssertionUrl);
216 |
217 | if LSPConfig.SignPubKeyFormat <> TKeyDataFormat.Der then
218 | raise Exception.Create('The key must be in DER format');
219 | LKeyFileName := TPath.Combine(ExtractFileDir(AFileName), LSPConfig.SignPubKeyFile);
220 | LKeyData := TFile.ReadAllBytes(LKeyFileName);
221 | FMetadata.Keys.Add(TKeyDescriptor.Create('signing', LKeyData));
222 |
223 | if LSPConfig.EncPubKeyFormat <> TKeyDataFormat.Der then
224 | raise Exception.Create('The key must be in DER format');
225 | LKeyFileName := TPath.Combine(ExtractFileDir(AFileName), LSPConfig.EncPubKeyFile);
226 | LKeyData := TFile.ReadAllBytes(LKeyFileName);
227 | FMetadata.Keys.Add(TKeyDescriptor.Create('encryption', LKeyData));
228 | finally
229 | LSPConfig.Free;
230 | end;
231 | ShowMetadata(FMetadata);
232 | except
233 | FMetadata.Free;
234 | raise;
235 | end;
236 | end;
237 |
238 | procedure TMainForm.ParseXML(const AFileName: string);
239 | begin
240 | if Assigned(FMetadata) then
241 | FMetadata.Free;
242 |
243 | FMetadata := TSAMLMetadata.Create(AFileName);
244 | try
245 | ShowMetadata(FMetadata);
246 | except
247 | FMetadata.Free;
248 | raise;
249 | end;
250 | end;
251 |
252 | procedure TMainForm.AddTitle(const ATitle: string);
253 | begin
254 | AddValues('+' + ATitle, '');
255 | end;
256 |
257 | procedure TMainForm.AddValues(const AKey, AValue: string);
258 | var
259 | LRowIndex: Integer;
260 | begin
261 | LRowIndex := grdValues.RowCount - 1;
262 | grdValues.Cells[0, LRowIndex] := AKey;
263 | grdValues.Cells[1, LRowIndex] := AValue;
264 | grdValues.RowCount := grdValues.RowCount + 1;
265 | end;
266 |
267 | procedure TMainForm.LoadIni;
268 | var
269 | LFiles: TStringDynArray;
270 | LFileName: string;
271 | begin
272 | cmbIniFiles.Items.Clear;
273 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.ini');
274 | for LFileName in LFiles do
275 | cmbIniFiles.Items.Add(ExtractFileName(LFileName));
276 | end;
277 |
278 | procedure TMainForm.LoadXML;
279 | var
280 | LFiles: TStringDynArray;
281 | LFileName: string;
282 | begin
283 | edtMetatadata.Items.Clear;
284 | LFiles := TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.xml');
285 | for LFileName in LFiles do
286 | edtMetatadata.Items.Add(ExtractFileName(LFileName));
287 | end;
288 |
289 | procedure TMainForm.lstValuesKeyPress(Sender: TObject; var Key: Char);
290 | begin
291 | Key := #0;
292 | end;
293 |
294 | procedure TMainForm.btnNewClick(Sender: TObject);
295 | begin
296 | if Assigned(FNewMetadata) then
297 | FreeAndNil(FNewMetadata);
298 |
299 | FNewMetadata := TSAMLMetadata.Create;
300 | end;
301 |
302 | procedure TMainForm.btnOpenFileClick(Sender: TObject);
303 | begin
304 | if OpenDialog1.Execute(Handle) then
305 | begin
306 | if SameText(ExtractFileExt(OpenDialog1.FileName), '.xml') then
307 | ParseXML(OpenDialog1.FileName)
308 | else
309 | ParseINI(OpenDialog1.FileName)
310 | end;
311 | end;
312 |
313 | procedure TMainForm.btnSaveClick(Sender: TObject);
314 | begin
315 | if edtKeys.ItemIndex >= 0 then
316 | begin
317 | SaveDialog1.FileName := edtKeys.Text + '.der';
318 | if SaveDialog1.Execute(Handle) then
319 | begin
320 | TFile.WriteAllBytes(SaveDialog1.FileName, FMetadata.Keys[edtKeys.ItemIndex].Certificate);
321 | end;
322 | end;
323 | end;
324 |
325 | procedure TMainForm.btnWriterSaveClick(Sender: TObject);
326 | begin
327 | FNewMetadata.EntityID := edtEntityID.Text;
328 | FNewMetadata.Location := edtLocation.Text;
329 | FNewMetadata.ProtocolBinding := edtProtocolBinding.Text;
330 | FNewMetadata.CacheDuration := edtCacheDuration.Text;
331 | FNewMetadata.ValidUntil := Now + StrToIntDef(edtValidUntil.Text, 1) * 365;
332 | FNewMetadata.Keys.Clear;
333 |
334 | if edtCertificate.Text <> '' then
335 | begin
336 | if not FileExists(edtCertificate.Text) then
337 | raise Exception.CreateFmt('File "%s" not found', [edtCertificate.Text]);
338 |
339 | FNewMetadata.Keys.AddCertificate('signing',
340 | TFileStream.Create(edtCertificate.Text, fmOpenRead),
341 | TCertificateFormat(edtCerificateFormat.ItemIndex),
342 | True);
343 | end;
344 |
345 | if dlgSaveMetadata.Execute(Handle) then
346 | begin
347 | TFile.WriteAllText(dlgSaveMetadata.FileName, FNewMetadata.AsXML);
348 | end;
349 | end;
350 |
351 | procedure TMainForm.cmbIniFilesChange(Sender: TObject);
352 | begin
353 | if cmbIniFiles.ItemIndex >= 0 then
354 | ParseEditIni(cmbIniFiles.Text);
355 | end;
356 |
357 | procedure TMainForm.edtMetatadataChange(Sender: TObject);
358 | begin
359 | if edtMetatadata.ItemIndex >= 0 then
360 | ParseXML(edtMetatadata.Text);
361 | end;
362 |
363 | procedure TMainForm.FormCreate(Sender: TObject);
364 | begin
365 | pgcMain.ActivePageIndex := 0;
366 | LoadXML;
367 | LoadIni;
368 | FNewMetadata := TSAMLMetadata.Create;
369 | end;
370 |
371 | procedure TMainForm.FormDestroy(Sender: TObject);
372 | begin
373 | FMetadata.Free;
374 | FNewMetadata.Free;
375 | end;
376 |
377 | procedure TMainForm.FormResize(Sender: TObject);
378 | const
379 | ScrollbarAndBorderWidth = 30;
380 | begin
381 | grdValues.ColCount := 2;
382 | grdValues.ColWidths[0] := (grdValues.Width - ScrollbarAndBorderWidth) div 2;
383 | grdValues.ColWidths[1] := (grdValues.Width - ScrollbarAndBorderWidth) div 2;
384 | end;
385 |
386 | procedure TMainForm.grdValuesDrawCell(Sender: TObject; ACol, ARow: Integer;
387 | Rect: TRect; State: TGridDrawState);
388 | begin
389 | if grdValues.Cells[0, ARow].StartsWith('+') then
390 | begin
391 | grdValues.Canvas.Brush.Color := clBtnFace;
392 | grdValues.Canvas.FillRect(Rect);
393 | if ACol = 0 then
394 | grdValues.Canvas.TextRect(Rect, Rect.Left + 5, Rect.Top + 5, Copy(grdValues.Cells[0, ARow], 2, 100));
395 | end;
396 | end;
397 |
398 | end.
399 |
--------------------------------------------------------------------------------