├── .gitignore
├── .scrutinizer.yml
├── .travis.yml
├── CHANGELOG-1.0.md
├── CONTRIBUTORS.md
├── LICENSE
├── README.md
├── autoload.php
├── bin
├── lightsaml
├── lightsaml.bat
└── lightsaml.php
├── composer.json
├── composer.lock
├── doc
├── command_sp_meta_build.md
├── console.md
├── index.md
└── signing_and_certificates.md
├── phpunit.xml
├── resources
└── sample
│ ├── Certificate
│ ├── saml.crt
│ └── saml.pem
│ ├── EntitiesDescriptor
│ └── testshib-providers.xml
│ ├── EntityDescriptor
│ ├── ed01-formatted-certificate.xml
│ ├── idp-ed.xml
│ ├── idp2-ed.xml
│ ├── sp-ed.xml
│ └── sp-ed2.xml
│ ├── Request
│ ├── logoutrequest01.xml
│ └── request01.xml
│ ├── Response
│ ├── invalid.xml
│ ├── invalid02.xml
│ ├── response01-formatted.xml
│ ├── response01.xml
│ ├── response02.xml
│ ├── response03-formatted.xml
│ └── response03.xml
│ ├── foo-formatted.xml
│ └── foo.xml
└── src
└── AerialShip
└── LightSaml
├── Binding
├── AbstractBinding.php
├── BindingDetector.php
├── HttpPost.php
├── HttpPostTemplate.php
├── HttpRedirect.php
├── PostResponse.php
├── RedirectResponse.php
├── Request.php
└── Response.php
├── Bindings.php
├── ClaimTypes.php
├── Command
└── BuildSPMetadataCommand.php
├── Error
├── BindingException.php
├── BuildRequestException.php
├── InvalidAssertionException.php
├── InvalidAuthnStatementException.php
├── InvalidBindingException.php
├── InvalidCertificateException.php
├── InvalidMessageException.php
├── InvalidNameIDException.php
├── InvalidRequestException.php
├── InvalidResponseException.php
├── InvalidSubjectException.php
├── InvalidXmlException.php
├── InvalidXmlNamespaceException.php
├── LightSamlBaseException.php
└── SecurityException.php
├── Helper.php
├── Meta
├── AbstractRequestBuilder.php
├── AuthnRequestBuilder.php
├── GetSignedXmlInterface.php
├── GetXmlInterface.php
├── LoadFromXmlInterface.php
├── LogoutRequestBuilder.php
├── SerializationContext.php
├── SpMeta.php
├── XmlChildrenLoaderTrait.php
└── XmlRequiredAttributesTrait.php
├── Model
├── Assertion
│ ├── Assertion.php
│ ├── Attribute.php
│ ├── AuthnStatement.php
│ ├── NameID.php
│ ├── Subject.php
│ ├── SubjectConfirmation.php
│ └── SubjectConfirmationData.php
├── Metadata
│ ├── EntitiesDescriptor.php
│ ├── EntityDescriptor.php
│ ├── IdpSsoDescriptor.php
│ ├── KeyDescriptor.php
│ ├── NameIDFormat.php
│ ├── SSODescriptor.php
│ ├── Service
│ │ ├── AbstractService.php
│ │ ├── AssertionConsumerService.php
│ │ ├── SingleLogoutService.php
│ │ └── SingleSignOnService.php
│ └── SpSsoDescriptor.php
├── Protocol
│ ├── AbstractRequest.php
│ ├── AuthnRequest.php
│ ├── LogoutRequest.php
│ ├── LogoutResponse.php
│ ├── Message.php
│ ├── Response.php
│ ├── Status.php
│ ├── StatusCode.php
│ └── StatusResponse.php
└── XmlDSig
│ ├── Signature.php
│ ├── SignatureCreator.php
│ ├── SignatureStringValidator.php
│ ├── SignatureValidatorInterface.php
│ └── SignatureXmlValidator.php
├── NameIDPolicy.php
├── Protocol.php
├── Security
├── KeyHelper.php
└── X509Certificate.php
└── Tests
├── Binding
├── Base.php
├── HttpPostTest.php
└── HttpRedirectTest.php
├── CommonHelper.php
├── Meta
└── AuthnRequestBuilderTest.php
├── Model
├── Metadata
│ ├── EntitiesDescriptor
│ │ ├── EntitiesDescriptorFunctional01Test.php
│ │ └── EntitiesDescriptorTest.php
│ ├── EntityDescriptor
│ │ ├── EntityDescriptorSample01Test.php
│ │ ├── EntityDescriptorSample02Test.php
│ │ └── EntityDescriptorXmlTest.php
│ └── SSODescriptor
│ │ └── SSODescriptorTest.php
├── Protocol
│ ├── AuthnRequest
│ │ └── AuthnRequestSample01Test.php
│ ├── LogoutRequest
│ │ └── LogoutRequestSample01Test.php
│ └── Response
│ │ └── ResponseSample01Test.php
└── XmlDSig
│ └── Signature
│ ├── SignatureCreatorValidatorFunctionalTest.php
│ └── SignatureSample01Test.php
└── Security
└── X509CertificateTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | # Bootstrap
2 | app/bootstrap*
3 |
4 | # Symfony directories
5 | vendor/*
6 | */logs/*
7 | */cache/*
8 | web/uploads/*
9 | web/bundles/*
10 |
11 | # Configuration files
12 | app/config/parameters.ini
13 | app/config/parameters.yml
14 |
15 | /.idea
16 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - php
3 |
4 | tools:
5 | external_code_coverage:
6 | timeout: 600 # Timeout in seconds.
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - hhvm
8 |
9 | matrix:
10 | allow_failures:
11 | - php: hhvm
12 |
13 | before_script:
14 | - COMPOSER_ROOT_VERSION=dev-master composer --prefer-source --dev install
15 |
16 | script:
17 | - phpunit --coverage-clover=coverage.clover
18 |
19 | after_script:
20 | - wget https://scrutinizer-ci.com/ocular.phar
21 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
22 |
--------------------------------------------------------------------------------
/CHANGELOG-1.0.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 1.0.x
2 | ===================
3 |
4 | 1.0.2 (2014-07-09)
5 | * [Bug] Logout Request Builder #5
6 | * [CodeStyle] Improve code metric #7
7 | * [Bug] Support for formatted certificate in message XML #10
8 | * [Bug] "KeyDescriptor" elment "use" attribute should be optional #12
9 | * [NewFeature] Support for EntitiesDescriptor element #11
10 | * [Bug] InResponseTo attribute optional for StatusResponse #14 #15
11 | * [Bug] InvalidArgumentException at LogoutRequest ->setNotOnOrAfter() #16
12 | * [NewFeature] New method in Signature Validator for array of keys #18
13 | * [NewFeature] New method EntitiesDescriptor::getByEntityId #19
14 | * [Bug] Fix AuthnRequest send and Response receive bidnings and url #20
15 | * [NewFeature] Logging of sent/received messages in Binding #23
16 | * [Bug] NameIDPolicy made optional in AuthnRequest? #21
17 | * [Bug] SignatureMethod element made optional #24
18 | * [Bug] StatusCode missing from status #26
19 | * [NewFeature] Optional constructor arguments 037a595fc
20 | * [NewFeature] Support for IdpSsoDescriptor Attributes & NameIdFormat e37b037d1
21 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | CONTRIBUTORS
2 | ============
3 |
4 | LightSaml so far is a result of work of
5 |
6 | * Milos Tomic (tmilos)
7 | * Boris Vujicic (i3or1s)
8 |
9 |
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 aerialship
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SAML 2.0 PHP Component
2 | ======================
3 |
4 | NEW VERSION
5 | -----------
6 |
7 | **New version of this library is in own organization: [lightsaml/lightsaml](https://github.com/lightsaml/lightsaml)**.
8 | Details can be found at [LightSAML website](http://www.lightsaml.com/LightSAML-Core/).
9 |
10 |
11 | [](https://waffle.io/aerialship/lightsaml)
12 | [](https://travis-ci.org/aerialship/lightsaml)
13 | [](https://scrutinizer-ci.com/g/aerialship/lightsaml/)
14 | [](https://insight.sensiolabs.com/projects/a5537ce0-a513-4d3d-ba7a-21e9115f4c89)
15 | [](https://scrutinizer-ci.com/g/aerialship/lightsaml/?branch=master)
16 | [](http://hhvm.h4cc.de/package/aerialship/lightsaml)
17 |
18 |
19 |
20 | LightSaml Implements basic SAML 2.0 data model classes, serialization/deserialization to/from xml with XML security and
21 | certificates support, and message encapsulations to bindings. Covered with unit tests.
22 |
23 | * [PHP SAML Symfony2 Bundle](https://github.com/aerialship/SamlSPBundle)
24 |
25 |
26 | DOCUMENTATION
27 | =============
28 |
29 | * [Usage](doc/index.md)
30 | * [Console](doc/console.md)
31 | * [Signing and Certificates](doc/signing_and_certificates.md)
32 |
33 |
34 | CONTRIBUTING
35 | ============
36 |
37 | LightSaml is an open source project and is open for contributions.
38 |
39 |
40 | CREDIT
41 | ======
42 |
43 | Thanks to all contributors and specially to SimpleSamlPHP open source which though hardly reusable helped us in
44 | start to understand better how SAML works and speed up the implementation.
45 |
--------------------------------------------------------------------------------
/autoload.php:
--------------------------------------------------------------------------------
1 | add(new \AerialShip\LightSaml\Command\BuildSPMetadataCommand());
10 | $app->run($input);
11 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aerialship/lightsaml",
3 | "license": "MIT",
4 | "description": "Light SAML2 php library",
5 | "autoload": {
6 | "psr-0": { "AerialShip\\LightSaml\\": "src/" }
7 | },
8 | "require": {
9 | "php": ">=5.4.1",
10 | "rnijveld/xmlseclibs": "1.3.1",
11 | "symfony/console": "~2.2"
12 | },
13 | "require-dev": {
14 | "phpunit/phpunit": "~4.1"
15 | },
16 | "bin": ["bin/lightsaml"],
17 | "prefer-stable": true,
18 | "minimum-stability": "stable"
19 | }
20 |
--------------------------------------------------------------------------------
/doc/command_sp_meta_build.md:
--------------------------------------------------------------------------------
1 |
2 | SP Metadata build command
3 | =========================
4 |
5 | ID: aerialship:lightsaml:sp:meta:build
6 | Class: AerialShip\LightSaml\Command\BuildSPMetadataCommand
7 |
8 | Used to build SP metadata xml. Just run it and follow dialog questions. As a result a metadata xml file is created.
9 |
10 |
--------------------------------------------------------------------------------
/doc/console.md:
--------------------------------------------------------------------------------
1 | LightSaml console
2 | =================
3 |
4 | Executes a lightsaml command.
5 |
6 | Location: bin/lightsaml
7 |
8 | Commands:
9 |
10 | * [aerialship:lightsaml:sp:meta:build](command_sp_meta_build.md)
11 |
--------------------------------------------------------------------------------
/doc/index.md:
--------------------------------------------------------------------------------
1 | METADATA
2 | ========
3 |
4 | Metadata building
5 | -----------------
6 |
7 | Use [aerialship:lightsaml:sp:meta:build](command_sp_meta_build.md) command for simple cases
8 |
9 | ```php
10 | $ed = new EntityDescriptor();
11 | $sp = new SpSsoDescriptor();
12 | $ed->addItem($sp);
13 |
14 | // KeyDescriptor
15 | $certificate = new X509Certificate();
16 | $certificate->loadFromFile($certificatePath);
17 | $keyDescriptor = new KeyDescriptor('signing', $certificate);
18 | $ed->addItem($keyDescriptor);
19 |
20 | // SingleLogoutService
21 | $s = new SingleLogoutService();
22 | $s->setLocation($url);
23 | $s->setBinding($this->resolveBinding($binding));
24 | $sp->addService($s);
25 |
26 | // AssertionConsumerService
27 | $s = new AssertionConsumerService($binding1, $url, 0);
28 | $sp->addService($s);
29 | $s = new AssertionConsumerService($binding2, $url, 1);
30 | $sp->addService($s);
31 | ```
32 |
33 | Saving metadata to xml
34 | ----------------------
35 |
36 | ```php
37 | $ed = new Model\Metadata\EntityDescriptor();
38 | // ...
39 | $context = new Meta\SerializationContext();
40 | $ed->getXml($context->getDocument(), $context);
41 | file_put_contents($context->getDocument()->saveXML(), $xml);
42 | ```
43 |
44 | Loading metadata from xml
45 | -------------------------
46 |
47 | ```php
48 | $doc = new \DOMDocument();
49 | $doc->load('sp.xml');
50 | $ed = new EntityDescriptor();
51 | $ed->loadFromXml($doc->firstChild);
52 | ```
53 |
54 |
55 | AUTHN REQUEST
56 | =============
57 |
58 | ```php
59 | $spMeta = new Meta\SpMeta();
60 | $spMeta->setNameIdFormat(NameIDPolicy::PERSISTENT);
61 | $spED = getEntityDescriptorSP();
62 | $idpED = getEntityDescriptorIDP();
63 |
64 | $builder = new Meta\AuthnRequestBuilder($spED, $idpED, $spMeta);
65 | $request = $builder->build();
66 | ```
67 |
68 |
69 | SENDING MESSAGE
70 | ===============
71 |
72 | HTTP Redirect
73 | -------------
74 |
75 | ```php
76 | $binding = new Binding\HttpRedirect();
77 | $bindingResponse = $binding->send($message);
78 | $bindingResponse->render();
79 | ```
80 |
81 | HTTP POST
82 | ---------
83 |
84 | ```php
85 | $binding = new Binding\HttpPost();
86 | $bindingResponse = $binding->send($message);
87 | $bindingResponse->render();
88 | ```
89 |
90 |
91 | RECEIVING MESSAGE
92 | =================
93 |
94 | ```php
95 | $request = new Binding\Request();
96 | $request->setQueryString($_SERVER['QUERY_STRING']);
97 | $request->setGet($_GET);
98 | $request->getPost($_POST);
99 | $request->setRequestMethod($_SERVER['REQUEST_METHOD']);
100 |
101 | $detector = new BindingDetector();
102 | $binding = $detector->instantiate($this->bindingDetector->getBinding($bindingRequest));
103 |
104 | $message = $binding->receive($bindingRequest);
105 | ```
106 |
--------------------------------------------------------------------------------
/doc/signing_and_certificates.md:
--------------------------------------------------------------------------------
1 | SIGNING AND CERTIFICATES
2 | ========================
3 |
4 | The LightSaml relies on the [xmlseclibs](https://code.google.com/p/xmlseclibs/) regarding signing and certificates
5 | functionality. LightSaml has helper methods and was tested using xmlseclibs with PEM format only.
6 |
7 |
8 | Creating self signed certificates
9 | ---------------------------------
10 |
11 | Run the following command to generate pem certificate and key
12 |
13 | ``` bash
14 | $ openssl req -new -x509 -days 3652 -nodes -out saml.crt -keyout saml.pem
15 | ```
16 |
17 | Loading certificate from file and creating public key
18 | -----------------------------------------------------
19 |
20 | ``` php
21 | $certificate = new X509Certificate();
22 | $certificate->loadFromFile($crtFilename);
23 |
24 | $publicKey = KeyHelper::createPublicKey($certificate);
25 | ```
26 |
27 |
28 | Creating private key
29 | --------------------
30 |
31 | ``` php
32 | $privateKey = KeyHelper::createPrivateKey($filename, $pass, true);
33 | ```
34 |
35 | Signing SAML messages
36 | ---------------------
37 | You would require private key for signing SAML messages.
38 |
39 | ``` php
40 | $message->sign($certificate, $privateKey);
41 | ```
42 |
43 | Exposing certificate in metadata
44 | --------------------------------
45 |
46 | If your SP supports signing you would need to expose your certificate in your SP's metadata entity descriptor
47 |
48 | ``` php
49 | $ed = new EntityDescriptor();
50 | $sp = new SpSsoDescriptor();
51 | $sp->addKeyDescriptor(new KeyDescriptor('signing', $certificate));
52 | $ed->->addItem($sp);
53 | ```
54 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | src/AerialShip/LightSaml/Tests
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/resources/sample/Certificate/saml.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNV
3 | BAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxML
4 | bXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQsw
5 | CQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNV
6 | BAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
7 | ws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35bre
8 | Ga9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0
9 | fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3
10 | iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4d
11 | kxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv
12 | +428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ce
13 | IXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQw
14 | QjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQw
15 | EgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJ
16 | KoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU
17 | 1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1dou
18 | g+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAq
19 | bz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3
20 | EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6r
21 | BYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=
22 | -----END CERTIFICATE-----
23 |
--------------------------------------------------------------------------------
/resources/sample/Certificate/saml.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs
3 | 1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20j
4 | TqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf
5 | 4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6
6 | GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj
7 | /jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABAoIBAAuwFflqsG/8XFfD
8 | QT+A5Ov6tPTmLw0wR6KguPKllT0SnkKRI/NwNpMuXM9y9CeYWpL37bUEdIl8HMlp
9 | z+cfu0K+sYVIMbp0a2H07qJRiuEHaGkFl0S0lgp6qWltP79LeDOpc2wjcwPQBjup
10 | LEE4WtsKhTHePUaBP1nH+rt9lOiVddR+09qJf+v149XGaMvU9CngnzB1QUHEZGu/
11 | g9gbr37uv0zaJ08Nr+eZvJ8ByVCbseEaM4bPE3pj/5GCI/b4Y24cEYyVxNWKxK4x
12 | DtVyMA9WkVg1J+C9cyQtWyFAByjfzLXCeRV5Yanh5erfBGxKeLf2iYj+67vZnoIV
13 | 45py66ECgYEA/Ejrir3dD1ehUf8QQrn9SzPtHKIfvKxjY9099Jr7YaFJMnsD3D3j
14 | EYV0Jf9MOVakc+cQyNuqLGXhgpcHuBIHFKxOQ2ROleUxBlix93wkKXYJTAbg3dlz
15 | HM5JOi5H1Ms/cHiZtmi7jP9qPxgvVx5PjnHT74gme6z2cVtSwmwQdzMCgYEAxa1J
16 | ubQehmU00SPhtmiD1nkv/5N1IzcerwAbMSfEe3VTbTer+c42F50GW0RPLhSTyS7I
17 | vKI2kjgnvbL+ZDftGJ/8Sy/xuR4oqI7HS8R/b0TDzs00Ih6jRoKvCvWc4Rz/LnAK
18 | 3U+By2kO0LoAYMMyEIROJY1ToM0ZJNw+YJi36I0CgYBYooHmd7gfuMjblwIuf0un
19 | TTID+k2uKt6sakFnG8Av18twqdl8Wl3ZfQqGgwBTsMYMVmUGPG64NH8bM1ap6+OC
20 | 9tp0QNx/O0uTEDxOV9YYnvi7NjtwlgIkX7FIeJQSBepe6HAQrxEdg2rfie6v691F
21 | jWZJZIsormbTAqO73N2YEwKBgE5vV9WLlqEU/0QMzL6n8cfkBhuO0ufKMy6VCDUU
22 | 5m1mPFgVwvM301bDQ4ZrME/Ecm9dVOEkLCsQhRRMNYxmdHlU4bKjr3IYeWGIZaO2
23 | sCniSx9/ZLQ1G+waZoIeusTH0KkIZAc0SPgBE5PWedfrG65aEPftf8VKHDP3//gs
24 | IKzxAoGBAKaDo/sPvb6Z/RLFDt+QH+VBLSFOrdAn4+tKmSoMHWRrx4mxt48NF4hh
25 | X+1z7SA9OHZ1iLBRwGhjWhyELkV0MvwCZDb3TC0wp+BJMGQnOMwB8KPisvHj/Qxh
26 | OgAVD1IafyfRczuodKG3I2qu2VRcLMbmUZKmhOQ/ylj93vKC5B/y
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/resources/sample/EntityDescriptor/ed01-formatted-certificate.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
8 |
9 |
10 |
11 | MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEV
12 | MBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYD
13 | VQQKEwhUZXN0U2hpYjEZMBcGA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4
14 | MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcxCzAJBgNVBAYTAlVTMRUwEwYDVQQI
15 | EwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gxETAPBgNVBAoTCFRl
16 | c3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0B
17 | AQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7C
18 | yVTDClcpu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe
19 | 3OQ01Ow3yT4I+Wdg1tsTpSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aT
20 | NPFmDixzUjoYzbGDrtAyCqA8f9CN2txIfJnpHE6q6CmKcoLADS4UrNPlhHSzd614
21 | kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB5/9nb0yh/ojRuJGmgMWH
22 | gWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HEMIHBMB0G
23 | A1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ86
24 | 9nh83KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBl
25 | bm5zeWx2YW5pYTETMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNo
26 | aWIxGTAXBgNVBAMTEGlkcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zAN
27 | BgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5MFfSVk98t3CT9jHZoYxd8QMRL
28 | I4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpkOAvZZUosVkUo
29 | 93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4
30 | /SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAj
31 | Geka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr
32 | 8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA==
33 |
34 |
35 |
36 |
37 |
39 |
41 |
43 |
45 |
46 |
--------------------------------------------------------------------------------
/resources/sample/EntityDescriptor/sp-ed.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
15 |
19 |
23 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/resources/sample/EntityDescriptor/sp-ed2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 | MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxMLbXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQswCQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNVBAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ceIXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQwQjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQwEgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1doug+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAqbz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6rBYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=
11 |
12 |
13 |
14 |
15 |
16 |
17 | MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxMLbXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQswCQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNVBAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ceIXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQwQjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQwEgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1doug+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAqbz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6rBYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/resources/sample/Request/logoutrequest01.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 | https://mt.evo.team/simplesaml/module.php/saml/sp/metadata.php/default-sp
11 | user
12 | _677952a2-7fb3-4e7a-b439-326366e677db
13 |
14 |
--------------------------------------------------------------------------------
/resources/sample/Request/request01.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 | https://mt.evo.team/simplesaml/module.php/saml/sp/metadata.php/default-sp
11 |
12 |
--------------------------------------------------------------------------------
/resources/sample/Response/invalid.xml:
--------------------------------------------------------------------------------
1 | https://B1.bead.loc/adfs/services/trust
--------------------------------------------------------------------------------
/resources/sample/Response/invalid02.xml:
--------------------------------------------------------------------------------
1 |
8 | https://sts.windows.net/554fadfe-f04f-4975-90cb-ddc8b147aaa2/
9 |
10 |
11 |
12 |
13 |
14 | ACS75006: An error occurred while processing a SAML2 Authentication request. ACS75003: SAML protocol response cannot be sent via bindings other than HTTP POST. Requested binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
15 | Trace ID: d75d5305-d3fc-40b0-9087-d59032682dd9
16 | Correlation ID: ca26b4bd-23d4-4233-9c28-96bc0a336c39
17 | Timestamp: 2013-11-17 12:35:10Z
18 |
19 |
20 |
--------------------------------------------------------------------------------
/resources/sample/Response/response01-formatted.xml:
--------------------------------------------------------------------------------
1 |
6 | https://B1.bead.loc/adfs/services/trust
7 |
8 |
9 |
10 |
12 | https://B1.bead.loc/adfs/services/trust
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | V8Ls9BSGOMwyyCmMtz2AFEGZdic=
24 |
25 |
26 |
27 | LHTt9aRHMBkgNukWiCEGTqrRavdHjz+i0duaUe6t1yVWVqRHsbdjQDHv4nxAPe18qMEO3j1PGoyjjFTZNR6v+yvuFu7zmARhxTjDuqzNGP5npiP5D8DACiTFyL1WFH8C7jZmJA5j9wRGDHq4xvMExQr2pTgQEHe1InmLvix8xjbPoevR7Wf1rG3nGIhfHcyQRpMqAeNQN2qI7hSQQ1k9rEGS7daz1j29YCeoWqvQ+hZNkhtY/HSCVeQzfXEG79AFZHpYQyXzWK+v8f48ntegIJx2hi9FV/HE4n4RBbNMdqbT9y71bw8EM/kEZoJehpgMgQYZP7ryGfdNMGWC9LfbjA==
28 |
29 |
30 |
31 |
32 | MIIC0jCCAbqgAwIBAgIQGFT6omLmWbhAD65bM40rGzANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDExpBREZTIFNpZ25pbmcgLSBCMS5iZWFkLmxvYzAeFw0xMzEwMDkxNDUyMDVaFw0xNDEwMDkxNDUyMDVaMCUxIzAhBgNVBAMTGkFERlMgU2lnbmluZyAtIEIxLmJlYWQubG9jMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlGKV64+63lpqdPmCTZ0kt/yKr8xukR1Y071SlmRVV5sSFhTe8cjylPqqxdyEBrfPhpL6vwFQyKfDhuM8T9E+BW5fUdoXO4WmIHrLOxV/BzKv2rDGidlCFzDSQPDxPH2RdQkMBksiauIMSHIYXB92rO4fkcsTgQ6cc+PZp4M3Z/jR1mcxQzz9RQk3I9w2OtI9xcv+uDC5mQU0ZWVHc99VSFQt+zshduwIqxQdHvMdTRslso+oCLEQom42pGCD8TksQTGw4sB7Ctb0mgXdfy0PDIznfi2oDBGtPY2Hkms6/n9xoyCynQea0YYXcpEe7lAvs+t6Lq+ZaKp2kUaa2x8d+QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfwlmaN1iPg0gNiqdVphJjWnzpV4h6/Mz3L0xYzNQeglWCDKCKuajQfmo/AQBErtOWZJsP8avzK79gNRqFHXF6CirjGnL6WO+S6Ug1hvy3xouOxOkIYgZsbmcNL2XO1hIxP4z/QWPthotp3FSUTae2hFBHuy4Gtb+9d9a60GDtgrHnfgVeCTE7CSiaI/D/51JNbtpg2tCpcEzMQgPkQqb8E+V79xc0dnEcI5cBaS6eYgkJgS5gKIMbwaJ/VxzCVGIKwFjFnJedJ5N7zH7OVwor56Q7nuKD7X4yFY9XR3isjGnwXveh9E4d9wD4CMl52AHJpsYsToXsi3eRvApDV/PE
33 |
34 |
35 |
36 |
37 |
38 | bos@bead.loc
39 |
40 |
43 |
44 |
45 |
46 |
47 | https://mt.evo.team/simplesaml/module.php/saml/sp/metadata.php/b1
48 |
49 |
50 |
51 |
52 | bos@bead.loc
53 |
54 |
55 |
56 |
57 | urn:federation:authentication:windows
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/resources/sample/Response/response01.xml:
--------------------------------------------------------------------------------
1 | https://B1.bead.loc/adfs/services/trusthttps://B1.bead.loc/adfs/services/trustV8Ls9BSGOMwyyCmMtz2AFEGZdic=LHTt9aRHMBkgNukWiCEGTqrRavdHjz+i0duaUe6t1yVWVqRHsbdjQDHv4nxAPe18qMEO3j1PGoyjjFTZNR6v+yvuFu7zmARhxTjDuqzNGP5npiP5D8DACiTFyL1WFH8C7jZmJA5j9wRGDHq4xvMExQr2pTgQEHe1InmLvix8xjbPoevR7Wf1rG3nGIhfHcyQRpMqAeNQN2qI7hSQQ1k9rEGS7daz1j29YCeoWqvQ+hZNkhtY/HSCVeQzfXEG79AFZHpYQyXzWK+v8f48ntegIJx2hi9FV/HE4n4RBbNMdqbT9y71bw8EM/kEZoJehpgMgQYZP7ryGfdNMGWC9LfbjA==MIIC0jCCAbqgAwIBAgIQGFT6omLmWbhAD65bM40rGzANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDExpBREZTIFNpZ25pbmcgLSBCMS5iZWFkLmxvYzAeFw0xMzEwMDkxNDUyMDVaFw0xNDEwMDkxNDUyMDVaMCUxIzAhBgNVBAMTGkFERlMgU2lnbmluZyAtIEIxLmJlYWQubG9jMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlGKV64+63lpqdPmCTZ0kt/yKr8xukR1Y071SlmRVV5sSFhTe8cjylPqqxdyEBrfPhpL6vwFQyKfDhuM8T9E+BW5fUdoXO4WmIHrLOxV/BzKv2rDGidlCFzDSQPDxPH2RdQkMBksiauIMSHIYXB92rO4fkcsTgQ6cc+PZp4M3Z/jR1mcxQzz9RQk3I9w2OtI9xcv+uDC5mQU0ZWVHc99VSFQt+zshduwIqxQdHvMdTRslso+oCLEQom42pGCD8TksQTGw4sB7Ctb0mgXdfy0PDIznfi2oDBGtPY2Hkms6/n9xoyCynQea0YYXcpEe7lAvs+t6Lq+ZaKp2kUaa2x8d+QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfwlmaN1iPg0gNiqdVphJjWnzpV4h6/Mz3L0xYzNQeglWCDKCKuajQfmo/AQBErtOWZJsP8avzK79gNRqFHXF6CirjGnL6WO+S6Ug1hvy3xouOxOkIYgZsbmcNL2XO1hIxP4z/QWPthotp3FSUTae2hFBHuy4Gtb+9d9a60GDtgrHnfgVeCTE7CSiaI/D/51JNbtpg2tCpcEzMQgPkQqb8E+V79xc0dnEcI5cBaS6eYgkJgS5gKIMbwaJ/VxzCVGIKwFjFnJedJ5N7zH7OVwor56Q7nuKD7X4yFY9XR3isjGnwXveh9E4d9wD4CMl52AHJpsYsToXsi3eRvApDV/PEbos@bead.lochttps://mt.evo.team/simplesaml/module.php/saml/sp/metadata.php/b1bos@bead.locurn:federation:authentication:windows
--------------------------------------------------------------------------------
/resources/sample/Response/response02.xml:
--------------------------------------------------------------------------------
1 | https://B1.bead.loc/adfs/services/trusthttps://B1.bead.loc/adfs/services/trustV8Ls9BSGOMwyyCmMtz2AFEGZdic=LHTt9aRHMBkgNukWiCEGTqrRavdHjz+i0duaUe6t1yVWVqRHsbdjQDHv4nxAPe18qMEO3j1PGoyjjFTZNR6v+yvuFu7zmARhxTjDuqzNGP5npiP5D8DACiTFyL1WFH8C7jZmJA5j9wRGDHq4xvMExQr2pTgQEHe1InmLvix8xjbPoevR7Wf1rG3nGIhfHcyQRpMqAeNQN2qI7hSQQ1k9rEGS7daz1j29YCeoWqvQ+hZNkhtY/HSCVeQzfXEG79AFZHpYQyXzWK+v8f48ntegIJx2hi9FV/HE4n4RBbNMdqbT9y71bw8EM/kEZoJehpgMgQYZP7ryGfdNMGWC9LfbjA==MIIC0jCCAbqgAwIBAgIQGFT6omLmWbhAD65bM40rGzANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDExpBREZTIFNpZ25pbmcgLSBCMS5iZWFkLmxvYzAeFw0xMzEwMDkxNDUyMDVaFw0xNDEwMDkxNDUyMDVaMCUxIzAhBgNVBAMTGkFERlMgU2lnbmluZyAtIEIxLmJlYWQubG9jMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlGKV64+63lpqdPmCTZ0kt/yKr8xukR1Y071SlmRVV5sSFhTe8cjylPqqxdyEBrfPhpL6vwFQyKfDhuM8T9E+BW5fUdoXO4WmIHrLOxV/BzKv2rDGidlCFzDSQPDxPH2RdQkMBksiauIMSHIYXB92rO4fkcsTgQ6cc+PZp4M3Z/jR1mcxQzz9RQk3I9w2OtI9xcv+uDC5mQU0ZWVHc99VSFQt+zshduwIqxQdHvMdTRslso+oCLEQom42pGCD8TksQTGw4sB7Ctb0mgXdfy0PDIznfi2oDBGtPY2Hkms6/n9xoyCynQea0YYXcpEe7lAvs+t6Lq+ZaKp2kUaa2x8d+QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfwlmaN1iPg0gNiqdVphJjWnzpV4h6/Mz3L0xYzNQeglWCDKCKuajQfmo/AQBErtOWZJsP8avzK79gNRqFHXF6CirjGnL6WO+S6Ug1hvy3xouOxOkIYgZsbmcNL2XO1hIxP4z/QWPthotp3FSUTae2hFBHuy4Gtb+9d9a60GDtgrHnfgVeCTE7CSiaI/D/51JNbtpg2tCpcEzMQgPkQqb8E+V79xc0dnEcI5cBaS6eYgkJgS5gKIMbwaJ/VxzCVGIKwFjFnJedJ5N7zH7OVwor56Q7nuKD7X4yFY9XR3isjGnwXveh9E4d9wD4CMl52AHJpsYsToXsi3eRvApDV/PEbos@bead.lochttps://mt.evo.team/simplesaml/module.php/saml/sp/metadata.php/b1bos@bead.locurn:federation:authentication:windows
--------------------------------------------------------------------------------
/resources/sample/Response/response03-formatted.xml:
--------------------------------------------------------------------------------
1 |
6 | https://B1.bead.loc/adfs/services/trust
7 |
8 |
9 |
10 |
12 | https://B1.bead.loc/adfs/services/trust
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | geMEaAJqRuNYPx3ccSqFwEIcGnk=
24 |
25 |
26 |
27 | Wt5E/asZPwmuPyk9He3h7jaGC5W5z4VVKRlBFhws+x821hUrjGjL0YsQo6ILQplwvrfJJvfZ/T+n2mAkxtm/VRt8Tj2MuvppRNdT6Ou+pZ76+uivXfZon/sayBQ9CxTd6ph/SMDG/oQ7/wOOupaPiZujFIZ5iVuIoQdwZxhoxlkh8D7ZDNwCH0iKHAtih6fazJ7Dtb6cK0+GyAam63sfNuPWK1gXon4Qe66rNxhgyxHMxGgyfp9tpHMGdYDbJ7cZqIAyBV0P5nmkFtPohBnpZ4EJHZfAw3AysvGiGZxaXrGasVyfONra/kbkYsN/1+FWhLByXrgTuZIEh28jUVReTg==
28 |
29 |
30 |
31 |
32 | MIIC0jCCAbqgAwIBAgIQGFT6omLmWbhAD65bM40rGzANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDExpBREZTIFNpZ25pbmcgLSBCMS5iZWFkLmxvYzAeFw0xMzEwMDkxNDUyMDVaFw0xNDEwMDkxNDUyMDVaMCUxIzAhBgNVBAMTGkFERlMgU2lnbmluZyAtIEIxLmJlYWQubG9jMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlGKV64+63lpqdPmCTZ0kt/yKr8xukR1Y071SlmRVV5sSFhTe8cjylPqqxdyEBrfPhpL6vwFQyKfDhuM8T9E+BW5fUdoXO4WmIHrLOxV/BzKv2rDGidlCFzDSQPDxPH2RdQkMBksiauIMSHIYXB92rO4fkcsTgQ6cc+PZp4M3Z/jR1mcxQzz9RQk3I9w2OtI9xcv+uDC5mQU0ZWVHc99VSFQt+zshduwIqxQdHvMdTRslso+oCLEQom42pGCD8TksQTGw4sB7Ctb0mgXdfy0PDIznfi2oDBGtPY2Hkms6/n9xoyCynQea0YYXcpEe7lAvs+t6Lq+ZaKp2kUaa2x8d+QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfwlmaN1iPg0gNiqdVphJjWnzpV4h6/Mz3L0xYzNQeglWCDKCKuajQfmo/AQBErtOWZJsP8avzK79gNRqFHXF6CirjGnL6WO+S6Ug1hvy3xouOxOkIYgZsbmcNL2XO1hIxP4z/QWPthotp3FSUTae2hFBHuy4Gtb+9d9a60GDtgrHnfgVeCTE7CSiaI/D/51JNbtpg2tCpcEzMQgPkQqb8E+V79xc0dnEcI5cBaS6eYgkJgS5gKIMbwaJ/VxzCVGIKwFjFnJedJ5N7zH7OVwor56Q7nuKD7X4yFY9XR3isjGnwXveh9E4d9wD4CMl52AHJpsYsToXsi3eRvApDV/PE
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 | https://bevo.evo.loc/saml
47 |
48 |
49 |
50 |
51 | bos@bead.loc
52 |
53 |
54 | bos@bos.com
55 |
56 |
57 | BosFirstName
58 |
59 |
60 | LastName
61 |
62 |
63 |
64 |
65 | urn:federation:authentication:windows
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/resources/sample/Response/response03.xml:
--------------------------------------------------------------------------------
1 | https://B1.bead.loc/adfs/services/trusthttps://B1.bead.loc/adfs/services/trustgeMEaAJqRuNYPx3ccSqFwEIcGnk=Wt5E/asZPwmuPyk9He3h7jaGC5W5z4VVKRlBFhws+x821hUrjGjL0YsQo6ILQplwvrfJJvfZ/T+n2mAkxtm/VRt8Tj2MuvppRNdT6Ou+pZ76+uivXfZon/sayBQ9CxTd6ph/SMDG/oQ7/wOOupaPiZujFIZ5iVuIoQdwZxhoxlkh8D7ZDNwCH0iKHAtih6fazJ7Dtb6cK0+GyAam63sfNuPWK1gXon4Qe66rNxhgyxHMxGgyfp9tpHMGdYDbJ7cZqIAyBV0P5nmkFtPohBnpZ4EJHZfAw3AysvGiGZxaXrGasVyfONra/kbkYsN/1+FWhLByXrgTuZIEh28jUVReTg==MIIC0jCCAbqgAwIBAgIQGFT6omLmWbhAD65bM40rGzANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDExpBREZTIFNpZ25pbmcgLSBCMS5iZWFkLmxvYzAeFw0xMzEwMDkxNDUyMDVaFw0xNDEwMDkxNDUyMDVaMCUxIzAhBgNVBAMTGkFERlMgU2lnbmluZyAtIEIxLmJlYWQubG9jMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlGKV64+63lpqdPmCTZ0kt/yKr8xukR1Y071SlmRVV5sSFhTe8cjylPqqxdyEBrfPhpL6vwFQyKfDhuM8T9E+BW5fUdoXO4WmIHrLOxV/BzKv2rDGidlCFzDSQPDxPH2RdQkMBksiauIMSHIYXB92rO4fkcsTgQ6cc+PZp4M3Z/jR1mcxQzz9RQk3I9w2OtI9xcv+uDC5mQU0ZWVHc99VSFQt+zshduwIqxQdHvMdTRslso+oCLEQom42pGCD8TksQTGw4sB7Ctb0mgXdfy0PDIznfi2oDBGtPY2Hkms6/n9xoyCynQea0YYXcpEe7lAvs+t6Lq+ZaKp2kUaa2x8d+QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfwlmaN1iPg0gNiqdVphJjWnzpV4h6/Mz3L0xYzNQeglWCDKCKuajQfmo/AQBErtOWZJsP8avzK79gNRqFHXF6CirjGnL6WO+S6Ug1hvy3xouOxOkIYgZsbmcNL2XO1hIxP4z/QWPthotp3FSUTae2hFBHuy4Gtb+9d9a60GDtgrHnfgVeCTE7CSiaI/D/51JNbtpg2tCpcEzMQgPkQqb8E+V79xc0dnEcI5cBaS6eYgkJgS5gKIMbwaJ/VxzCVGIKwFjFnJedJ5N7zH7OVwor56Q7nuKD7X4yFY9XR3isjGnwXveh9E4d9wD4CMl52AHJpsYsToXsi3eRvApDV/PEhttps://bevo.evo.loc/samlbos@bead.locbos@bos.comBosFirstNameLastNameurn:federation:authentication:windows
--------------------------------------------------------------------------------
/resources/sample/foo-formatted.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | BXhK3C4G4X4jcKMiyiiagHLqyEw=
14 |
15 |
16 |
17 | WveIJuhS9u1JoEoQXtJudRflIsAURDQBDiFMavyFk0jkomRsh2mhh0OZ8bycnBzxzmr0ddH37F0yHlKJ4fjIlNTMvbT9XF7a/UncNRu3kC9mnr0/dLF9tu4MNq3tcRb5NreMFWtD6Ikzfh11mQJten3FhPeZ3wAiz8fzOORAcnsH+oKugcDB4tmP425pPKmQ+J0WMMM9kiwW4Wew1+fNEw0axS0HrKNLvLqDixlELbwNrdTh1Qu7+5vu2PUKRRAFbif/EBzay7B1QaY+cyRj46Lb2phuHysBRh6K5hA2L+/KT6eUnypqwgAV9RPTsXSEHALXwHTsR6aKsa6Es2acIg==
18 |
19 |
20 |
21 |
22 | MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxMLbXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQswCQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNVBAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ceIXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQwQjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQwEgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1doug+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAqbz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6rBYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=
23 |
24 |
25 |
26 |
27 |
28 | something
29 |
30 |
31 |
--------------------------------------------------------------------------------
/resources/sample/foo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BXhK3C4G4X4jcKMiyiiagHLqyEw=WveIJuhS9u1JoEoQXtJudRflIsAURDQBDiFMavyFk0jkomRsh2mhh0OZ8bycnBzxzmr0ddH37F0yHlKJ4fjIlNTMvbT9XF7a/UncNRu3kC9mnr0/dLF9tu4MNq3tcRb5NreMFWtD6Ikzfh11mQJten3FhPeZ3wAiz8fzOORAcnsH+oKugcDB4tmP425pPKmQ+J0WMMM9kiwW4Wew1+fNEw0axS0HrKNLvLqDixlELbwNrdTh1Qu7+5vu2PUKRRAFbif/EBzay7B1QaY+cyRj46Lb2phuHysBRh6K5hA2L+/KT6eUnypqwgAV9RPTsXSEHALXwHTsR6aKsa6Es2acIg==
6 | MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxMLbXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQswCQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNVBAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ceIXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQwQjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQwEgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1doug+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAqbz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6rBYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=something
7 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/AbstractBinding.php:
--------------------------------------------------------------------------------
1 | destination = $destination;
25 | }
26 |
27 | /**
28 | * @return string
29 | */
30 | public function getDestination() {
31 | return $this->destination;
32 | }
33 |
34 |
35 | /**
36 | * @param $callable
37 | */
38 | public function addReceiveListener($callable)
39 | {
40 | $this->receiveListeners[] = $callable;
41 | }
42 |
43 | /**
44 | * @param $callable
45 | */
46 | public function addSendListener($callable)
47 | {
48 | $this->sendListeners[] = $callable;
49 | }
50 |
51 |
52 | /**
53 | * @param string $messageString
54 | */
55 | protected function dispatchReceive($messageString)
56 | {
57 | foreach ($this->receiveListeners as $callable) {
58 | call_user_func($callable, $messageString);
59 | }
60 | }
61 |
62 | /**
63 | * @param string $messageString
64 | */
65 | protected function dispatchSend($messageString)
66 | {
67 | foreach ($this->sendListeners as $callable) {
68 | call_user_func($callable, $messageString);
69 | }
70 | }
71 |
72 | /**
73 | * @param Message $message
74 | * @return Response
75 | */
76 | abstract function send(Message $message);
77 |
78 |
79 | /**
80 | * @param Request $request
81 | * @return Message
82 | */
83 | abstract function receive(Request $request);
84 |
85 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/BindingDetector.php:
--------------------------------------------------------------------------------
1 | getRequestMethod()));
41 | if ($requestMethod == 'GET') {
42 | return $this->processGET($request);
43 | } else if ($requestMethod == 'POST') {
44 | return $this->processPOST($request);
45 | }
46 | return null;
47 | }
48 |
49 |
50 | /**
51 | * @param Request $request
52 | * @return null|string
53 | */
54 | private function processGET(Request $request)
55 | {
56 | $get = $request->getGet();
57 | if (array_key_exists('SAMLRequest', $get) || array_key_exists('SAMLResponse', $get)) {
58 | return Bindings::SAML2_HTTP_REDIRECT;
59 | } elseif (array_key_exists('SAMLart', $get) ){
60 | return Bindings::SAML2_HTTP_ARTIFACT;
61 | }
62 | return null;
63 | }
64 |
65 |
66 | /**
67 | * @param Request $request
68 | * @return null|string
69 | */
70 | private function processPOST(Request $request)
71 | {
72 | $post = $request->getPost();
73 | if (array_key_exists('SAMLRequest', $post) || array_key_exists('SAMLResponse', $post)) {
74 | return Bindings::SAML2_HTTP_POST;
75 | } elseif (array_key_exists('SAMLart', $post) ){
76 | return Bindings::SAML2_HTTP_ARTIFACT;
77 | } else {
78 | if ($request->getContentType()) {
79 | $contentType = explode(';', $request->getContentType());
80 | $contentType = $contentType[0]; /* Remove charset. */
81 | if ($contentType === 'text/xml') {
82 | return Bindings::SAML2_SOAP;
83 | }
84 | }
85 | }
86 | return null;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/HttpPost.php:
--------------------------------------------------------------------------------
1 | getDestination() ?: $this->getDestination();
20 |
21 | $context = new SerializationContext();
22 | $message->getSignedXml($context->getDocument(), $context);
23 | $msgStr = $context->getDocument()->saveXML();
24 |
25 | $this->dispatchSend($msgStr);
26 |
27 | $msgStr = base64_encode($msgStr);
28 |
29 | $type = $message instanceof AbstractRequest ? 'SAMLRequest' : 'SAMLResponse';
30 |
31 | $data = array($type => $msgStr);
32 | if ($message->getRelayState()) {
33 | $data['RelayState'] = $message->getRelayState();
34 | }
35 |
36 | $result = new PostResponse($destination, $data);
37 | return $result;
38 | }
39 |
40 |
41 | /**
42 | * @param Request $request
43 | * @return Message
44 | * @throws \AerialShip\LightSaml\Error\BindingException
45 | */
46 | function receive(Request $request) {
47 | $post = $request->getPost();
48 | if (array_key_exists('SAMLRequest', $post)) {
49 | $msg = $post['SAMLRequest'];
50 | } elseif (array_key_exists('SAMLResponse', $post)) {
51 | $msg = $post['SAMLResponse'];
52 | } else {
53 | throw new BindingException('Missing SAMLRequest or SAMLResponse parameter');
54 | }
55 |
56 | $msg = base64_decode($msg);
57 |
58 | $this->dispatchReceive($msg);
59 |
60 | $doc = new \DOMDocument();
61 | $doc->loadXML($msg);
62 | $result = Message::fromXML($doc->firstChild);
63 |
64 | if (array_key_exists('RelayState', $post)) {
65 | $result->setRelayState($post['RelayState']);
66 | }
67 |
68 | return $result;
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/HttpPostTemplate.php:
--------------------------------------------------------------------------------
1 | destination = $destination;
17 | $this->data = $data;
18 | }
19 |
20 |
21 | function render() {
22 | ?>
23 |
25 |
26 |
27 |
28 | POST data
29 |
30 |
31 |
32 |
35 |
36 |
48 |
49 | data = $data;
20 | }
21 |
22 |
23 | /**
24 | * @param array $data
25 | */
26 | public function setData($data)
27 | {
28 | $this->data = $data;
29 | }
30 |
31 | /**
32 | * @return array
33 | */
34 | public function getData()
35 | {
36 | return $this->data;
37 | }
38 |
39 |
40 |
41 |
42 | /**
43 | * @return string
44 | */
45 | public function render()
46 | {
47 | $template = new HttpPostTemplate($this->getDestination(), $this->getData());
48 | ob_start();
49 | $template->render();
50 | $result = ob_get_clean();
51 | return $result;
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/RedirectResponse.php:
--------------------------------------------------------------------------------
1 | getDestination(), true, 302);
21 | header('Pragma: no-cache');
22 | header('Cache-Control: no-cache, must-revalidate');
23 | }
24 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/Request.php:
--------------------------------------------------------------------------------
1 | setContentType($_SERVER['CONTENT_TYPE']);
30 | $result->setGet($_GET);
31 | $result->setPost($_POST);
32 | $result->setQueryString($_SERVER['QUERY_STRING']);
33 | $result->setRequestMethod($_SERVER['REQUEST_METHOD']);
34 |
35 | return $result;
36 | }
37 |
38 | /**
39 | * @param string $contentType
40 | */
41 | public function setContentType($contentType)
42 | {
43 | $this->contentType = $contentType;
44 | }
45 |
46 | /**
47 | * @return string
48 | */
49 | public function getContentType()
50 | {
51 | return $this->contentType;
52 | }
53 |
54 | /**
55 | * @param array $get
56 | */
57 | public function setGet($get)
58 | {
59 | $this->get = $get;
60 | }
61 |
62 | /**
63 | * @return array
64 | */
65 | public function getGet()
66 | {
67 | return $this->get;
68 | }
69 |
70 | /**
71 | * @param array $post
72 | */
73 | public function setPost($post)
74 | {
75 | $this->post = $post;
76 | }
77 |
78 | /**
79 | * @return array
80 | */
81 | public function getPost()
82 | {
83 | return $this->post;
84 | }
85 |
86 | /**
87 | * @param string $queryString
88 | */
89 | public function setQueryString($queryString)
90 | {
91 | $this->queryString = $queryString;
92 | }
93 |
94 | /**
95 | * @return string
96 | */
97 | public function getQueryString()
98 | {
99 | return $this->queryString;
100 | }
101 |
102 | /**
103 | * @param string $requestMethod
104 | */
105 | public function setRequestMethod($requestMethod)
106 | {
107 | $this->requestMethod = $requestMethod;
108 | }
109 |
110 | /**
111 | * @return string
112 | */
113 | public function getRequestMethod()
114 | {
115 | return $this->requestMethod;
116 | }
117 |
118 |
119 |
120 |
121 |
122 | public function parseQueryString($queryString = null, $urlDecodeValues = false)
123 | {
124 | if ($queryString) {
125 | $this->queryString = $queryString;
126 | }
127 | $result = array();
128 | foreach (explode('&', $this->queryString) as $e) {
129 | $tmp = explode('=', $e, 2);
130 | $name = $tmp[0];
131 | $value = count($tmp) === 2 ? $value = $tmp[1] : '';
132 | $name = urldecode($name);
133 | $result[$name] = $urlDecodeValues ? urldecode($value) : $value;
134 | }
135 | return $result;
136 | }
137 |
138 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Binding/Response.php:
--------------------------------------------------------------------------------
1 | destination = $destination;
16 | }
17 |
18 |
19 |
20 | /**
21 | * @param string $destination
22 | */
23 | public function setDestination($destination)
24 | {
25 | $this->destination = $destination;
26 | }
27 |
28 | /**
29 | * @return string
30 | */
31 | public function getDestination()
32 | {
33 | return $this->destination;
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Bindings.php:
--------------------------------------------------------------------------------
1 | Protocol::SAML2,
24 | self::SAML2_HTTP_POST => Protocol::SAML2,
25 | self::SAML2_HTTP_POST_SIMPLE_SIGN => Protocol::SAML2,
26 | self::SAML2_HTTP_ARTIFACT => Protocol::SAML2,
27 | self::SAML1_BROWSER_POST => Protocol::SAML1,
28 | self::SAML1_ARTIFACT1 => Protocol::SAML1,
29 | self::SHIB1_AUTHN_REQUEST => Protocol::SHIB1
30 | );
31 |
32 |
33 | private static $_constants = null;
34 |
35 | private static function getConstants() {
36 | if (self::$_constants === null) {
37 | $ref = new \ReflectionClass('\AerialShip\LightSaml\Bindings');
38 | self::$_constants = $ref->getConstants();
39 | }
40 | return self::$_constants;
41 | }
42 |
43 | /**
44 | * @param string $binding
45 | * @return bool
46 | */
47 | static function isValid($binding) {
48 | $result = in_array($binding, self::getConstants());
49 | return $result;
50 | }
51 |
52 |
53 | static function validate($binding) {
54 | if (!self::isValid($binding)) {
55 | throw new InvalidBindingException($binding);
56 | }
57 | }
58 |
59 |
60 | /**
61 | * @param string $binding one of \AerialShip\LightSaml\Bindings
62 | * @return string one of \AerialShip\LightSaml\Protocol::* constants
63 | */
64 | static function getBindingProtocol($binding) {
65 | $result = @self::$_binding2protocol[$binding];
66 | return $result;
67 | }
68 |
69 |
70 | private function __construct() { }
71 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/ClaimTypes.php:
--------------------------------------------------------------------------------
1 | edSP = $edSP;
38 | $this->edIDP = $edIDP;
39 | $this->spMeta = $spMeta;
40 | $this->signature = $signature;
41 | }
42 |
43 |
44 | /**
45 | * @param Message $message
46 | * @return \AerialShip\LightSaml\Binding\Response
47 | */
48 | abstract public function send(Message $message);
49 |
50 |
51 | /**
52 | * @param EntityDescriptor $edIDP
53 | */
54 | public function setEdIDP($edIDP) {
55 | $this->edIDP = $edIDP;
56 | }
57 |
58 | /**
59 | * @return EntityDescriptor
60 | */
61 | public function getEdIDP() {
62 | return $this->edIDP;
63 | }
64 |
65 | /**
66 | * @param EntityDescriptor $edSP
67 | */
68 | public function setEdSP($edSP) {
69 | $this->edSP = $edSP;
70 | }
71 |
72 | /**
73 | * @return EntityDescriptor
74 | */
75 | public function getEdSP() {
76 | return $this->edSP;
77 | }
78 |
79 | /**
80 | * @param Signature $signature
81 | */
82 | public function setSigningProvider($signature)
83 | {
84 | $this->signature = $signature;
85 | }
86 |
87 | /**
88 | * @return Signature
89 | */
90 | public function getSigningProvider()
91 | {
92 | return $this->signature;
93 | }
94 |
95 |
96 | /**
97 | * @return SpSsoDescriptor
98 | * @throws BuildRequestException
99 | */
100 | protected function getSpSsoDescriptor()
101 | {
102 | $ed = $this->getEdSP();
103 | if (!$ed) {
104 | throw new BuildRequestException('No SP EntityDescriptor set');
105 | }
106 | $arr = $ed->getAllSpSsoDescriptors();
107 | if (empty($arr)) {
108 | throw new BuildRequestException('SP EntityDescriptor has no SPSSODescriptor');
109 | }
110 | if (count($arr)>1) {
111 | throw new BuildRequestException('SP EntityDescriptor has more then one SPSSODescriptor');
112 | }
113 | $result = $arr[0];
114 | return $result;
115 | }
116 |
117 |
118 | /**
119 | * @return IdpSsoDescriptor
120 | * @throws BuildRequestException
121 | */
122 | protected function getIdpSsoDescriptor()
123 | {
124 | $ed = $this->getEdIDP();
125 | if (!$ed) {
126 | throw new BuildRequestException('No IDP EntityDescriptor set');
127 | }
128 | $arr = $ed->getAllIdpSsoDescriptors();
129 | if (empty($arr)) {
130 | throw new BuildRequestException('IDP EntityDescriptor has no IDPSSODescriptor');
131 | }
132 | if (count($arr)>1) {
133 | throw new BuildRequestException('IDP EntityDescriptor has more then one IDPSSODescriptor');
134 | }
135 | $result = $arr[0];
136 | return $result;
137 | }
138 |
139 |
140 | /**
141 | * @param \AerialShip\LightSaml\Model\Metadata\Service\AbstractService[] $services
142 | * @param string|null $binding
143 | * @return \AerialShip\LightSaml\Model\Metadata\Service\AbstractService|null
144 | */
145 | protected function findServiceByBinding(array $services, $binding)
146 | {
147 | $result = null;
148 | if (!$binding) {
149 | $result = array_shift($services);
150 | } else {
151 | foreach ($services as $service) {
152 | if ($binding == $service->getBinding()) {
153 | $result = $service;
154 | break;
155 | }
156 | }
157 | }
158 |
159 | return $result;
160 | }
161 |
162 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Meta/AuthnRequestBuilder.php:
--------------------------------------------------------------------------------
1 | getEdSP();
23 |
24 | $result->setID(Helper::generateID());
25 | $result->setDestination($this->getDestination());
26 | $result->setIssueInstant(time());
27 |
28 | $asc = $this->getAssertionConsumerService();
29 | $result->setAssertionConsumerServiceURL($asc->getLocation());
30 | $result->setProtocolBinding($asc->getBinding());
31 |
32 | $result->setIssuer($edSP->getEntityID());
33 |
34 | if ($this->spMeta->getNameIdFormat()) {
35 | $result->setNameIdPolicyFormat($this->spMeta->getNameIdFormat());
36 | }
37 |
38 | $result->setSignature($this->signature);
39 |
40 | return $result;
41 | }
42 |
43 |
44 | /**
45 | * @param Message $message
46 | * @return \AerialShip\LightSaml\Binding\Response
47 | */
48 | public function send(Message $message)
49 | {
50 | $bindingType = $this->spMeta->getAuthnRequestBinding();
51 | if ($bindingType) {
52 | $detector = new BindingDetector();
53 | $binding = $detector->instantiate($bindingType);
54 | } else {
55 | $binding = new HttpRedirect();
56 | }
57 | $result = $binding->send($message);
58 | return $result;
59 | }
60 |
61 |
62 | /**
63 | * @return AssertionConsumerService
64 | * @throws BuildRequestException
65 | */
66 | protected function getAssertionConsumerService()
67 | {
68 | $sp = $this->getSpSsoDescriptor();
69 | $arr = $sp->findAssertionConsumerServices();
70 | if (empty($arr)) {
71 | throw new BuildRequestException('SPSSODescriptor does not have any AssertionConsumerService');
72 | }
73 | $result = $this->findServiceByBinding($arr, $this->spMeta->getResponseBinding());
74 | if (!$result) {
75 | throw new BuildRequestException('SPSSODescriptor does not have AssertionConsumerService with binding '.$this->spMeta->getResponseBinding());
76 | }
77 | return $result;
78 | }
79 |
80 | /**
81 | * @return string
82 | * @throws \AerialShip\LightSaml\Error\BuildRequestException
83 | */
84 | protected function getDestination()
85 | {
86 | $idp = $this->getIdpSsoDescriptor();
87 | $arr = $idp->findSingleSignOnServices();
88 | if (empty($arr)) {
89 | throw new BuildRequestException('IDPSSODescriptor does not have any SingleSignOnService');
90 | }
91 | $result = $this->findServiceByBinding($arr, $this->spMeta->getAuthnRequestBinding());
92 | if (!$result) {
93 | throw new BuildRequestException('IDPSSODescriptor does not have SingleSignOnService with binding '.$this->spMeta->getAuthnRequestBinding());
94 | }
95 |
96 | return $result->getLocation();
97 | }
98 |
99 |
100 | /**
101 | * @return string
102 | * @throws \AerialShip\LightSaml\Error\BuildRequestException
103 | */
104 | protected function getProtocolBinding()
105 | {
106 | $result = $this->spMeta->getAuthnRequestBinding();
107 | if (!$result) {
108 | $asc = $this->getAssertionConsumerService();
109 | if ($asc) {
110 | $result = $asc->getBinding();
111 | }
112 | }
113 | if (!$result) {
114 | throw new BuildRequestException('Unable to determine protocol binding');
115 | }
116 | return $result;
117 | }
118 |
119 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Meta/GetSignedXmlInterface.php:
--------------------------------------------------------------------------------
1 | getIdpSsoDescriptor();
19 | $result = null;
20 | if ($this->spMeta->getLogoutRequestBinding()) {
21 | $arr = $idp->findSingleLogoutServices($this->spMeta->getLogoutRequestBinding());
22 | if ($arr) {
23 | $sso = array_shift($arr);
24 | $result = $sso->getLocation();
25 | }
26 | }
27 | if (!$result) {
28 | $arr = $idp->findSingleLogoutServices();
29 | /** @var SingleLogoutService $sso */
30 | $sso = array_shift($arr);
31 | $result = $sso->getLocation();
32 | }
33 | if (!$result) {
34 | throw new \LogicException('Unable to find IDP destination');
35 | }
36 | return $result;
37 | }
38 |
39 |
40 | /**
41 | * @param string $nameIDValue
42 | * @param string|null $nameIDFormat
43 | * @param string|null $sessionIndex
44 | * @param string|null $reason
45 | * @return LogoutRequest
46 | */
47 | public function build($nameIDValue, $nameIDFormat = null, $sessionIndex = null, $reason = null)
48 | {
49 | $result = new LogoutRequest();
50 | $edSP = $this->getEdSP();
51 |
52 | $result->setID(Helper::generateID());
53 | $result->setDestination($this->getDestination());
54 | $result->setIssueInstant(time());
55 | if ($reason) {
56 | $result->setReason($reason);
57 | }
58 | if ($sessionIndex) {
59 | $result->setSessionIndex($sessionIndex);
60 | }
61 |
62 | $nameID = new NameID();
63 | $nameID->setValue($nameIDValue);
64 | if ($nameIDFormat) {
65 | $nameID->setFormat($nameIDFormat);
66 | }
67 | $result->setNameID($nameID);
68 |
69 | $result->setIssuer($edSP->getEntityID());
70 | return $result;
71 | }
72 |
73 |
74 | /**
75 | * @param Message $message
76 | * @return \AerialShip\LightSaml\Binding\RedirectResponse|\AerialShip\LightSaml\Binding\Response
77 | */
78 | public function send(Message $message)
79 | {
80 | $bindingType = $this->spMeta->getLogoutRequestBinding();
81 | if ($bindingType) {
82 | $detector = new BindingDetector();
83 | $binding = $detector->instantiate($bindingType);
84 | } else {
85 | $binding = new HttpRedirect();
86 | }
87 | $result = $binding->send($message);
88 | return $result;
89 | }
90 |
91 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Meta/SerializationContext.php:
--------------------------------------------------------------------------------
1 | document = $document ? $document : new \DOMDocument();
14 | }
15 |
16 |
17 | /**
18 | * @param \DOMDocument $document
19 | */
20 | public function setDocument($document) {
21 | $this->document = $document;
22 | }
23 |
24 | /**
25 | * @return \DOMDocument
26 | */
27 | public function getDocument() {
28 | return $this->document;
29 | }
30 |
31 |
32 |
33 |
34 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Meta/SpMeta.php:
--------------------------------------------------------------------------------
1 | nameIdFormat = $nameIdFormat;
33 | }
34 |
35 |
36 | /**
37 | * @return string
38 | */
39 | public function getNameIdFormat()
40 | {
41 | return $this->nameIdFormat;
42 | }
43 |
44 | /**
45 | * @param string $authnRequestBinding
46 | */
47 | public function setAuthnRequestBinding($authnRequestBinding)
48 | {
49 | $this->authnRequestBinding = $authnRequestBinding;
50 | }
51 |
52 | /**
53 | * @return string
54 | */
55 | public function getAuthnRequestBinding()
56 | {
57 | return $this->authnRequestBinding;
58 | }
59 |
60 | /**
61 | * @param string $responseBinding
62 | */
63 | public function setResponseBinding($responseBinding)
64 | {
65 | $this->responseBinding = $responseBinding;
66 | }
67 |
68 | /**
69 | * @return string
70 | */
71 | public function getResponseBinding()
72 | {
73 | return $this->responseBinding;
74 | }
75 |
76 | /**
77 | * @param string $logoutRequestBinding
78 | */
79 | public function setLogoutRequestBinding($logoutRequestBinding)
80 | {
81 | $this->logoutRequestBinding = $logoutRequestBinding;
82 | }
83 |
84 | /**
85 | * @return string
86 | */
87 | public function getLogoutRequestBinding()
88 | {
89 | return $this->logoutRequestBinding;
90 | }
91 |
92 |
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Meta/XmlChildrenLoaderTrait.php:
--------------------------------------------------------------------------------
1 | firstChild; $node !== NULL; $node = $node->nextSibling) {
10 | if ($node instanceof \DOMElement) {
11 | $elementCallback($node);
12 | }
13 | }
14 | }
15 |
16 | protected function loadXmlChildren(\DOMElement $xml, array $node2ClassMap, \Closure $itemCallback) {
17 | $result = array();
18 | $this->iterateChildrenElements($xml, function(\DOMElement $node) use (&$result, $node2ClassMap, $itemCallback) {
19 | $recognized = $this->doMapping($node, $node2ClassMap, $itemCallback);
20 | if (!$recognized) {
21 | $result[] = $node;
22 | }
23 | });
24 | return $result;
25 | }
26 |
27 |
28 | /**
29 | * @param \DOMElement $node
30 | * @param array $node2ClassMap
31 | * @param callable $itemCallback
32 | * @return \DOMElement|null
33 | */
34 | private function doMapping(\DOMElement $node, array $node2ClassMap, \Closure $itemCallback) {
35 | $recognized = false;
36 | foreach ($node2ClassMap as $meta) {
37 | if (!$meta) continue;
38 | $this->getNodeNameAndNamespaceFromMeta($meta, $nodeName, $nodeNS);
39 | if ($nodeName == $node->localName
40 | && (!$nodeNS || $nodeNS == $node->namespaceURI)
41 | ) {
42 | $obj = $this->getObjectFromMetaClass($meta, $node);
43 | $itemCallback($obj);
44 | $recognized = true;
45 | break;
46 | }
47 | } // foreach $node2ClassMap
48 | return $recognized;
49 | }
50 |
51 |
52 | private function getNodeNameAndNamespaceFromMeta($meta, &$nodeName, &$nodeNS) {
53 | if (!is_array($meta)) {
54 | throw new \InvalidArgumentException('Meta must be array');
55 | }
56 | if (!isset($meta['node'])) {
57 | throw new \InvalidArgumentException('Missing node meta');
58 | }
59 | $nodeName = null;
60 | $nodeNS = null;
61 | if (is_string($meta['node'])) {
62 | $nodeName = $meta['node'];
63 | } else if (is_array($meta['node'])) {
64 | $nodeName = @$meta['node']['name'];
65 | $nodeNS = @$meta['node']['ns'];
66 | }
67 | if (!$nodeName) {
68 | throw new \InvalidArgumentException('Missing node name meta');
69 | }
70 | }
71 |
72 | /**
73 | * @param $meta
74 | * @param \DOMElement $node
75 | * @throws \InvalidArgumentException
76 | * @return LoadFromXmlInterface
77 | */
78 | private function getObjectFromMetaClass($meta, \DOMElement $node) {
79 | $class = @$meta['class'];
80 | if (!$class) {
81 | throw new \InvalidArgumentException('Missing class meta');
82 | }
83 | $obj = new $class();
84 | if ($obj instanceof LoadFromXmlInterface) {
85 | $obj->loadFromXml($node);
86 | } else {
87 | throw new \InvalidArgumentException("Class $class must implement LoadFromXmlInterface");
88 | }
89 | return $obj;
90 | }
91 |
92 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Meta/XmlRequiredAttributesTrait.php:
--------------------------------------------------------------------------------
1 | hasAttribute($name)) {
13 | throw new InvalidXmlException('XML Element '.$element->localName.' missing required attribute '.$name);
14 | }
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Assertion/Attribute.php:
--------------------------------------------------------------------------------
1 | name = $name;
35 | $this->values = $values;
36 | $this->friendlyName = $friendlyName;
37 | }
38 |
39 |
40 | /**
41 | * @param string $name
42 | */
43 | public function setName($name)
44 | {
45 | $this->name = $name;
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | public function getName()
52 | {
53 | return $this->name;
54 | }
55 |
56 | /**
57 | * @param null|string $nameFormat
58 | * @return $this|Attribute
59 | */
60 | public function setNameFormat($nameFormat)
61 | {
62 | $this->nameFormat = $nameFormat;
63 |
64 | return $this;
65 | }
66 |
67 | /**
68 | * @return null|string
69 | */
70 | public function getNameFormat()
71 | {
72 | return $this->nameFormat;
73 | }
74 |
75 | /**
76 | * @param string $friendlyName
77 | */
78 | public function setFriendlyName($friendlyName)
79 | {
80 | $this->friendlyName = $friendlyName;
81 | }
82 |
83 | /**
84 | * @return string
85 | */
86 | public function getFriendlyName()
87 | {
88 | return $this->friendlyName;
89 | }
90 |
91 | /**
92 | * @param string[] $values
93 | */
94 | public function setValues(array $values)
95 | {
96 | $this->values = $values;
97 | }
98 |
99 | /**
100 | * @return string[]
101 | */
102 | public function getValues()
103 | {
104 | return $this->values;
105 | }
106 |
107 |
108 | /**
109 | * @param string $value
110 | */
111 | public function addValue($value)
112 | {
113 | $this->values[] = $value;
114 | }
115 |
116 |
117 | public function getFirstValue()
118 | {
119 | return $this->values[0];
120 | }
121 |
122 |
123 | /**
124 | * @param \DOMNode $parent
125 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
126 | * @return \DOMElement
127 | */
128 | public function getXml(\DOMNode $parent, SerializationContext $context)
129 | {
130 | $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:Attribute');
131 | $parent->appendChild($result);
132 |
133 | $result->setAttribute('Name', $this->getName());
134 | if ($this->getNameFormat()) {
135 | $result->setAttribute('NameFormat', $this->getNameFormat());
136 | }
137 | if ($this->getFriendlyName()) {
138 | $result->setAttribute('FriendlyName', $this->getFriendlyName());
139 | }
140 |
141 | foreach ($this->getValues() as $v) {
142 | $valueNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AttributeValue', $v);
143 | $result->appendChild($valueNode);
144 | }
145 |
146 | return $result;
147 | }
148 |
149 | /**
150 | * @param \DOMElement $xml
151 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
152 | */
153 | public function loadFromXml(\DOMElement $xml)
154 | {
155 | if ($xml->localName != 'Attribute' || $xml->namespaceURI != Protocol::NS_ASSERTION) {
156 | throw new InvalidXmlException('Expected Attribute element but got '.$xml->localName);
157 | }
158 |
159 | if (!$xml->hasAttribute('Name')) {
160 | throw new InvalidXmlException('Missing Attribute Name');
161 | }
162 | $this->setName($xml->getAttribute('Name'));
163 |
164 | if ($xml->hasAttribute('NameFormat')) {
165 | $this->setNameFormat($xml->getAttribute('NameFormat'));
166 | }
167 | if ($xml->hasAttribute('FriendlyName')) {
168 | $this->setFriendlyName($xml->getAttribute('FriendlyName'));
169 | }
170 |
171 | for ($node = $xml->firstChild; $node !== NULL; $node = $node->nextSibling) {
172 | if ($node->localName != 'AttributeValue') {
173 | throw new InvalidXmlException('Expected AttributeValue but got '.$node->localName);
174 | }
175 | $this->addValue($node->textContent);
176 | }
177 | }
178 |
179 |
180 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Assertion/AuthnStatement.php:
--------------------------------------------------------------------------------
1 | authnContext = trim($authnContext);
36 | }
37 |
38 | /**
39 | * @return string
40 | */
41 | public function getAuthnContext() {
42 | return $this->authnContext;
43 | }
44 |
45 | /**
46 | * @param int|string $authnInstant
47 | * @throws \InvalidArgumentException
48 | */
49 | public function setAuthnInstant($authnInstant) {
50 | if (is_string($authnInstant)) {
51 | $authnInstant = Helper::parseSAMLTime($authnInstant);
52 | } else if (!is_int($authnInstant) || $authnInstant < 1) {
53 | throw new \InvalidArgumentException('Invalid AuthnInstant');
54 | }
55 | $this->authnInstant = $authnInstant;
56 | }
57 |
58 | /**
59 | * @return int
60 | */
61 | public function getAuthnInstant() {
62 | return $this->authnInstant;
63 | }
64 |
65 | /**
66 | * @param string $sessionIndex
67 | */
68 | public function setSessionIndex($sessionIndex) {
69 | $this->sessionIndex = $sessionIndex;
70 | }
71 |
72 | /**
73 | * @return string
74 | */
75 | public function getSessionIndex() {
76 | return $this->sessionIndex;
77 | }
78 |
79 |
80 |
81 | protected function prepareForXml() {
82 | if (!$this->getAuthnInstant()) {
83 | $this->setAuthnInstant(time());
84 | }
85 | }
86 |
87 |
88 | /**
89 | * @param \DOMNode $parent
90 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
91 | * @return \DOMElement
92 | */
93 | function getXml(\DOMNode $parent, SerializationContext $context) {
94 | $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AuthnStatement');
95 | $parent->appendChild($result);
96 |
97 | $result->setAttribute('AuthnInstant', Helper::time2string($this->getAuthnInstant()));
98 | if ($this->getSessionIndex()) {
99 | $result->setAttribute('SessionIndex', $this->getSessionIndex());
100 | }
101 |
102 | $authnContextNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AuthnContext');
103 | $result->appendChild($authnContextNode);
104 | $refNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AuthnContextClassRef', $this->getAuthnContext());
105 | $authnContextNode->appendChild($refNode);
106 |
107 | return $result;
108 | }
109 |
110 | /**
111 | * @param \DOMElement $xml
112 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
113 | */
114 | function loadFromXml(\DOMElement $xml) {
115 | if ($xml->localName != 'AuthnStatement' || $xml->namespaceURI != Protocol::NS_ASSERTION) {
116 | throw new InvalidXmlException('Expected AuthnStatement element but got '.$xml->localName);
117 | }
118 |
119 | $this->checkRequiredAttributes($xml, array('AuthnInstant'));
120 | $this->setAuthnInstant($xml->getAttribute('AuthnInstant'));
121 |
122 | if ($xml->hasAttribute('SessionIndex')) {
123 | $this->setSessionIndex($xml->getAttribute('SessionIndex'));
124 | }
125 |
126 | $xpath = new \DOMXPath($xml->ownerDocument);
127 | $xpath->registerNamespace('saml', Protocol::NS_ASSERTION);
128 | $xpath->registerNamespace('samlp', Protocol::SAML2);
129 |
130 | $list = $xpath->query('./saml:AuthnContext/saml:AuthnContextClassRef', $xml);
131 | if ($list->length) {
132 | $this->setAuthnContext($list->item(0)->textContent);
133 | }
134 | }
135 |
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Assertion/NameID.php:
--------------------------------------------------------------------------------
1 | value = $value;
38 | $this->format = $format;
39 | }
40 |
41 |
42 | /**
43 | * @param string $value
44 | */
45 | public function setValue($value) {
46 | $this->value = trim($value);
47 | }
48 |
49 | /**
50 | * @return string
51 | */
52 | public function getValue() {
53 | return $this->value;
54 | }
55 |
56 | /**
57 | * @param string $nameQualifier
58 | * @return $this
59 | */
60 | public function setNameQualifier($nameQualifier){
61 | $this->nameQualifier = $nameQualifier;
62 | return $this;
63 | }
64 |
65 | /**
66 | * @return string
67 | */
68 | public function getNameQualifier(){
69 | return $this->nameQualifier;
70 | }
71 |
72 | /**
73 | * @param string $sPNameQualifier
74 | * @return $this
75 | */
76 | public function setSPNameQualifier($sPNameQualifier){
77 | $this->spNameQualifier = $sPNameQualifier;
78 | return $this;
79 | }
80 |
81 | /**
82 | * @return string
83 | */
84 | public function getSPNameQualifier(){
85 | return $this->spNameQualifier;
86 | }
87 |
88 | /**
89 | * @param string $format
90 | * @return $this
91 | */
92 | public function setFormat($format){
93 | $this->format = trim($format);
94 | return $this;
95 | }
96 |
97 | /**
98 | * @return string
99 | */
100 | public function getFormat(){
101 | return $this->format;
102 | }
103 |
104 | /**
105 | * @param string $sPProvidedID
106 | * @return $this
107 | */
108 | public function setSPProvidedID($sPProvidedID){
109 | $this->spProvidedID = $sPProvidedID;
110 | return $this;
111 | }
112 |
113 | /**
114 | * @return string
115 | */
116 | public function getSPProvidedID(){
117 | return $this->spProvidedID;
118 | }
119 |
120 |
121 |
122 |
123 | /**
124 | * @param \DOMNode $parent
125 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
126 | * @return \DOMElement
127 | */
128 | public function getXml(\DOMNode $parent, SerializationContext $context)
129 | {
130 | $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:NameID', $this->getValue());
131 |
132 | $parent->appendChild($result);
133 |
134 | if($this->getSPNameQualifier()) {
135 | $result->setAttribute('SPNameQualifier', $this->getSPNameQualifier());
136 | }
137 | if($this->getNameQualifier()) {
138 | $result->setAttribute('NameQualifier', $this->getNameQualifier());
139 | }
140 | if($this->getSPProvidedID()) {
141 | $result->setAttribute('SPProvidedID', $this->getSPProvidedID());
142 | }
143 | if($this->getFormat()) {
144 | $result->setAttribute('Format', $this->getFormat());
145 | }
146 |
147 | return $result;
148 | }
149 |
150 |
151 | /**
152 | * @param \DOMElement $xml
153 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
154 | */
155 | function loadFromXml(\DOMElement $xml) {
156 | if ($xml->localName != 'NameID') {
157 | throw new InvalidXmlException('Expected NameID element got '.$xml->localName);
158 | }
159 |
160 | if ($xml->hasAttribute('SPNameQualifier')) {
161 | $this->setSPNameQualifier($xml->getAttribute('SPNameQualifier'));
162 | }
163 | if ($xml->hasAttribute('NameQualifier')) {
164 | $this->setNameQualifier($xml->getAttribute('NameQualifier'));
165 | }
166 | if ($xml->hasAttribute('SPProvidedID')) {
167 | $this->setSPProvidedID($xml->getAttribute('SPProvidedID'));
168 | }
169 | if ($xml->hasAttribute('Format')) {
170 | $this->setFormat($xml->getAttribute('Format'));
171 | }
172 | $this->setValue(trim($xml->textContent));
173 | }
174 |
175 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Assertion/Subject.php:
--------------------------------------------------------------------------------
1 | nameID = $nameID;
34 | }
35 |
36 | /**
37 | * @return NameID
38 | */
39 | public function getNameID()
40 | {
41 | return $this->nameID;
42 | }
43 |
44 | /**
45 | * @param SubjectConfirmation $subjectConfirmation
46 | */
47 | public function addSubjectConfirmation($subjectConfirmation)
48 | {
49 | $this->subjectConfirmations[] = $subjectConfirmation;
50 | }
51 |
52 | /**
53 | * @return SubjectConfirmation[]
54 | */
55 | public function getSubjectConfirmations()
56 | {
57 | return $this->subjectConfirmations;
58 | }
59 |
60 |
61 |
62 |
63 |
64 | /**
65 | * @param \DOMNode $parent
66 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
67 | * @return \DOMElement
68 | */
69 | public function getXml(\DOMNode $parent, SerializationContext $context)
70 | {
71 | $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:Subject');
72 | $parent->appendChild($result);
73 |
74 | if ($this->getNameID()) {
75 | $this->getNameID()->getXml($result, $context);
76 | }
77 |
78 | foreach ($this->getSubjectConfirmations() as $sc) {
79 | $sc->getXml($result, $context);
80 | }
81 |
82 | return $result;
83 | }
84 |
85 | /**
86 | * @param \DOMElement $xml
87 | * @throws \LogicException
88 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
89 | */
90 | public function loadFromXml(\DOMElement $xml)
91 | {
92 | if ($xml->localName != 'Subject' || $xml->namespaceURI != Protocol::NS_ASSERTION) {
93 | throw new InvalidXmlException('Expected Subject element but got '.$xml->localName);
94 | }
95 |
96 | $this->nameID = null;
97 | $this->subjectConfirmations = array();
98 |
99 | $this->loadXmlChildren(
100 | $xml,
101 | array(
102 | array(
103 | 'node' => array('name'=>'NameID', 'ns'=>Protocol::NS_ASSERTION),
104 | 'class' => '\AerialShip\LightSaml\Model\Assertion\NameID'
105 | ),
106 | array(
107 | 'node' => array('name'=>'SubjectConfirmation', 'ns'=>Protocol::NS_ASSERTION),
108 | 'class' => '\AerialShip\LightSaml\Model\Assertion\SubjectConfirmation'
109 | )
110 | ),
111 | function ($object) {
112 | $this->loadXmlCallback($object);
113 | }
114 | );
115 | if (!$this->getSubjectConfirmations()) {
116 | throw new InvalidXmlException('Missing SubjectConfirmation element in Subject');
117 | }
118 | }
119 |
120 |
121 | protected function loadXmlCallback($object)
122 | {
123 | if ($object instanceof NameID) {
124 | if ($this->getNameID()) {
125 | throw new InvalidXmlException('More than one NameID in Subject');
126 | }
127 | $this->setNameID($object);
128 | } else if ($object instanceof SubjectConfirmation) {
129 | $this->addSubjectConfirmation($object);
130 | } else {
131 | throw new \LogicException('Unexpected type '.get_class($object));
132 | }
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Assertion/SubjectConfirmation.php:
--------------------------------------------------------------------------------
1 | method = $method;
35 | }
36 |
37 | /**
38 | * @return string
39 | */
40 | public function getMethod() {
41 | return $this->method;
42 | }
43 |
44 | /**
45 | * @param NameID $nameID
46 | */
47 | public function setNameID($nameID) {
48 | $this->nameID = $nameID;
49 | }
50 |
51 | /**
52 | * @return NameID
53 | */
54 | public function getNameID() {
55 | return $this->nameID;
56 | }
57 |
58 | /**
59 | * @param SubjectConfirmationData $data
60 | */
61 | public function setData($data) {
62 | $this->data = $data;
63 | }
64 |
65 | /**
66 | * @return SubjectConfirmationData
67 | */
68 | public function getData() {
69 | return $this->data;
70 | }
71 |
72 |
73 |
74 |
75 |
76 |
77 | protected function prepareForXml() {
78 | if (!$this->getMethod()) {
79 | throw new InvalidSubjectException('No SubjectConfirmation Method set');
80 | }
81 | if (!$this->getData()) {
82 | throw new InvalidSubjectException('No SubjectConfirmationData set');
83 | }
84 | }
85 |
86 |
87 | /**
88 | * @param \DOMNode $parent
89 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
90 | * @return \DOMElement
91 | */
92 | function getXml(\DOMNode $parent, SerializationContext $context) {
93 | $this->prepareForXml();
94 |
95 | $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:SubjectConfirmation');
96 | $parent->appendChild($result);
97 |
98 | $result->setAttribute('Method', $this->getMethod());
99 |
100 | if ($this->getNameID()) {
101 | $this->getNameID()->getXml($result, $context);
102 | }
103 |
104 | $this->getData()->getXml($result, $context);
105 |
106 | return $result;
107 | }
108 |
109 | /**
110 | * @param \DOMElement $xml
111 | * @throws \LogicException
112 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
113 | */
114 | function loadFromXml(\DOMElement $xml) {
115 | if ($xml->localName != 'SubjectConfirmation' || $xml->namespaceURI != Protocol::NS_ASSERTION) {
116 | throw new InvalidXmlException('Expected Subject element but got '.$xml->localName);
117 | }
118 |
119 | if (!$xml->hasAttribute('Method')) {
120 | throw new InvalidXmlException('Missing Method attribute in SubjectConfirmation');
121 | }
122 | $this->setMethod($xml->getAttribute('Method'));
123 |
124 |
125 | $this->nameID = null;
126 | $this->loadXmlChildren(
127 | $xml,
128 | array(
129 | array(
130 | 'node' => array('name'=>'NameID', 'ns'=>Protocol::NS_ASSERTION),
131 | 'class' => '\AerialShip\LightSaml\Model\Assertion\NameID'
132 | ),
133 | array(
134 | 'node' => array('name'=>'SubjectConfirmationData', 'ns'=>Protocol::NS_ASSERTION),
135 | 'class' => '\AerialShip\LightSaml\Model\Assertion\SubjectConfirmationData'
136 | )
137 | ),
138 | function ($obj) {
139 | if ($obj instanceof NameID) {
140 | if ($this->getNameID()) {
141 | throw new InvalidXmlException('More than one NameID in SubjectConfirmation');
142 | }
143 | $this->setNameID($obj);
144 | } else if ($obj instanceof SubjectConfirmationData) {
145 | $this->setData($obj);
146 | } else {
147 | throw new \LogicException('Unexpected type '.get_class($obj));
148 | }
149 | }
150 | );
151 | }
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Assertion/SubjectConfirmationData.php:
--------------------------------------------------------------------------------
1 | address = $address;
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function getAddress() {
45 | return $this->address;
46 | }
47 |
48 | /**
49 | * @param string $inResponseTo
50 | */
51 | public function setInResponseTo($inResponseTo) {
52 | $this->inResponseTo = $inResponseTo;
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getInResponseTo() {
59 | return $this->inResponseTo;
60 | }
61 |
62 | /**
63 | * @param int|string $notBefore
64 | * @throws \InvalidArgumentException
65 | */
66 | public function setNotBefore($notBefore) {
67 | if (is_string($notBefore)) {
68 | $notBefore = Helper::parseSAMLTime($notBefore);
69 | }
70 | if (!is_int($notBefore) || $notBefore < 1) {
71 | throw new \InvalidArgumentException();
72 | }
73 | $this->notBefore = $notBefore;
74 | }
75 |
76 | /**
77 | * @return int
78 | */
79 | public function getNotBefore() {
80 | return $this->notBefore;
81 | }
82 |
83 | /**
84 | * @param int|string $notOnOrAfter
85 | * @throws \InvalidArgumentException
86 | */
87 | public function setNotOnOrAfter($notOnOrAfter) {
88 | if (is_string($notOnOrAfter)) {
89 | $notOnOrAfter = Helper::parseSAMLTime($notOnOrAfter);
90 | }
91 | if (!is_int($notOnOrAfter) || $notOnOrAfter < 1) {
92 | throw new \InvalidArgumentException();
93 | }
94 | $this->notOnOrAfter = $notOnOrAfter;
95 | }
96 |
97 | /**
98 | * @return int
99 | */
100 | public function getNotOnOrAfter() {
101 | return $this->notOnOrAfter;
102 | }
103 |
104 | /**
105 | * @param string $recipient
106 | */
107 | public function setRecipient($recipient) {
108 | $this->recipient = $recipient;
109 | }
110 |
111 | /**
112 | * @return string
113 | */
114 | public function getRecipient() {
115 | return $this->recipient;
116 | }
117 |
118 |
119 | /**
120 | * @param \DOMNode $parent
121 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
122 | * @return \DOMElement
123 | */
124 | function getXml(\DOMNode $parent, SerializationContext $context) {
125 | $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:SubjectConfirmationData');
126 | $parent->appendChild($result);
127 |
128 | if ($this->getNotBefore()) {
129 | $result->setAttribute('NotBefore', Helper::time2string($this->getNotBefore()));
130 | }
131 | if ($this->getNotOnOrAfter()) {
132 | $result->setAttribute('NotOnOrAfter', Helper::time2string($this->getNotOnOrAfter()));
133 | }
134 |
135 | foreach (array('Recipient', 'InResponseTo', 'Address') as $name) {
136 | $method = "get{$name}";
137 | if ($this->$method()) {
138 | $result->setAttribute($name, $this->$method());
139 | }
140 | }
141 |
142 | return $result;
143 | }
144 |
145 | /**
146 | * @param \DOMElement $xml
147 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
148 | */
149 | function loadFromXml(\DOMElement $xml) {
150 | if ($xml->localName != 'SubjectConfirmationData' || $xml->namespaceURI != Protocol::NS_ASSERTION) {
151 | throw new InvalidXmlException('Expected SubjectConfirmationData element but got '.$xml->localName);
152 | }
153 |
154 | foreach (array('NotBefore', 'NotOnOrAfter', 'Recipient', 'InResponseTo', 'Address') as $name) {
155 | if ($xml->hasAttribute($name)) {
156 | $method = "set{$name}";
157 | $this->$method($xml->getAttribute($name));
158 | }
159 | }
160 | }
161 |
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Metadata/IdpSsoDescriptor.php:
--------------------------------------------------------------------------------
1 | attributes = $attributes;
26 | return $this;
27 | }
28 |
29 | /**
30 | * @return \AerialShip\LightSaml\Model\Assertion\Attribute[]
31 | */
32 | public function getAttributes()
33 | {
34 | return $this->attributes;
35 | }
36 |
37 | /**
38 | * @param Attribute $attribute
39 | */
40 | public function addAttribute(Attribute $attribute)
41 | {
42 | $this->attributes[] = $attribute;
43 | }
44 |
45 |
46 | /**
47 | * @param AbstractService $service
48 | * @return SpSsoDescriptor
49 | * @throws \InvalidArgumentException
50 | */
51 | public function addService(AbstractService $service)
52 | {
53 | $class = Helper::getClassNameOnly($service);
54 | if ($class != 'SingleLogoutService' &&
55 | $class != 'SingleSignOnService'
56 | ) {
57 | throw new \InvalidArgumentException("Invalid service type $class for IDPSSODescriptor");
58 | }
59 | return parent::addService($service);
60 | }
61 |
62 |
63 | /**
64 | * @return string
65 | */
66 | public function getXmlNodeName()
67 | {
68 | return 'IDPSSODescriptor';
69 | }
70 |
71 |
72 | /**
73 | * @param \DOMNode $parent
74 | * @param SerializationContext $context
75 | * @return \DOMElement
76 | */
77 | public function getXml(\DOMNode $parent, SerializationContext $context)
78 | {
79 | $result = parent::getXml($parent, $context);
80 |
81 | if ($this->getAttributes()) {
82 | foreach ($this->getAttributes() as $attribute) {
83 | $attribute->getXml($result, $context);
84 | }
85 | }
86 |
87 | return $result;
88 | }
89 |
90 |
91 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Metadata/KeyDescriptor.php:
--------------------------------------------------------------------------------
1 | use = $use;
33 | $this->certificate = $certificate;
34 | }
35 |
36 |
37 | /**
38 | * @param string $use
39 | * @throws \InvalidArgumentException
40 | */
41 | public function setUse($use) {
42 | $use = trim($use);
43 | if ($use != '' && $use != self::USE_ENCRYPTION && $use != self::USE_SIGNING) {
44 | throw new \InvalidArgumentException("Invalid use value: $use");
45 | }
46 | $this->use = $use;
47 | }
48 |
49 | /**
50 | * @return string
51 | */
52 | public function getUse() {
53 | return $this->use;
54 | }
55 |
56 |
57 | /**
58 | * @param X509Certificate $certificate
59 | */
60 | public function setCertificate(X509Certificate $certificate) {
61 | $this->certificate = $certificate;
62 | }
63 |
64 | /**
65 | * @return X509Certificate
66 | */
67 | public function getCertificate() {
68 | return $this->certificate;
69 | }
70 |
71 |
72 | /**
73 | * @param \DOMNode $parent
74 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
75 | * @return \DOMNode
76 | */
77 | function getXml(\DOMNode $parent, SerializationContext $context)
78 | {
79 | $result = $context->getDocument()->createElementNS(Protocol::NS_METADATA, 'md:KeyDescriptor');
80 | $parent->appendChild($result);
81 | if ($this->getUse()) {
82 | $result->setAttribute('use', $this->getUse());
83 | }
84 | $keyInfo = $parent->ownerDocument->createElementNS(Protocol::NS_XMLDSIG, 'ds:KeyInfo');
85 | $result->appendChild($keyInfo);
86 | $xData = $parent->ownerDocument->createElementNS(Protocol::NS_XMLDSIG, 'ds:X509Data');
87 | $keyInfo->appendChild($xData);
88 | $xCert = $parent->ownerDocument->createElementNS(Protocol::NS_XMLDSIG, 'ds:X509Certificate');
89 | $xData->appendChild($xCert);
90 | $xCert->nodeValue = $this->getCertificate()->getData();
91 | return $result;
92 | }
93 |
94 | /**
95 | * @param \DOMElement $xml
96 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
97 | */
98 | public function loadFromXml(\DOMElement $xml)
99 | {
100 | if ($xml->localName != 'KeyDescriptor' || $xml->namespaceURI != Protocol::NS_METADATA) {
101 | throw new InvalidXmlException('Expected KeyDescriptor element and '.Protocol::NS_METADATA.' namespace but got '.$xml->localName);
102 | }
103 |
104 | $this->setUse($xml->getAttribute('use'));
105 |
106 | $xpath = new \DOMXPath($xml instanceof \DOMDocument ? $xml : $xml->ownerDocument);
107 | $xpath->registerNamespace('ds', \XMLSecurityDSig::XMLDSIGNS);
108 |
109 | $list = $xpath->query('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', $xml);
110 | if ($list->length != 1) {
111 | throw new InvalidXmlException("Missing X509Certificate node");
112 | }
113 |
114 | /** @var $x509CertificateNode \DOMElement */
115 | $x509CertificateNode = $list->item(0);
116 | $certificateData = trim($x509CertificateNode->nodeValue);
117 | if (!$certificateData) {
118 | throw new InvalidXmlException("Missing certificate data");
119 | }
120 |
121 | $this->certificate = new X509Certificate();
122 | $this->certificate->setData($certificateData);
123 | }
124 |
125 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Metadata/NameIDFormat.php:
--------------------------------------------------------------------------------
1 | value = $value;
24 | }
25 |
26 | /**
27 | * @param string $value
28 | * @throws \InvalidArgumentException
29 | * @return $this|NameIDFormat
30 | */
31 | public function setValue($value)
32 | {
33 | $value = trim($value);
34 | if ($value && false == NameIDPolicy::isValid($value)) {
35 | throw new \InvalidArgumentException(sprintf("Invalid NameIDFormat '%s'", $value));
36 | }
37 | $this->value = $value;
38 |
39 | return $this;
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function getValue()
46 | {
47 | return $this->value;
48 | }
49 |
50 |
51 |
52 | /**
53 | * @param \DOMNode $parent
54 | * @param SerializationContext $context
55 | * @return \DOMElement
56 | */
57 | public function getXml(\DOMNode $parent, SerializationContext $context)
58 | {
59 | $result = $context->getDocument()->createElementNS(Protocol::NS_METADATA, 'md:NameIDFormat');
60 | $parent->appendChild($result);
61 |
62 | $result->nodeValue = $this->value;
63 |
64 | return $result;
65 | }
66 |
67 | /**
68 | * @param \DOMElement $xml
69 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
70 | * @return void
71 | */
72 | public function loadFromXml(\DOMElement $xml)
73 | {
74 | if ($xml->localName != 'NameIDFormat' || $xml->namespaceURI != Protocol::NS_METADATA) {
75 | throw new InvalidXmlException('Expected NameIDFormat element and '.Protocol::NS_METADATA.' namespace but got '.$xml->localName);
76 | }
77 |
78 | $this->setValue($xml->nodeValue);
79 | }
80 |
81 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Metadata/Service/AbstractService.php:
--------------------------------------------------------------------------------
1 | setBinding($binding);
27 | }
28 | if ($location !== null) {
29 | $this->setLocation($location);
30 | }
31 | }
32 |
33 |
34 |
35 | /**
36 | * @param string $binding
37 | */
38 | public function setBinding($binding) {
39 | Bindings::validate($binding);
40 | $this->binding = $binding;
41 | }
42 |
43 | /**
44 | * @return string
45 | */
46 | public function getBinding() {
47 | return $this->binding;
48 | }
49 |
50 | /**
51 | * @param string $location
52 | */
53 | public function setLocation($location) {
54 | $this->location = $location;
55 | }
56 |
57 | /**
58 | * @return string
59 | */
60 | public function getLocation() {
61 | return $this->location;
62 | }
63 |
64 |
65 |
66 | abstract protected function getXmlNodeName();
67 |
68 |
69 | /**
70 | * @param \DOMNode $parent
71 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
72 | * @return \DOMElement
73 | */
74 | function getXml(\DOMNode $parent, SerializationContext $context) {
75 | $result = $context->getDocument()->createElementNS(Protocol::NS_METADATA, 'md:'.$this->getXmlNodeName());
76 | $parent->appendChild($result);
77 | $result->setAttribute('Binding', $this->getBinding());
78 | $result->setAttribute('Location', $this->getLocation());
79 | return $result;
80 | }
81 |
82 |
83 | /**
84 | * @param \DOMElement $xml
85 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
86 | */
87 | function loadFromXml(\DOMElement $xml) {
88 | $name = $this->getXmlNodeName();
89 | if ($xml->localName != $name || $xml->namespaceURI != Protocol::NS_METADATA) {
90 | throw new InvalidXmlException("Expected $name element and ".Protocol::NS_METADATA.' namespace but got '.$xml->localName);
91 | }
92 | if (!$xml->hasAttribute('Binding')) {
93 | throw new InvalidXmlException("Missing Binding attribute");
94 | }
95 | if (!$xml->hasAttribute('Location')) {
96 | throw new InvalidXmlException("Missing Location attribute");
97 | }
98 | $this->setBinding($xml->getAttribute('Binding'));
99 | $this->setLocation($xml->getAttribute('Location'));
100 | }
101 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Metadata/Service/AssertionConsumerService.php:
--------------------------------------------------------------------------------
1 | setIndex($index);
19 | }
20 | }
21 |
22 |
23 | /**
24 | * @param int $index
25 | * @throws \InvalidArgumentException
26 | */
27 | public function setIndex($index) {
28 | $v = intval($index);
29 | if ($v != $index) {
30 | throw new \InvalidArgumentException("Expected int got $index");
31 | }
32 | $this->index = $index;
33 | }
34 |
35 | /**
36 | * @return int
37 | */
38 | public function getIndex() {
39 | return $this->index;
40 | }
41 |
42 |
43 | protected function getXmlNodeName() {
44 | return 'AssertionConsumerService';
45 | }
46 |
47 | /**
48 | * @param \DOMNode $parent
49 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
50 | * @return \DOMElement
51 | */
52 | function getXml(\DOMNode $parent, SerializationContext $context) {
53 | $result = $result = parent::getXml($parent, $context);
54 | $result->setAttribute('index', $this->getIndex());
55 | return $result;
56 | }
57 |
58 | /**
59 | * @param \DOMElement $xml
60 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
61 | */
62 | function loadFromXml(\DOMElement $xml) {
63 | parent::loadFromXml($xml);
64 | if (!$xml->hasAttribute('index')) {
65 | throw new InvalidXmlException("Missing index attribute");
66 | }
67 | $this->setIndex($xml->getAttribute('index'));
68 | }
69 |
70 |
71 |
72 |
73 |
74 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Metadata/Service/SingleLogoutService.php:
--------------------------------------------------------------------------------
1 | wantAssertionsSigned = (bool)$wantAssertionsSigned;
21 | }
22 |
23 | /**
24 | * @return boolean
25 | */
26 | public function getWantAssertionsSigned() {
27 | return $this->wantAssertionsSigned;
28 | }
29 |
30 |
31 |
32 |
33 |
34 |
35 | public function addService(AbstractService $service) {
36 | $class = Helper::getClassNameOnly($service);
37 | if ($class != 'SingleLogoutService' &&
38 | $class != 'AssertionConsumerService'
39 | ) {
40 | throw new \InvalidArgumentException("Invalid service type $class for SPSSODescriptor");
41 | }
42 | return parent::addService($service);
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function getXmlNodeName() {
49 | return 'SPSSODescriptor';
50 | }
51 |
52 |
53 | /**
54 | * @param \DOMNode $parent
55 | * @param SerializationContext $context
56 | * @return \DOMElement
57 | */
58 | function getXml(\DOMNode $parent, SerializationContext $context) {
59 | $result = parent::getXml($parent, $context);
60 | $result->setAttribute('WantAssertionsSigned', $this->getWantAssertionsSigned() ? 'true' : 'false');
61 | return $result;
62 | }
63 |
64 |
65 | /**
66 | * @param \DOMElement $xml
67 | */
68 | function loadFromXml(\DOMElement $xml) {
69 | parent::loadFromXml($xml);
70 | if ($xml->hasAttribute('WantAssertionsSigned')) {
71 | $this->setWantAssertionsSigned($xml->getAttribute('WantAssertionsSigned'));
72 | }
73 | }
74 |
75 |
76 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Protocol/AbstractRequest.php:
--------------------------------------------------------------------------------
1 | notOnOrAfter = $notOnOrAfter;
56 | return $this;
57 | }
58 |
59 | /**
60 | * @return int
61 | */
62 | public function getNotOnOrAfter(){
63 | return $this->notOnOrAfter;
64 | }
65 |
66 | /**
67 | * An indication of the reason for the logout
68 | * @param string $reason
69 | * @return LogoutRequest
70 | */
71 | public function setReason($reason){
72 | $this->reason = trim($reason);
73 | return $this;
74 | }
75 |
76 | public function getReason(){
77 | return $this->reason;
78 | }
79 |
80 | /**
81 | * @param NameID $nameId
82 | * @return LogoutRequest
83 | */
84 | public function setNameID(NameID $nameId){
85 | $this->nameID = $nameId;
86 | return $this;
87 | }
88 |
89 | /**
90 | * @return null|NameID
91 | */
92 | public function getNameID(){
93 | return $this->nameID;
94 | }
95 |
96 | /**
97 | * @param string $sessionIndex
98 | * @return LogoutRequest
99 | */
100 | public function setSessionIndex($sessionIndex){
101 | $this->sessionIndex = $sessionIndex;
102 | return $this;
103 | }
104 |
105 | /**
106 | * @return null|string
107 | */
108 | public function getSessionIndex(){
109 | return $this->sessionIndex;
110 | }
111 |
112 |
113 |
114 | function getXml(\DOMNode $parent, SerializationContext $context)
115 | {
116 | $result = parent::getXml($parent, $context);
117 |
118 | if ($this->getNotOnOrAfter()) {
119 | $result->setAttribute('NotOnOrAfter', Helper::time2string($this->getNotOnOrAfter()));
120 | }
121 | if ($this->getReason()) {
122 | $result->setAttribute('Reason', $this->getReason());
123 | }
124 | if ($this->getNameID()) {
125 | $result->appendChild($this->getNameID()->getXml($parent, $context));
126 | }
127 | if ($this->getSessionIndex()) {
128 | $sessionIndex = $context->getDocument()->createElementNS(Protocol::SAML2, 'samlp:SessionIndex', $this->getSessionIndex());
129 | $result->appendChild($sessionIndex);
130 | }
131 |
132 | return $result;
133 | }
134 |
135 | /**
136 | * @param \DOMElement $xml
137 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
138 | */
139 | function loadFromXml(\DOMElement $xml)
140 | {
141 | parent::loadFromXml($xml);
142 |
143 | if ($xml->hasAttribute('Reason')) {
144 | $this->setReason($xml->getAttribute('Reason'));
145 | }
146 | if ($xml->hasAttribute('NotOnOrAfter')) {
147 | $this->setNotOnOrAfter($xml->getAttribute('NotOnOrAfter'));
148 | }
149 |
150 | $signatureNode = null;
151 | $this->iterateChildrenElements($xml, function(\DOMElement $node) use (&$signatureNode) {
152 | if ($node->localName == 'NameID') {
153 | $nameID = new NameID();
154 | $nameID->loadFromXml($node);
155 | $this->setNameID($nameID);
156 | }
157 | if ($node->localName == 'SessionIndex') {
158 | $this->setSessionIndex($node->textContent);
159 | }
160 |
161 | if ($node->localName == 'Signature' && $node->namespaceURI == Protocol::NS_XMLDSIG) {
162 | $signatureNode = $node;
163 | }
164 | });
165 |
166 | if (null !== $signatureNode) {
167 | $signature = new SignatureXmlValidator;
168 | $signature->loadFromXml($signatureNode);
169 | $this->setSignature($signature);
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Protocol/LogoutResponse.php:
--------------------------------------------------------------------------------
1 | assertions;
39 | }
40 |
41 | public function addAssertion(Assertion $assertion) {
42 | $this->assertions[] = $assertion;
43 | }
44 |
45 |
46 |
47 |
48 | protected function prepareForXml() {
49 | parent::prepareForXml();
50 | if (!$this->getAllAssertions()) {
51 | throw new InvalidResponseException('Missing Assertions');
52 | }
53 | }
54 |
55 |
56 | /**
57 | * @param \DOMNode $parent
58 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
59 | * @return \DOMElement
60 | */
61 | function getXml(\DOMNode $parent, SerializationContext $context) {
62 | $result = parent::getXml($parent, $context);
63 | foreach ($this->getAllAssertions() as $assertion) {
64 | $assertion->getXml($result, $context);
65 | }
66 | return $result;
67 | }
68 |
69 |
70 | /**
71 | * @param \DOMElement $xml
72 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
73 | */
74 | function loadFromXml(\DOMElement $xml) {
75 | parent::loadFromXml($xml);
76 | $this->iterateChildrenElements($xml, function(\DOMElement $node) {
77 | if ($node->localName == 'Assertion' && $node->namespaceURI == Protocol::NS_ASSERTION) {
78 | $assertion = new Assertion();
79 | $assertion->loadFromXml($node);
80 | $this->addAssertion($assertion);
81 | }
82 | });
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Protocol/Status.php:
--------------------------------------------------------------------------------
1 | statusCode = $statusCode;
31 | $this->message = $message;
32 | }
33 |
34 | /**
35 | * @param \AerialShip\LightSaml\Model\Protocol\StatusCode $statusCode
36 | */
37 | public function setStatusCode($statusCode) {
38 | $this->statusCode = $statusCode;
39 | }
40 |
41 | /**
42 | * @return \AerialShip\LightSaml\Model\Protocol\StatusCode
43 | */
44 | public function getStatusCode() {
45 | return $this->statusCode;
46 | }
47 |
48 | /**
49 | * @param string $message
50 | */
51 | public function setMessage($message) {
52 | $this->message = $message;
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getMessage() {
59 | return $this->message;
60 | }
61 |
62 |
63 |
64 | public function isSuccess() {
65 | $result = $this->getStatusCode() && $this->getStatusCode()->getValue() == Protocol::STATUS_SUCCESS;
66 | return $result;
67 | }
68 |
69 |
70 | public function setSuccess() {
71 | $this->setStatusCode(new StatusCode());
72 | $this->getStatusCode()->setValue(Protocol::STATUS_SUCCESS);
73 | }
74 |
75 |
76 |
77 | protected function prepareForXml() {
78 | if (!$this->getStatusCode()) {
79 | throw new InvalidXmlException('StatusCode not set');
80 | }
81 | }
82 |
83 |
84 | /**
85 | * @param \DOMNode $parent
86 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
87 | * @return \DOMElement
88 | */
89 | function getXml(\DOMNode $parent, SerializationContext $context) {
90 | $this->prepareForXml();
91 |
92 | $result = $context->getDocument()->createElementNS(Protocol::SAML2, 'samlp:Status');
93 | $parent->appendChild($result);
94 |
95 | $result->appendChild($this->getStatusCode()->getXml($result, $context));
96 |
97 | if ($this->getMessage()) {
98 | $statusMessageNode = $context->getDocument()->createElementNS(Protocol::SAML2, 'samlp:StatusMessage', $this->getMessage());
99 | $result->appendChild($statusMessageNode);
100 | }
101 |
102 | return $result;
103 | }
104 |
105 |
106 | /**
107 | * @param \DOMElement $xml
108 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
109 | */
110 | function loadFromXml(\DOMElement $xml) {
111 | if ($xml->localName != 'Status' || $xml->namespaceURI != Protocol::SAML2) {
112 | throw new InvalidXmlException('Expected Status element but got '.$xml->localName);
113 | }
114 |
115 | $this->iterateChildrenElements($xml, function(\DOMElement $node) {
116 | if ($node->localName == 'StatusCode' && $node->namespaceURI == Protocol::SAML2) {
117 | $statusCode = new StatusCode();
118 | $statusCode->loadFromXml($node);
119 | $this->setStatusCode($statusCode);
120 | } else if ($node->localName == 'StatusMessage' && $node->namespaceURI == Protocol::SAML2) {
121 | $this->setMessage($node->textContent);
122 | }
123 | });
124 |
125 | if (!$this->getStatusCode()) {
126 | throw new InvalidXmlException('Missing StatusCode node');
127 | }
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Protocol/StatusCode.php:
--------------------------------------------------------------------------------
1 | value = $value;
29 | }
30 |
31 | /**
32 | * @param string $value
33 | */
34 | public function setValue($value) {
35 | $this->value = $value;
36 | }
37 |
38 | /**
39 | * @return string
40 | */
41 | public function getValue() {
42 | return $this->value;
43 | }
44 |
45 | /**
46 | * @param \AerialShip\LightSaml\Model\Protocol\StatusCode|null $child
47 | */
48 | public function setChild($child) {
49 | $this->child = $child;
50 | }
51 |
52 | /**
53 | * @return \AerialShip\LightSaml\Model\Protocol\StatusCode|null
54 | */
55 | public function getChild() {
56 | return $this->child;
57 | }
58 |
59 |
60 |
61 | protected function prepareForXml() {
62 | if (!$this->getValue()) {
63 | throw new InvalidXmlException('StatusCode value not set');
64 | }
65 | }
66 |
67 |
68 | /**
69 | * @param \DOMNode $parent
70 | * @param SerializationContext $context
71 | * @return \DOMElement
72 | */
73 | function getXml(\DOMNode $parent, SerializationContext $context) {
74 | $this->prepareForXml();
75 |
76 | $result = $context->getDocument()->createElementNS(Protocol::SAML2, 'samlp:StatusCode');
77 | $result->setAttribute('Value', $this->getValue());
78 |
79 | if ($this->getChild()) {
80 | $this->getChild()->getXml($result, $context);
81 | }
82 |
83 | return $result;
84 | }
85 |
86 | /**
87 | * @param \DOMElement $xml
88 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
89 | * @return void
90 | */
91 | function loadFromXml(\DOMElement $xml) {
92 | if ($xml->localName != 'StatusCode' || $xml->namespaceURI != Protocol::SAML2) {
93 | throw new InvalidXmlException('Expected StatusCode element but got '.$xml->localName);
94 | }
95 |
96 | if (!$xml->hasAttribute('Value')) {
97 | throw new InvalidXmlException('Required attribute StatusCode Value missing');
98 | }
99 | $this->setValue($xml->getAttribute('Value'));
100 |
101 | $this->iterateChildrenElements($xml, function(\DOMElement $node) {
102 | if ($node->localName == 'StatusCode' && $node->namespaceURI == Protocol::SAML2) {
103 | $this->setChild(new StatusCode());
104 | $this->getChild()->loadFromXml($node);
105 | } else {
106 | throw new InvalidXmlException('Unknown element '.$node->localName);
107 | }
108 | });
109 | }
110 |
111 |
112 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/Protocol/StatusResponse.php:
--------------------------------------------------------------------------------
1 | inResponseTo = $inResponseTo;
26 | }
27 |
28 | /**
29 | * @return string
30 | */
31 | public function getInResponseTo() {
32 | return $this->inResponseTo;
33 | }
34 |
35 |
36 | /**
37 | * @param \AerialShip\LightSaml\Model\Protocol\Status $status
38 | */
39 | public function setStatus($status) {
40 | $this->status = $status;
41 | }
42 |
43 | /**
44 | * @return \AerialShip\LightSaml\Model\Protocol\Status
45 | */
46 | public function getStatus() {
47 | return $this->status;
48 | }
49 |
50 |
51 |
52 |
53 |
54 | protected function prepareForXml() {
55 | parent::prepareForXml();
56 | if (!$this->getStatus()) {
57 | throw new InvalidResponseException('Missing Status');
58 | }
59 | }
60 |
61 |
62 | /**
63 | * @param \DOMNode $parent
64 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
65 | * @return \DOMElement
66 | */
67 | function getXml(\DOMNode $parent, SerializationContext $context) {
68 | $result = parent::getXml($parent, $context);
69 |
70 | if ($this->getInResponseTo()) {
71 | $result->setAttribute('InResponseTo', $this->getInResponseTo());
72 | }
73 | $this->getStatus()->getXml($result, $context);
74 | return $result;
75 | }
76 |
77 | /**
78 | * @param \DOMElement $xml
79 | * @throws \AerialShip\LightSaml\Error\InvalidXmlException
80 | */
81 | function loadFromXml(\DOMElement $xml) {
82 | parent::loadFromXml($xml);
83 |
84 | if ($xml->hasAttribute('InResponseTo')) {
85 | $this->setInResponseTo($xml->getAttribute('InResponseTo'));
86 | }
87 | $this->iterateChildrenElements($xml, function(\DOMElement $node) {
88 | if ($node->localName == 'Status' && $node->namespaceURI == Protocol::SAML2) {
89 | $this->setStatus(new Status());
90 | $this->getStatus()->loadFromXml($node);
91 | }
92 | });
93 | if (!$this->getStatus()) {
94 | throw new InvalidXmlException('Missing Status element');
95 | }
96 | }
97 |
98 |
99 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/XmlDSig/Signature.php:
--------------------------------------------------------------------------------
1 | canonicalMethod;
28 | }
29 |
30 | /**
31 | * @param string $canonicalMethod
32 | */
33 | public function setCanonicalMethod($canonicalMethod) {
34 | $this->canonicalMethod = $canonicalMethod;
35 | }
36 |
37 | /**
38 | * @param \XMLSecurityKey $key
39 | */
40 | public function setXmlSecurityKey(\XMLSecurityKey $key) {
41 | $this->xmlSecurityKey = $key;
42 | }
43 |
44 | /**
45 | * @return \XMLSecurityKey
46 | */
47 | public function getXmlSecurityKey() {
48 | return $this->xmlSecurityKey;
49 | }
50 |
51 | /**
52 | * @param \AerialShip\LightSaml\Security\X509Certificate $certificate
53 | */
54 | public function setCertificate(X509Certificate $certificate) {
55 | $this->certificate = $certificate;
56 | }
57 |
58 | /**
59 | * @return \AerialShip\LightSaml\Security\X509Certificate
60 | */
61 | public function getCertificate() {
62 | return $this->certificate;
63 | }
64 |
65 |
66 | /**
67 | * @param \DOMNode $parent
68 | * @param \AerialShip\LightSaml\Meta\SerializationContext $context
69 | * @return \DOMNode
70 | */
71 | function getXml(\DOMNode $parent, SerializationContext $context) {
72 | $objXMLSecDSig = new \XMLSecurityDSig();
73 | $objXMLSecDSig->setCanonicalMethod($this->getCanonicalMethod());
74 | $key = $this->getXmlSecurityKey();
75 | switch ($key->type) {
76 | case \XMLSecurityKey::RSA_SHA256:
77 | $type = \XMLSecurityDSig::SHA256;
78 | break;
79 | case \XMLSecurityKey::RSA_SHA384:
80 | $type = \XMLSecurityDSig::SHA384;
81 | break;
82 | case \XMLSecurityKey::RSA_SHA512:
83 | $type = \XMLSecurityDSig::SHA512;
84 | break;
85 | default:
86 | $type = \XMLSecurityDSig::SHA1;
87 | }
88 |
89 | $objXMLSecDSig->addReferenceList(
90 | array($parent),
91 | $type,
92 | array(Protocol::XMLSEC_TRANSFORM_ALGORITHM_ENVELOPED_SIGNATURE, \XMLSecurityDSig::EXC_C14N),
93 | array('id_name' => $this->getIDName(), 'overwrite' => FALSE)
94 | );
95 |
96 | $objXMLSecDSig->sign($key);
97 | $objXMLSecDSig->add509Cert($this->getCertificate()->getData(), false, false);
98 | $firstChild = $parent->hasChildNodes() ? $parent->firstChild : null;
99 | if ($firstChild && $firstChild->localName == 'Issuer') {
100 | // The signature node should come after the issuer node
101 | $firstChild = $firstChild->nextSibling;
102 | }
103 | $objXMLSecDSig->insertSignature($parent, $firstChild);
104 | }
105 |
106 |
107 |
108 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/XmlDSig/SignatureStringValidator.php:
--------------------------------------------------------------------------------
1 | signature = $signature;
25 | $this->algorithm = $algorithm;
26 | $this->data = $data;
27 | }
28 |
29 |
30 |
31 | /**
32 | * @param string $algorithm
33 | */
34 | public function setAlgorithm($algorithm)
35 | {
36 | $this->algorithm = $algorithm;
37 | }
38 |
39 | /**
40 | * @return string
41 | */
42 | public function getAlgorithm()
43 | {
44 | return $this->algorithm;
45 | }
46 |
47 | /**
48 | * @param string $data
49 | */
50 | public function setData($data)
51 | {
52 | $this->data = $data;
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getData()
59 | {
60 | return $this->data;
61 | }
62 |
63 | /**
64 | * @param string $signature
65 | */
66 | public function setSignature($signature)
67 | {
68 | $this->signature = $signature;
69 | }
70 |
71 | /**
72 | * @return string
73 | */
74 | public function getSignature()
75 | {
76 | return $this->signature;
77 | }
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | /**
86 | * @param \XMLSecurityKey $key
87 | * @return bool True if validated, False if validation was not performed
88 | * @throws \AerialShip\LightSaml\Error\SecurityException If validation fails
89 | */
90 | public function validate(\XMLSecurityKey $key)
91 | {
92 | if ($this->getSignature() == null) {
93 | return false;
94 | }
95 |
96 | if ($key->type !== \XMLSecurityKey::RSA_SHA1) {
97 | throw new SecurityException('Invalid key type for validating signature on query string');
98 | }
99 | if ($key->type !== $this->getAlgorithm()) {
100 | $key = KeyHelper::castKey($key, $this->getAlgorithm());
101 | }
102 |
103 | $signature = base64_decode($this->getSignature());
104 | if (!$key->verifySignature($this->getData(), $signature)) {
105 | throw new SecurityException('Unable to validate signature on query string');
106 | }
107 |
108 | return true;
109 | }
110 |
111 |
112 |
113 | /**
114 | * @param \XMLSecurityKey[] $keys
115 | * @throws \LogicException
116 | * @throws \InvalidArgumentException If some element of $keys array is not \XMLSecurityKey
117 | * @throws \AerialShip\LightSaml\Error\SecurityException If validation fails
118 | * @throws \Exception
119 | * @throws null
120 | * @return bool True if validated, False if validation was not performed
121 | */
122 | public function validateMulti(array $keys)
123 | {
124 | $lastException = null;
125 |
126 | foreach ($keys as $key) {
127 | if (!$key instanceof \XMLSecurityKey) {
128 | throw new \InvalidArgumentException('Expected XMLSecurityKey but got '.get_class($key));
129 | }
130 |
131 | try {
132 | $result = $this->validate($key);
133 |
134 | if ($result === false) {
135 | return false;
136 | }
137 |
138 | return true;
139 |
140 | } catch (SecurityException $ex) {
141 | $lastException = $ex;
142 | }
143 | }
144 |
145 | if ($lastException) {
146 | throw $lastException;
147 | } else {
148 | throw new \LogicException('Should not get here???');
149 | }
150 | }
151 |
152 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Model/XmlDSig/SignatureValidatorInterface.php:
--------------------------------------------------------------------------------
1 | getConstants();
25 | }
26 | return self::$_constants;
27 | }
28 |
29 |
30 | static function isValid($value) {
31 | $result = in_array($value, self::getConstants());
32 | return $result;
33 | }
34 |
35 |
36 | private function __construct() { }
37 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Protocol.php:
--------------------------------------------------------------------------------
1 | 'private'));
20 | $result->passphrase = $passphrase;
21 | $result->loadKey($key, $isFile, $isCert);
22 |
23 | return $result;
24 | }
25 |
26 | /**
27 | * @param X509Certificate $certificate
28 | * @return \XMLSecurityKey
29 | */
30 | static function createPublicKey(X509Certificate $certificate)
31 | {
32 | $key = new \XMLSecurityKey(\XMLSecurityKey::RSA_SHA1, array('type'=>'public'));
33 | $key->loadKey($certificate->toPem(), false, true);
34 |
35 | return $key;
36 | }
37 |
38 |
39 | /**
40 | * @param \XMLSecurityKey $key
41 | * @param string $algorithm
42 | * @throws \AerialShip\LightSaml\Error\SecurityException
43 | * @throws \InvalidArgumentException
44 | * @return \XMLSecurityKey
45 | */
46 | static function castKey(\XMLSecurityKey $key, $algorithm)
47 | {
48 | if (!is_string($algorithm)) {
49 | throw new \InvalidArgumentException('Algorithm must be string');
50 | }
51 |
52 | // do nothing if algorithm is already the type of the key
53 | if ($key->type === $algorithm) {
54 | return $key;
55 | }
56 |
57 | $keyInfo = openssl_pkey_get_details($key->key);
58 | if ($keyInfo === FALSE) {
59 | throw new SecurityException('Unable to get key details from XMLSecurityKey.');
60 | }
61 | if (!isset($keyInfo['key'])) {
62 | throw new SecurityException('Missing key in public key details.');
63 | }
64 |
65 | $newKey = new \XMLSecurityKey($algorithm, array('type'=>'public'));
66 | $newKey->loadKey($keyInfo['key']);
67 |
68 | return $newKey;
69 | }
70 |
71 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Security/X509Certificate.php:
--------------------------------------------------------------------------------
1 | data = preg_replace('/\s+/', '', $data);
19 | }
20 |
21 | /**
22 | * @return string
23 | */
24 | public function getData() {
25 | return $this->data;
26 | }
27 |
28 |
29 |
30 |
31 | function loadPem($data) {
32 | $pattern = '/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
33 | if (!preg_match($pattern, $data, $matches)) {
34 | throw new InvalidCertificateException('Invalid PEM encoded certificate');
35 | }
36 | $this->data = preg_replace('/\s+/', '', $matches[1]);
37 | }
38 |
39 | function loadFromFile($filename) {
40 | if (!is_file($filename)) {
41 | throw new InvalidCertificateException("File not found $filename");
42 | }
43 | $content = file_get_contents($filename);
44 | $this->loadPem($content);
45 | }
46 |
47 | function toPem() {
48 | $result = "-----BEGIN CERTIFICATE-----\n".chunk_split($this->getData(), 64, "\n")."-----END CERTIFICATE-----\n";
49 | return $result;
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Binding/Base.php:
--------------------------------------------------------------------------------
1 | loadFromFile(__DIR__.'/../../../../../resources/sample/Certificate/saml.crt');
38 |
39 | $key = new \XMLSecurityKey(\XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
40 | $key->loadKey(__DIR__.'/../../../../../resources/sample/Certificate/saml.pem', true, false);
41 |
42 | $signature = new SignatureCreator();
43 | $signature->setCertificate($certificate);
44 | $signature->setXmlSecurityKey($key);
45 | $request->setSignature($signature);
46 |
47 | $request->setRelayState($this->relayState);
48 |
49 | return $request;
50 | }
51 |
52 |
53 | protected function checkRequest(AuthnRequest $request, $id, $time) {
54 | $this->assertEquals($id, $request->getID());
55 | $this->assertEquals('2.0', $request->getVersion());
56 | $this->assertEquals($this->destination, $request->getDestination());
57 | $this->assertEquals($this->ascURL, $request->getAssertionConsumerServiceURL());
58 | $this->assertEquals($this->protocolBinding, $request->getProtocolBinding());
59 | $this->assertEquals($time, $request->getIssueInstant());
60 |
61 | $this->assertEquals($this->issuer, $request->getIssuer());
62 | $this->assertEquals($this->nameIDPolicyFormat, $request->getNameIdPolicyFormat());
63 | $this->assertTrue($request->getNameIdPolicyAllowCreate());
64 |
65 |
66 | /** @var SignatureValidatorInterface $signature */
67 | $signature = $request->getSignature();
68 | $this->assertNotNull($signature);
69 | $this->assertTrue($signature instanceof SignatureValidatorInterface);
70 |
71 | $certificate = new X509Certificate();
72 | $certificate->loadFromFile(__DIR__.'/../../../../../resources/sample/Certificate/saml.crt');
73 | $key = KeyHelper::createPublicKey($certificate);
74 | $signature->validate($key);
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Binding/HttpPostTest.php:
--------------------------------------------------------------------------------
1 | getRequest();
15 | $id = $authnRequest->getID();
16 | $time = $authnRequest->getIssueInstant();
17 |
18 | $binding = new HttpPost();
19 |
20 | /** @var PostResponse $response */
21 | $response = $binding->send($authnRequest);
22 | $this->assertNotNull($response);
23 | $this->assertTrue($response instanceof PostResponse);
24 | $this->assertEquals($this->destination, $response->getDestination());
25 |
26 | /** @var $authnRequest AuthnRequest */
27 | $bindingRequest = new Request();
28 | $bindingRequest->setPost($response->getData());
29 | $authnRequest = $binding->receive($bindingRequest);
30 | $this->assertTrue($authnRequest instanceof AuthnRequest);
31 | $this->checkRequest($authnRequest, $id, $time);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Binding/HttpRedirectTest.php:
--------------------------------------------------------------------------------
1 | getRequest();
16 | $id = $authnRequest->getID();
17 | $time = $authnRequest->getIssueInstant();
18 |
19 | $binding = new HttpRedirect();
20 |
21 | /** @var RedirectResponse $response */
22 | $response = $binding->send($authnRequest);
23 | $this->assertNotNull($response);
24 | $this->assertTrue($response instanceof RedirectResponse);
25 | $pos = strpos($response->getDestination(), '?');
26 | $destination = substr($response->getDestination(), 0, $pos);
27 | $queryString = substr($response->getDestination(), $pos+1);
28 |
29 | $this->assertEquals($this->destination, $destination);
30 |
31 | $bindingRequest = new Request();
32 | $data = $bindingRequest->parseQueryString($queryString, true);
33 | $this->checkData($data);
34 |
35 |
36 | /** @var AuthnRequest $authnRequest */
37 | $authnRequest = $binding->receive($bindingRequest);
38 | $this->assertTrue($authnRequest instanceof AuthnRequest);
39 | $this->checkRequest($authnRequest, $id, $time);
40 | }
41 |
42 |
43 |
44 |
45 |
46 | private function checkData(array $data) {
47 | $this->assertTrue(array_key_exists('SAMLRequest', $data));
48 | $this->assertTrue(array_key_exists('RelayState', $data));
49 | $this->assertTrue(array_key_exists('SigAlg', $data));
50 | $this->assertTrue(array_key_exists('Signature', $data));
51 |
52 | $this->assertEquals($this->relayState, $data['RelayState']);
53 | $this->assertEquals($this->sigAlg, $data['SigAlg']);
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/CommonHelper.php:
--------------------------------------------------------------------------------
1 | load($file);
28 | $result = new EntityDescriptor();
29 | $result->loadFromXml($doc->firstChild);
30 | return $result;
31 | }
32 |
33 |
34 | /**
35 | * @param string $sp
36 | * @param string $idp
37 | * @param SpMeta $spMeta
38 | * @return AuthnRequest
39 | * @throws \InvalidArgumentException
40 | */
41 | public static function buildAuthnRequestFromEntityDescriptors($sp, $idp, SpMeta $spMeta = null)
42 | {
43 | if (is_string($sp)) {
44 | $sp = self::getEntityDescriptorFromXmlFile($sp);
45 | } else if (!$sp instanceof EntityDescriptor) {
46 | throw new \InvalidArgumentException('SP parameter must be instance of EntityDescriptor or string');
47 | }
48 |
49 | if (is_string($idp)) {
50 | $idp = self::getEntityDescriptorFromXmlFile($idp);
51 | } else if (!$idp instanceof EntityDescriptor) {
52 | throw new \InvalidArgumentException('IDP parameter must be instance of EntityDescriptor or string');
53 | }
54 |
55 | if (!$spMeta) {
56 | $spMeta = new SpMeta();
57 | $spMeta->setNameIdFormat(NameIDPolicy::PERSISTENT);
58 | }
59 |
60 | $builder = new AuthnRequestBuilder($sp, $idp, $spMeta);
61 | $result = $builder->build();
62 | return $result;
63 | }
64 |
65 | /**
66 | * @param string $sp
67 | * @param string $idp
68 | * @param SpMeta $spMeta
69 | * @return LogoutRequest
70 | * @throws \InvalidArgumentException
71 | */
72 | public static function buildLogoutRequestFromEntityDescriptors($sp, $idp, SpMeta $spMeta = null)
73 | {
74 | if (is_string($sp)) {
75 | $sp = self::getEntityDescriptorFromXmlFile($sp);
76 | } else if (!$sp instanceof EntityDescriptor) {
77 | throw new \InvalidArgumentException('SP parameter must be instance of EntityDescriptor or string');
78 | }
79 |
80 | if (is_string($idp)) {
81 | $idp = self::getEntityDescriptorFromXmlFile($idp);
82 | } else if (!$idp instanceof EntityDescriptor) {
83 | throw new \InvalidArgumentException('IDP parameter must be instance of EntityDescriptor or string');
84 | }
85 |
86 | if (!$spMeta) {
87 | $spMeta = new SpMeta();
88 | $spMeta->setNameIdFormat(NameIDPolicy::PERSISTENT);
89 | }
90 |
91 | $builder = new LogoutRequestBuilder($sp, $idp, $spMeta);
92 | $result = $builder->build('urn:oasis:names:tc:SAML:2.0:nameid-format:transient', 'user', '_677952a2-7fb3-4e7a-b439-326366e677db');
93 | return $result;
94 | }
95 |
96 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/Metadata/EntitiesDescriptor/EntitiesDescriptorFunctional01Test.php:
--------------------------------------------------------------------------------
1 | load(__DIR__.'/../../../../../../../resources/sample/EntitiesDescriptor/testshib-providers.xml');
18 |
19 | $ed = new EntitiesDescriptor();
20 | $ed->loadFromXml($doc->firstChild);
21 |
22 | $arr = $ed->getAllEntityDescriptors();
23 | $this->assertCount(2, $arr);
24 |
25 | $this->assertEquals('https://idp.testshib.org/idp/shibboleth', $arr[0]->getEntityID());
26 | $this->assertCount(1, $arr[0]->getAllIdpSsoDescriptors());
27 | $this->assertCount(0, $arr[0]->getAllSpSsoDescriptors());
28 |
29 | $this->assertEquals('https://sp.testshib.org/shibboleth-sp', $arr[1]->getEntityID());
30 | $this->assertCount(0, $arr[1]->getAllIdpSsoDescriptors());
31 | $this->assertCount(1, $arr[1]->getAllSpSsoDescriptors());
32 | }
33 |
34 |
35 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/Metadata/EntityDescriptor/EntityDescriptorSample02Test.php:
--------------------------------------------------------------------------------
1 | load(__DIR__.'/../../../../../../../resources/sample/EntityDescriptor/ed01-formatted-certificate.xml');
24 |
25 | $ed = new EntityDescriptor();
26 | $ed->loadFromXml($doc->firstChild);
27 |
28 | $this->checkSP($ed);
29 | $this->checkIDP($ed);
30 | }
31 |
32 |
33 | private function checkIDP(EntityDescriptor $ed) {
34 | $arr = $ed->getAllIdpSsoDescriptors();
35 | $this->assertEquals(1, count($arr));
36 | $idp = $arr[0];
37 |
38 | $this->assertEquals(1, count($idp->getKeyDescriptors()));
39 |
40 | $arr = $idp->getKeyDescriptors();
41 | $this->assertEquals(1, count($arr));
42 | $this->assertEquals('', $arr[0]->getUse());
43 | $cert = $arr[0]->getCertificate();
44 | $this->assertNotNull($cert);
45 | $this->assertGreaterThan(100, strlen($cert->getData()));
46 |
47 | $this->assertEquals(0, count($idp->findSingleLogoutServices()));
48 |
49 | $this->assertEquals(4, count($idp->findSingleSignOnServices()));
50 |
51 | $arr = $idp->findSingleSignOnServices(Bindings::SAML2_HTTP_POST);
52 | $this->assertEquals(1, count($arr));
53 | $this->assertEquals(Bindings::SAML2_HTTP_POST, $arr[0]->getBinding());
54 | $this->assertEquals('https://idp.testshib.org/idp/profile/SAML2/POST/SSO', $arr[0]->getLocation());
55 |
56 | $arr = $idp->findSingleSignOnServices(Bindings::SAML2_HTTP_REDIRECT);
57 | $this->assertEquals(1, count($arr));
58 | $this->assertEquals(Bindings::SAML2_HTTP_REDIRECT, $arr[0]->getBinding());
59 | $this->assertEquals('https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO', $arr[0]->getLocation());
60 | }
61 |
62 |
63 | private function checkSP(EntityDescriptor $ed) {
64 | $arr = $ed->getAllSpSsoDescriptors();
65 | $this->assertEquals(0, count($arr));
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/Metadata/SSODescriptor/SSODescriptorTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($rc->isAbstract());
16 | }
17 |
18 | /**
19 | * @test
20 | */
21 | public function shouldImplementGetXmlInterface()
22 | {
23 | $rc = new \ReflectionClass('AerialShip\LightSaml\Model\Metadata\SSODescriptor');
24 | $this->assertTrue($rc->implementsInterface('AerialShip\LightSaml\Meta\GetXmlInterface'));
25 | }
26 |
27 | /**
28 | * @test
29 | */
30 | public function shouldImplementLoadFromXmlInterface()
31 | {
32 | $rc = new \ReflectionClass('AerialShip\LightSaml\Model\Metadata\SSODescriptor');
33 | $this->assertTrue($rc->implementsInterface('AerialShip\LightSaml\Meta\LoadFromXmlInterface'));
34 | }
35 |
36 | /**
37 | * @test
38 | */
39 | public function shouldReturnAllKeyDescriptorsWhenFindKeyDescriptorsCalledWithNullArgument()
40 | {
41 | $mock = $this->getSSODescriptorMock();
42 | $mock->addKeyDescriptor($kd1 = new KeyDescriptor());
43 | $mock->addKeyDescriptor($kd2 = new KeyDescriptor(KeyDescriptor::USE_SIGNING));
44 | $mock->addKeyDescriptor($kd3 = new KeyDescriptor(KeyDescriptor::USE_ENCRYPTION));
45 |
46 | $arr = $mock->findKeyDescriptors(null);
47 | $this->assertCount(3, $arr);
48 | $this->assertContainsOnlyInstancesOf('AerialShip\LightSaml\Model\Metadata\KeyDescriptor', $arr);
49 | $this->assertSame($kd1, $arr[0]);
50 | $this->assertSame($kd2, $arr[1]);
51 | $this->assertSame($kd3, $arr[2]);
52 | }
53 |
54 | /**
55 | * @test
56 | */
57 | public function shouldReturnSignAndNullUseKeyDescriptorsWhenFindKeyDescriptorsCalledWithSignArgument()
58 | {
59 | $mock = $this->getSSODescriptorMock();
60 | $mock->addKeyDescriptor($kd1 = new KeyDescriptor());
61 | $mock->addKeyDescriptor($kd2 = new KeyDescriptor(KeyDescriptor::USE_SIGNING));
62 | $mock->addKeyDescriptor($kd3 = new KeyDescriptor(KeyDescriptor::USE_ENCRYPTION));
63 |
64 | $arr = $mock->findKeyDescriptors(KeyDescriptor::USE_SIGNING);
65 | $this->assertCount(2, $arr);
66 | $this->assertContainsOnlyInstancesOf('AerialShip\LightSaml\Model\Metadata\KeyDescriptor', $arr);
67 | $this->assertSame($kd1, $arr[0]);
68 | $this->assertSame($kd2, $arr[1]);
69 | }
70 |
71 | /**
72 | * @test
73 | */
74 | public function shouldReturnEncryptionAndNullUseKeyDescriptorsWhenFindKeyDescriptorsCalledWithEncryptionArgument()
75 | {
76 | $mock = $this->getSSODescriptorMock();
77 | $mock->addKeyDescriptor($kd1 = new KeyDescriptor());
78 | $mock->addKeyDescriptor($kd2 = new KeyDescriptor(KeyDescriptor::USE_SIGNING));
79 | $mock->addKeyDescriptor($kd3 = new KeyDescriptor(KeyDescriptor::USE_ENCRYPTION));
80 |
81 | $arr = $mock->findKeyDescriptors(KeyDescriptor::USE_ENCRYPTION);
82 | $this->assertCount(2, $arr);
83 | $this->assertContainsOnlyInstancesOf('AerialShip\LightSaml\Model\Metadata\KeyDescriptor', $arr);
84 | $this->assertSame($kd1, $arr[0]);
85 | $this->assertSame($kd3, $arr[1]);
86 | }
87 |
88 |
89 |
90 | /**
91 | * @return \PHPUnit_Framework_MockObject_MockObject|\AerialShip\LightSaml\Model\Metadata\SSODescriptor
92 | */
93 | private function getSSODescriptorMock()
94 | {
95 | return $this->getMock('AerialShip\LightSaml\Model\Metadata\SSODescriptor', array('getXmlNodeName'));
96 | }
97 |
98 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/Protocol/AuthnRequest/AuthnRequestSample01Test.php:
--------------------------------------------------------------------------------
1 | setNameIdFormat(NameIDPolicy::PERSISTENT);
26 | $request = CommonHelper::buildAuthnRequestFromEntityDescriptors(
27 | __DIR__.'/../../../../../../../resources/sample/EntityDescriptor/sp-ed2.xml',
28 | __DIR__.'/../../../../../../../resources/sample/EntityDescriptor/idp2-ed.xml',
29 | $spMeta
30 | );
31 |
32 | $id = $request->getID();
33 | $this->assertNotEmpty($id);
34 | $this->assertEquals(43, strlen($id));
35 |
36 | $time = $request->getIssueInstant();
37 | $this->assertNotEmpty($time);
38 | $this->assertLessThan(2, abs(time()-$time));
39 |
40 | $this->checkRequestObject($request, $id, $time);
41 |
42 | // serialize to XML Document and check xml
43 | $context = new SerializationContext();
44 | $request->getXml($context->getDocument(), $context);
45 | $this->checkRequestXml($context->getDocument(), $id);
46 |
47 | // Deserialize new request out of xml
48 | $request = new AuthnRequest();
49 | $request->loadFromXml($context->getDocument()->firstChild);
50 | $this->checkRequestObject($request, $id, $time);
51 |
52 | // serialize again to xml and check xml
53 | $context = new SerializationContext();
54 | $request->getXml($context->getDocument(), $context);
55 | $this->checkRequestXml($context->getDocument(), $id);
56 | }
57 |
58 | private function checkRequestObject(AuthnRequest $request, $id, $time) {
59 | $this->assertEquals($id, $request->getID());
60 | $this->assertEquals('2.0', $request->getVersion());
61 | $this->assertEquals($this->destination, $request->getDestination());
62 | $this->assertEquals($this->ascURL, $request->getAssertionConsumerServiceURL());
63 | $this->assertEquals($this->protocolBinding, $request->getProtocolBinding());
64 | $this->assertEquals($time, $request->getIssueInstant());
65 |
66 | $this->assertEquals($this->issuer, $request->getIssuer());
67 | $this->assertEquals($this->nameIDPolicyFormat, $request->getNameIdPolicyFormat());
68 | $this->assertTrue($request->getNameIdPolicyAllowCreate());
69 | }
70 |
71 |
72 | private function checkRequestXml(\DOMDocument $doc, $id) {
73 | //$xml = $doc->saveXML();
74 | //print "\n\n$xml\n\n";
75 |
76 | $xpath = new \DOMXPath($doc);
77 | $xpath->registerNamespace('samlp', Protocol::SAML2);
78 | $xpath->registerNamespace('saml', Protocol::NS_ASSERTION);
79 |
80 | $list = $xpath->query('/samlp:AuthnRequest');
81 | $this->assertEquals(1, $list->length);
82 |
83 | /** @var $node \DOMElement */
84 | $node = $list->item(0);
85 |
86 | $this->assertEquals($id, $node->getAttribute('ID'));
87 | $this->assertEquals('2.0', $node->getAttribute('Version'));
88 | $this->assertEquals($this->destination, $node->getAttribute('Destination'));
89 | $this->assertEquals($this->ascURL, $node->getAttribute('AssertionConsumerServiceURL'));
90 | $this->assertEquals($this->protocolBinding, $node->getAttribute('ProtocolBinding'));
91 |
92 | $list = $xpath->query('/samlp:AuthnRequest/saml:Issuer');
93 | $this->assertEquals(1, $list->length);
94 | /** @var $node \DOMElement */
95 | $node = $list->item(0);
96 | $this->assertEquals($this->issuer, $node->textContent);
97 |
98 | $list = $xpath->query('/samlp:AuthnRequest/samlp:NameIDPolicy');
99 | $this->assertEquals(1, $list->length);
100 | /** @var $node \DOMElement */
101 | $node = $list->item(0);
102 | $this->assertEquals($this->nameIDPolicyFormat, $node->getAttribute('Format'));
103 | $this->assertEquals('true', $node->getAttribute('AllowCreate'));
104 | }
105 |
106 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/Protocol/LogoutRequest/LogoutRequestSample01Test.php:
--------------------------------------------------------------------------------
1 | setNameIdFormat(NameIDPolicy::PERSISTENT);
23 |
24 | $request = CommonHelper::buildLogoutRequestFromEntityDescriptors(
25 | __DIR__.'/../../../../../../../resources/sample/EntityDescriptor/sp-ed2.xml',
26 | __DIR__.'/../../../../../../../resources/sample/EntityDescriptor/idp2-ed.xml',
27 | $spMeta
28 | );
29 |
30 | $id = $request->getID();
31 | $this->assertNotEmpty($id);
32 | $this->assertEquals(43, strlen($id));
33 |
34 | $time = $request->getIssueInstant();
35 | $this->assertNotEmpty($time);
36 | $this->assertLessThan(2, abs(time()-$time));
37 |
38 | $this->checkRequestObject($request, $id, $time);
39 |
40 | $context = new SerializationContext();
41 | $request->getXml($context->getDocument(), $context);
42 | $this->checkRequestXml($context->getDocument(), $request);
43 |
44 | $request = new LogoutRequest();
45 | $request->loadFromXml($context->getDocument()->firstChild);
46 | $this->checkRequestObject($request, $id, $time);
47 | }
48 |
49 | private function checkRequestObject(LogoutRequest $request, $id, $time) {
50 | $this->assertEquals($id, $request->getID());
51 | $this->assertEquals('2.0', $request->getVersion());
52 | $this->assertEquals($this->destination, $request->getDestination());
53 | $this->assertEquals($time, $request->getIssueInstant());
54 | $this->assertEquals($this->issuer, $request->getIssuer());
55 |
56 | $reason = $request->getReason();
57 | if($reason != null){
58 | $this->assertStringMatchesFormat('%s', $reason);
59 | }
60 | $NameId = $request->getNameID();
61 | $this->assertInstanceOf('AerialShip\LightSaml\Model\Assertion\NameID', $NameId);
62 | $this->assertNotEmpty($NameId->getFormat());
63 | }
64 |
65 | private function checkRequestXml(\DOMDocument $doc, LogoutRequest $request)
66 | {
67 | $xpath = new \DOMXPath($doc);
68 | $xpath->registerNamespace('samlp', Protocol::SAML2);
69 | $xpath->registerNamespace('saml', Protocol::NS_ASSERTION);
70 |
71 | $list = $xpath->query('/samlp:LogoutRequest');
72 | $this->assertEquals(1, $list->length);
73 |
74 | /** @var $node \DOMElement */
75 | $node = $list->item(0);
76 |
77 | $this->assertEquals($request->getReason(), $node->getAttribute('Reason'));
78 | $this->assertEquals($request->getID(), $node->getAttribute('ID'));
79 | $this->assertEquals('2.0', $node->getAttribute('Version'));
80 | $this->assertEquals($this->destination, $node->getAttribute('Destination'));
81 |
82 | $list = $xpath->query('/samlp:LogoutRequest/saml:Issuer');
83 | $this->assertEquals(1, $list->length);
84 | $node = $list->item(0);
85 | $this->assertEquals($this->issuer, $node->textContent);
86 |
87 | $list = $xpath->query('/samlp:LogoutRequest/saml:NameID');
88 | $this->assertEquals(1, $list->length);
89 | $node = $list->item(0);
90 | $this->assertEquals($request->getNameID()->getFormat(), $node->getAttribute('Format'));
91 | $this->assertEquals($request->getNameID()->getValue(), $node->textContent);
92 | }
93 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/XmlDSig/Signature/SignatureCreatorValidatorFunctionalTest.php:
--------------------------------------------------------------------------------
1 | getSignedXml();
17 | $this->verifySignature($xml);
18 | }
19 |
20 |
21 | private function verifySignature($xml) {
22 | $doc = new \DOMDocument();
23 | $doc->loadXML($xml);
24 |
25 | $xpath = new \DOMXPath($doc);
26 | $xpath->registerNamespace('ds', Protocol::NS_XMLDSIG);
27 |
28 | $list = $xpath->query('/root/ds:Signature');
29 | $this->assertEquals(1, $list->length);
30 |
31 | /** @var $signatureNode \DOMElement */
32 | $signatureNode = $list->item(0);
33 |
34 | $signatureValidator = new SignatureXmlValidator();
35 | $signatureValidator->loadFromXml($signatureNode);
36 |
37 |
38 | $certificate = new X509Certificate();
39 | $certificate->loadFromFile(__DIR__.'/../../../../../../../resources/sample/Certificate/saml.crt');
40 |
41 | $key = KeyHelper::createPublicKey($certificate);
42 |
43 | $ok = $signatureValidator->validate($key);
44 |
45 | $this->assertTrue($ok);
46 | }
47 |
48 |
49 | private function getSignedXml() {
50 | $doc = new \DOMDocument();
51 | $doc->appendChild($doc->createElement('root'));
52 | /** @var $root \DOMElement */
53 | $root = $doc->firstChild;
54 | $root->setAttribute('foo', 'bar');
55 |
56 | $other = $doc->createElement('other');
57 | $root->appendChild($other);
58 | $child = $doc->createElement('child', 'something');
59 | $other->appendChild($child);
60 |
61 | $certificate = new X509Certificate();
62 | $certificate->loadFromFile(__DIR__.'/../../../../../../../resources/sample/Certificate/saml.crt');
63 |
64 | $key = new \XMLSecurityKey(\XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
65 | $key->loadKey(__DIR__.'/../../../../../../../resources/sample/Certificate/saml.pem', true);
66 |
67 | $signatureCreator = new SignatureCreator();
68 | $signatureCreator->setCertificate($certificate);
69 | $signatureCreator->setXmlSecurityKey($key);
70 |
71 | $context = new SerializationContext($doc);
72 | $signatureCreator->getXml($root, $context);
73 |
74 | $xml = $doc->saveXML();
75 |
76 | return $xml;
77 | }
78 |
79 |
80 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Model/XmlDSig/Signature/SignatureSample01Test.php:
--------------------------------------------------------------------------------
1 | load(__DIR__.'/../../../../../../../resources/sample/Response/response01.xml');
17 |
18 | $xpath = new \DOMXPath($doc);
19 | $xpath->registerNamespace('samlp', Protocol::SAML2);
20 | $xpath->registerNamespace('ds', Protocol::NS_XMLDSIG);
21 | $xpath->registerNamespace('a', Protocol::NS_ASSERTION);
22 |
23 | $list = $xpath->query('/samlp:Response/a:Assertion/ds:Signature');
24 | $this->assertEquals(1, $list->length);
25 | /** @var $signatureNode \DOMElement */
26 | $signatureNode = $list->item(0);
27 |
28 | $signatureValidator = new SignatureXmlValidator();
29 | $signatureValidator->loadFromXml($signatureNode);
30 |
31 | $list = $xpath->query('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', $signatureNode);
32 | $this->assertEquals(1, $list->length);
33 | /** @var $signatureNode \DOMElement */
34 | $certificateDataNode = $list->item(0);
35 |
36 | $certData = $certificateDataNode->textContent;
37 | $certificate = new X509Certificate();
38 | $certificate->setData($certData);
39 | $key = KeyHelper::createPublicKey($certificate);
40 |
41 | $ok = $signatureValidator->validate($key);
42 | $this->assertTrue($ok);
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/src/AerialShip/LightSaml/Tests/Security/X509CertificateTest.php:
--------------------------------------------------------------------------------
1 | setData($this->getData());
18 | KeyHelper::createPublicKey($cert);
19 | }
20 |
21 |
22 | /**
23 | * @test
24 | */
25 | public function shouldCreatePublicKeyWhenLoadedFromPem()
26 | {
27 | $cert = new X509Certificate();
28 | $cert->loadPem($this->getPEM());
29 | KeyHelper::createPublicKey($cert);
30 | }
31 |
32 |
33 | /**
34 | * @return string
35 | */
36 | protected function getPEM()
37 | {
38 | return "-----BEGIN CERTIFICATE-----\n".trim($this->getData())."\n-----END CERTIFICATE-----\n";
39 | }
40 |
41 |
42 | /**
43 | * @return string
44 | */
45 | protected function getData()
46 | {
47 | return "
48 | MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEV
49 | MBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYD
50 | VQQKEwhUZXN0U2hpYjEZMBcGA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4
51 | MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcxCzAJBgNVBAYTAlVTMRUwEwYDVQQI
52 | EwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gxETAPBgNVBAoTCFRl
53 | c3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0B
54 | AQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7C
55 | yVTDClcpu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe
56 | 3OQ01Ow3yT4I+Wdg1tsTpSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aT
57 | NPFmDixzUjoYzbGDrtAyCqA8f9CN2txIfJnpHE6q6CmKcoLADS4UrNPlhHSzd614
58 | kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB5/9nb0yh/ojRuJGmgMWH
59 | gWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HEMIHBMB0G
60 | A1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ86
61 | 9nh83KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBl
62 | bm5zeWx2YW5pYTETMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNo
63 | aWIxGTAXBgNVBAMTEGlkcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zAN
64 | BgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5MFfSVk98t3CT9jHZoYxd8QMRL
65 | I4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpkOAvZZUosVkUo
66 | 93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4
67 | /SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAj
68 | Geka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr
69 | 8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA==
70 | ";
71 | }
72 | }
--------------------------------------------------------------------------------