├── .nvmrc ├── index.js ├── .gitignore ├── .npmignore ├── test └── data │ ├── response_no_status.xml │ ├── response_bad_version.xml │ ├── good_response_decrypted.xml │ ├── namespaced_assertion.xml │ ├── response_error_status.xml │ ├── logout_request.xml │ ├── namespaced_assertion_with_empty_inclusivenamespaces.xml │ ├── namespaced_assertion_with_inclusivenamespaces.xml │ ├── empty_attribute_value.xml │ ├── blank_assertion.xml │ ├── test.crt │ ├── test2.crt │ ├── no_subject.xml │ ├── test.pem │ ├── test2.pem │ ├── response_notbefore_future_decoded.xml │ ├── response_no_audience_no_timing.xml │ ├── response_empty_audience_no_timing.xml │ ├── good_response.xml │ ├── response_audience_no_timing.xml │ ├── unsigned_assertion.xml │ ├── good_assertion_signed_data.xml │ ├── response_notbefore_future.xml │ ├── empty_session_index.xml │ ├── empty_nameid.xml │ ├── response_unsigned_assertion.xml │ ├── good_assertion_no_session_index.xml │ ├── good_assertion.xml │ ├── response_external_signed_assertion.xml │ ├── response_notbefore_future_encrypted_decoded.xml │ ├── good_assertion_commented_out_digest.xml │ ├── good_assertion_explicit_namespaces.xml │ ├── response_notbefore_future_signed.xml │ ├── response_notbefore_future_encrypted.xml │ ├── redirect_response.xml │ ├── response_notbefore_future_encrypted_then_signed.xml │ ├── good_response_twice_signed_dsig_ns_at_top.xml │ ├── response_notbefore_future_signed_then_encrypted.xml │ ├── good_response_twice_signed.xml │ ├── post_response.xml │ ├── response_notbefore_future_encrypted_then_signed_base64.xml │ └── response_notbefore_future_signed_then_encrypted_base64.xml ├── catalog-info.yaml ├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── notify-ci-status.yml ├── package.json ├── .circleci └── config.yml ├── LICENSE ├── README.md └── lib └── saml2.coffee /.nvmrc: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib-js/saml2'); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | node_modules 3 | lib-js 4 | *.html 5 | package-lock.json 6 | coverage 7 | .nyc_output/ 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *~ 2 | coverage 3 | node_modules 4 | lib 5 | *.html 6 | .circleci/ 7 | .github/ 8 | .nvmrc 9 | -------------------------------------------------------------------------------- /test/data/response_no_status.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/data/response_bad_version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/data/good_response_decrypted.xml: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. -------------------------------------------------------------------------------- /test/data/namespaced_assertion.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: saml2 5 | description: Node module to abstract away the complexities of the SAML protocol behind an easy to use interface. 6 | owner: unknown 7 | spec: 8 | type: unknown 9 | lifecycle: production 10 | owner: unknown 11 | system: Clever 12 | -------------------------------------------------------------------------------- /test/data/response_error_status.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/data/logout_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://idp.example.com/metadata.xml 4 | tstudent 5 | _2 6 | 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Clever Coding Standards Agreement 2 | 3 | - [ ] Author and Review Statement, "We agree this code adheres to our [Clever Global Coding Standards](https://app.getguru.com/folders/ibabX5oT/Engineering-Standards-Best-Practices?activeCard=a8a444f4-9149-4ec7-a0fd-8ba42519d93e) and other applicable [Coding Standards](https://app.getguru.com/folders/ibabX5oT/Engineering-Standards-Best-Practices)" 4 | 5 | ## JIRA 6 | [Link to JIRA](insert url here) 7 | 8 | ## Overview 9 | (insert PR description here) 10 | 11 | ## Testing 12 | (how did you test this) 13 | 14 | ## Rollout 15 | (are there any special rollout considerations? specific steps? risks?) 16 | 17 | ## Rollback 18 | (specific steps? risks?) -------------------------------------------------------------------------------- /.github/workflows/notify-ci-status.yml: -------------------------------------------------------------------------------- 1 | name: Notify CI status 2 | 3 | on: 4 | check_suite: 5 | types: [completed] 6 | status: 7 | 8 | jobs: 9 | call-workflow: 10 | if: >- 11 | (github.event.branches[0].name == github.event.repository.default_branch && 12 | (github.event.state == 'error' || github.event.state == 'failure')) || 13 | (github.event.check_suite.head_branch == github.event.repository.default_branch && 14 | github.event.check_suite.conclusion != 'success') 15 | uses: Clever/ci-scripts/.github/workflows/reusable-notify-ci-status.yml@master 16 | secrets: 17 | CIRCLE_CI_INTEGRATIONS_URL: ${{ secrets.CIRCLE_CI_INTEGRATIONS_URL }} 18 | CIRCLE_CI_INTEGRATIONS_USERNAME: ${{ secrets.CIRCLE_CI_INTEGRATIONS_USERNAME }} 19 | CIRCLE_CI_INTEGRATIONS_PASSWORD: ${{ secrets.CIRCLE_CI_INTEGRATIONS_PASSWORD }} 20 | SLACK_BOT_TOKEN: ${{ secrets.DAPPLE_BOT_TOKEN }} 21 | -------------------------------------------------------------------------------- /test/data/namespaced_assertion_with_empty_inclusivenamespaces.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/data/namespaced_assertion_with_inclusivenamespaces.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/data/empty_attribute_value.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://idp.example.com/metadata.xml 4 | 5 | tstudent 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/data/blank_assertion.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://idp.example.com/metadata.xml 4 | 5 | tstudent 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://sp.example.com/metadata.xml 13 | 14 | 15 | 16 | 17 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/data/test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDGTCCAgGgAwIBAgIJAO8HJfrb3JZeMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNV 3 | BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgwMTE3MTdaFw0y 4 | NDAzMTcwMTE3MTdaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 5 | ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFf1kCef6FTPMxQSoTh 6 | AZGFNmixh8fRDLsUo58pEFwztBRUPWS6s6Ql8mA75aAEdo4+JVyE8QPi5F+fWbnT 7 | oWkIw7E7YGl6s+EScSMQYHKCLq4mPHPMHtZspFowNp+Vax88SSUo1TKlpVNVIGim 8 | 8JQ5SRi3p0aD6UAiu9WxQ5s+xHnDwgvQiu3Sa4COl5NQjkC1r2LrhJnJQQiw0hsn 9 | 1nGgg15jEaDCZa8uPw1EtHv8smoZpjTbwRBVjXtzLskYIRyYLQjvqR+/QAd0XZca 10 | v0LdTwQR6obg/CwSgv7qG/WN6t25VIIGQDIUkVMBhLDmCh8QRpTvx1YWumSWW4D2 11 | k2kCAwEAAaNQME4wHQYDVR0OBBYEFLpo8Vz1m19xvPmzx+2wf2PaSTIpMB8GA1Ud 12 | IwQYMBaAFLpo8Vz1m19xvPmzx+2wf2PaSTIpMAwGA1UdEwQFMAMBAf8wDQYJKoZI 13 | hvcNAQEFBQADggEBALhwpLS6C+97nWrEICI5yetQjexCJGltMESg1llNYjsbIuJ/ 14 | S4XbrVzhN4nfNGMSbj8rb/9FT6TSru5QLjJQQmj38pqsWtEhR2vBLclqGqEcJfvP 15 | Mdn1qAJhJfhrs0KUpsX6xFTnSkNoyGxCP8Wh2C1L0NL5r+x58lkma5vL6ncwWYY+ 16 | 0C3bt1XbBRdeOZHUwuYTIcD+BCNixQiNor7KjO1TzpOb6V3m1SKHu8idDM5fUcKo 17 | oGbV3WuE7AJrAG5fvt59V9MtMPc2FklVFminfTeYKboEaxZJxuPDbQs2IyJ/0lI8 18 | P0Mv4LIKj4+OipQ/fGbZuE7cOioPKKl02dE7eCA= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /test/data/test2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDGTCCAgGgAwIBAgIJAJQd/RSI51tKMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNV 3 | BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgyMDMxMDNaFw0y 4 | NDAzMTcyMDMxMDNaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 5 | ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxerkURM4678nuft7LQ 6 | I7g5jySUHwHROCheAVt+kemVeg7JNFzPaF1AOm2n4S4xq4aI03/HW725sxZTJIit 7 | 6TBSiboC6yuN/cM/mzwjhbV+gCQRz2DrI7MkGGujn5bH+vu3qzxpXSoSqrkuHWrd 8 | eNGHLBP0C/0pHU2RZJOGG1h+S+tiW+EGKz1PItfL7mg8V2EhieUBYLgxGxVsNYwt 9 | L7dWcib7Y4476Yx25d34k1IgBrvkyo3yx1GizwG00+0FR3/ykMYOexwiZzCrKbZo 10 | z1Bf0itu9vqjbzDy9gbkEQBIcZxpE5GOwAtyLNKgBdSyFj3zbRTUIyOtNdTv5CN3 11 | 4WMCAwEAAaNQME4wHQYDVR0OBBYEFFIQ7r0sopn/h79pX1qiQaWzcMGoMB8GA1Ud 12 | IwQYMBaAFFIQ7r0sopn/h79pX1qiQaWzcMGoMAwGA1UdEwQFMAMBAf8wDQYJKoZI 13 | hvcNAQEFBQADggEBAHcMfEAswmSVRsRofaibLeP72Hm8zutb25ntpm3gcak+DikE 14 | 4ZwI/HGYw2YpzGZ9v8ysxc/egc7lLKn+yOlObRdIFJmXu5MSf0G6D5/NRv8RagCa 15 | 3x6KgjgZOTx5MNR8KX2y79bOupMMj/PnI4jA2jXbFFSUwz6MQFP/4VyhlpYqdhn3 16 | Qpuu8YVrW7KHcYm6RQHlrC70WCcfZEWLEHjU/uRwFK1+hMsULbbu3O8/zmJsU6O4 17 | b2ZbjCoPvsAZYPK0/OJYbyUxfpfHZ82KmF261HEKIchEWPkpiZivtrPfIOZFy6iV 18 | 4bt0PT/SGoIbKOxh0Nxxyt2mHnpd030tUXNYLTc= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "saml2-js", 3 | "version": "4.0.4", 4 | "description": "SAML 2.0 node helpers", 5 | "author": "Clever", 6 | "license": "Apache-2.0", 7 | "main": "index.js", 8 | "engines": { 9 | "node": ">=10.x" 10 | }, 11 | "scripts": { 12 | "build": "coffee --bare -c -o lib-js lib", 13 | "test": "NODE_ENV=test mocha --require coffeescript/register test/*.coffee", 14 | "test-cov": "NODE_ENV=test nyc --extension .coffee -r html -r text mocha --require coffeescript/register test/*.coffee", 15 | "prepare": "npm run build" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/Clever/saml2.git" 20 | }, 21 | "keywords": [ 22 | "saml", 23 | "node" 24 | ], 25 | "bugs": { 26 | "url": "https://github.com/Clever/saml2/issues" 27 | }, 28 | "devDependencies": { 29 | "coffeescript": "^1.12.7", 30 | "mocha": "^8.4.0", 31 | "nyc": "^15.0.0" 32 | }, 33 | "dependencies": { 34 | "@xmldom/xmldom": "^0.8.6", 35 | "async": "^3.2.0", 36 | "debug": "^4.3.0", 37 | "underscore": "^1.8.0", 38 | "xml-crypto": "^6.1.2", 39 | "xml-encryption": "^3.0.2", 40 | "xmlbuilder2": "^2.4.0", 41 | "xpath": "^0.0.34" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/data/no_subject.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | https://idp.example.com/metadata.xml 8 | 9 | 10 | https://sp.example.com/metadata.xml 11 | 12 | 13 | 14 | 15 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 16 | 17 | 18 | 19 | 20 | Test 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/data/test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBX9ZAnn+hUzzM 3 | UEqE4QGRhTZosYfH0Qy7FKOfKRBcM7QUVD1kurOkJfJgO+WgBHaOPiVchPED4uRf 4 | n1m506FpCMOxO2BperPhEnEjEGBygi6uJjxzzB7WbKRaMDaflWsfPEklKNUypaVT 5 | VSBopvCUOUkYt6dGg+lAIrvVsUObPsR5w8IL0Irt0muAjpeTUI5Ata9i64SZyUEI 6 | sNIbJ9ZxoINeYxGgwmWvLj8NRLR7/LJqGaY028EQVY17cy7JGCEcmC0I76kfv0AH 7 | dF2XGr9C3U8EEeqG4PwsEoL+6hv1jerduVSCBkAyFJFTAYSw5gofEEaU78dWFrpk 8 | lluA9pNpAgMBAAECggEAfi4XFBtYlOBHr9pEheh8qYQPOMl/HDeg4wJYsiaNclya 9 | iRle5jeduOK6AWmUMJI4+iA7KN/mlO6crnjAh608idkaOK/R/YH/lkH+aS7qgE3K 10 | QADbOYRcKvbBV8hWHFPXjo47/G9kjqPf+Tx25VLpcQ7gT6ynDjBNJ3iCsLH2t3lf 11 | M3rgdeRqauRrCvHb8zJzLgOFd+d5UZWGzcQxfSlRTkReBul2QPEK+GE3tLVVWWCg 12 | sC51teOHnPq6l0ymgFou6Z48e2QXXGc7I7ebYWIwjBQlHwhwT32q1uNB/xXyOHmh 13 | jJ5z7N8ZJk0mrtDZ8N3ClhMUdVH8+nm5G79WVonTwQKBgQDjaMR8B98s3QPOFoWG 14 | 3JK5xBw4dV2z7cTPr/qakA12E5vslqKjab51NQ1kzU7GyRWhNthv4iHM8KyerLH2 15 | GgZfYM4cve9uW5KOZKRPrBkvou3XBe/FFikRk19EvTL6BXqhnxyYYdOC6LfppGI9 16 | 8PbEGq0Z1BF0fbadw3Pmxvi5xQKBgQDZr6WTESfLHfXHJ6EmI3yvM3RBrUdojRY7 17 | WpwGcn6MkqnuFuTqkqJ1UUbB7wsDFvuBEXLvd3mgmWJYLditVvhhCxbqbPO2rj/B 18 | 1FC34FdMQLl2981ucz6qwTolaUwjBlhtoMnL+03hoJTG7lf2ZxlfbJZzXawMa0m/ 19 | 1RHHChyhVQKBgQDEPSJhDcHuywJ/kzvCtxD+sVbQ+abUn/fYaTnOq0SSgjVpokvS 20 | zGuIZTGbrPev3tKFffikA/W7Dm1HuCsR/j9FixoR/21gRDFiI0MPZamOTAEGLp9L 21 | 6eWivxPVE5er3ZKHafCZJsIJE52xRyNn5Epty79YrIIrjlhKJ+IaYdU9KQKBgAaC 22 | okkLskz40GjsXn1tgkUbHNb5/7C4x3lu9EudEPvTRxG/zYjWadVoYN1b8NBe15a8 23 | lttij1imPbK1bE2C1FrSohTQvVkxTObXGrLlGrdFGEbekl5DRBSHQt3rkENb5Tki 24 | Hebj1ShyTQDGEAtmefPIo5c/re2RJ9t829NAEishAoGAGOW5CPq7Q0tEvOVE+/br 25 | JXddPyZe++FB1e7i+iVYrA5F8wtvhVHsVsSxpm47XdAyAFdLdnttrnwzt3EA+QvB 26 | tsprKkdbwhTwaVKRDwnIAfwwpvONAV+/6X5W0UDJEmevDQZR8x74nBHWezdDv+lk 27 | Ig9R0ZWbG6k7TkdrLwTbs1c= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /test/data/test2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC8Xq5FETOOu/J7 3 | n7ey0CO4OY8klB8B0TgoXgFbfpHplXoOyTRcz2hdQDptp+EuMauGiNN/x1u9ubMW 4 | UySIrekwUom6Ausrjf3DP5s8I4W1foAkEc9g6yOzJBhro5+Wx/r7t6s8aV0qEqq5 5 | Lh1q3XjRhywT9Av9KR1NkWSThhtYfkvrYlvhBis9TyLXy+5oPFdhIYnlAWC4MRsV 6 | bDWMLS+3VnIm+2OOO+mMduXd+JNSIAa75MqN8sdRos8BtNPtBUd/8pDGDnscImcw 7 | qym2aM9QX9Irbvb6o28w8vYG5BEASHGcaRORjsALcizSoAXUshY9820U1CMjrTXU 8 | 7+Qjd+FjAgMBAAECggEAOIrTFLhNGZMg/iq7IVmI30unw/sSM6Fxkexly+j6M3tC 9 | 4B1VMmavlQ4qe6/gz9To/8Eie0CEMTcEorbiSISrcm3UGZm2raQ5f9of5rVi9U+7 10 | dxhBf34VgThcfDLpPIFavSQsqj2WUYK47E0DV4iTM5G3kWW4E4271gTGg+HFY5JA 11 | nv3f3cY9J4d0j/Jw9QbDElSVpxQw9/+KVsiae7fCqdIhTU9WtowbgAX6pjAxwL1F 12 | D7FJ6tccuOBdyyG32fVBWEhivYjYVyn6AuaIBkuZK2oLjQofkq+7W68aVh+CMpx4 13 | QoZtSh1sVaZ7X6o43yh11S8sd/LoqSNLOh9t6MmugQKBgQD5gGMmo53sOasar1f3 14 | bj9edXE4ZafDXFv88M2e2NQsCx0a2EPGc8Mx/JzH+4JcMrgiphDj4POOSIsEyq3B 15 | iHMFIU/4Fl/XS08aMTcx5qhrSZlT8wAQApPEWSOwhH0LKljqblVW9p3hSd2kP9ei 16 | na4FnOsjpZieNjPa7438+6QhGQKBgQDBRq7aGTPXj4BFEY/1Nq+5MVdOiOdohZKq 17 | tbT0jJcwAH0TBTWH/0NIh5u4vfy5CVkIQAM/vOl4VTu5aHwnX+yU2tANUEXvgGyi 18 | uAc96sW1COt28eDxoSP+ZZJk/GRqetvrItnAWJbWYzjn2xCG5+B/2Kom/IOoYCYd 19 | 0ZFFeVk52wKBgAobkGi9UiWCxJLFLbwhZEHQYjDVtXEtqbBalQntYNMT9C7lOgGt 20 | KOg6gqN7ZfGUQG9u6NpCf7tw5ujfySBBBd/cVKAJUAKp01+NRN4pqQMHrUWAX61G 21 | XXQj5FU/WM19/rIonB50yTqaQndn+rVky+sAS2pbSA6IxZsF/2uTSjfpAoGAc28p 22 | 420F/4rfi2Dv3/7neO41PNybiVutu3OHPj/x1GOWUBPeYvlcUCdeJDqkhEdG+5xv 23 | 1FOaBZqybwwuir3J6SW++RSmkGLdf1n2SU69AmDvcT0JoochnkE/7DyqJMZ4LrnD 24 | 4BOJE0ZzqFa4SjqXZQQcq+hJIfk7Crgt0Zamad0CgYAl51GpsFqtU/acA5xBrckU 25 | CB94urSYwdz4kjbZNoMkvp0FraKuSohD0jQuRv7GtxFaRxGLHClp4GzMjI6a03LS 26 | W41nVPjWvF1xoYABKDku0RYR4OYr/YfkVSFy797SnawJyMPfxBffSYyp6wJUe10b 27 | hpNq9wGUVe9umBSwAMqOmg== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /test/data/response_notbefore_future_decoded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | This data has no meaning. 7 | http://idp.example.com/metadata.xml 8 | 9 | tstudent 10 | 11 | 12 | 13 | 14 | 15 | 16 | https://sp.example.com/metadata.xml 17 | 18 | 19 | 20 | 21 | Test 22 | 23 | 24 | 25 | 26 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/data/response_no_audience_no_timing.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPgogICAgPHNhbWxwOlN0YXR1cz4KICAgICAgICA8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPgogICAgPC9zYW1scDpTdGF0dXM+CiAgICA8QXNzZXJ0aW9uIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iXzMiIElzc3VlSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zOTJaIiBWZXJzaW9uPSIyLjAiPgogICAgICAgIDxEYXRhIElEPSJfNSI+VGhpcyBkYXRhIGhhcyBubyBtZWFuaW5nLjwvRGF0YT4KICAgICAgICA8SXNzdWVyPmh0dHA6Ly9pZHAuZXhhbXBsZS5jb20vbWV0YWRhdGEueG1sPC9Jc3N1ZXI+CiAgICAgICAgPFN1YmplY3Q+CiAgICAgICAgICAgIDxOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPnRzdHVkZW50PC9OYW1lSUQ+CiAgICAgICAgICAgIDxTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI+CiAgICAgICAgICAgICAgICA8U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfNCIgTm90T25PckFmdGVyPSIyMDE0LTAzLTEyVDIxOjQwOjA1LjM5MloiIFJlY2lwaWVudD0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiIC8+CiAgICAgICAgICAgIDwvU3ViamVjdENvbmZpcm1hdGlvbj4KICAgICAgICA8L1N1YmplY3Q+CiAgICAgICAgPENvbmRpdGlvbnM+PC9Db25kaXRpb25zPgogICAgICAgIDxBdHRyaWJ1dGVTdGF0ZW1lbnQ+CiAgICAgICAgICAgIDxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZ2l2ZW5uYW1lIj4KICAgICAgICAgICAgICAgIDxBdHRyaWJ1dGVWYWx1ZT5UZXN0PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICAgICAgICAgPC9BdHRyaWJ1dGU+CiAgICAgICAgPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ+CiAgICAgICAgPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zNTRaIiBTZXNzaW9uSW5kZXg9Il8zIj4KICAgICAgICAgICAgPEF1dGhuQ29udGV4dD4KICAgICAgICAgICAgICAgIDxBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydDwvQXV0aG5Db250ZXh0Q2xhc3NSZWY+CiAgICAgICAgICAgIDwvQXV0aG5Db250ZXh0PgogICAgICAgIDwvQXV0aG5TdGF0ZW1lbnQ+CiAgICA8L0Fzc2VydGlvbj4KPC9zYW1scDpSZXNwb25zZT4K 2 | -------------------------------------------------------------------------------- /test/data/response_empty_audience_no_timing.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPgogICAgPHNhbWxwOlN0YXR1cz4KICAgICAgICA8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPgogICAgPC9zYW1scDpTdGF0dXM+CiAgICA8QXNzZXJ0aW9uIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iXzMiIElzc3VlSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zOTJaIiBWZXJzaW9uPSIyLjAiPgogICAgICAgIDxEYXRhIElEPSJfNSI+VGhpcyBkYXRhIGhhcyBubyBtZWFuaW5nLjwvRGF0YT4KICAgICAgICA8SXNzdWVyPmh0dHA6Ly9pZHAuZXhhbXBsZS5jb20vbWV0YWRhdGEueG1sPC9Jc3N1ZXI+CiAgICAgICAgPFN1YmplY3Q+CiAgICAgICAgICAgIDxOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPnRzdHVkZW50PC9OYW1lSUQ+CiAgICAgICAgICAgIDxTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI+CiAgICAgICAgICAgICAgICA8U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfNCIgTm90T25PckFmdGVyPSIyMDE0LTAzLTEyVDIxOjQwOjA1LjM5MloiIFJlY2lwaWVudD0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiIC8+CiAgICAgICAgICAgIDwvU3ViamVjdENvbmZpcm1hdGlvbj4KICAgICAgICA8L1N1YmplY3Q+CiAgICAgICAgPENvbmRpdGlvbnM+CiAgICAgICAgICAgIDxBdWRpZW5jZVJlc3RyaWN0aW9uPgogICAgICAgICAgICAgICAgPEF1ZGllbmNlPjwvQXVkaWVuY2U+CiAgICAgICAgICAgIDwvQXVkaWVuY2VSZXN0cmljdGlvbj4KICAgICAgICA8L0NvbmRpdGlvbnM+CiAgICAgICAgPEF0dHJpYnV0ZVN0YXRlbWVudD4KICAgICAgICAgICAgPEF0dHJpYnV0ZSBOYW1lPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9naXZlbm5hbWUiPgogICAgICAgICAgICAgICAgPEF0dHJpYnV0ZVZhbHVlPlRlc3Q8L0F0dHJpYnV0ZVZhbHVlPgogICAgICAgICAgICA8L0F0dHJpYnV0ZT4KICAgICAgICA8L0F0dHJpYnV0ZVN0YXRlbWVudD4KICAgICAgICA8QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE0LTAzLTEyVDIxOjM1OjA1LjM1NFoiIFNlc3Npb25JbmRleD0iXzMiPgogICAgICAgICAgICA8QXV0aG5Db250ZXh0PgogICAgICAgICAgICAgICAgPEF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOlBhc3N3b3JkUHJvdGVjdGVkVHJhbnNwb3J0PC9BdXRobkNvbnRleHRDbGFzc1JlZj4KICAgICAgICAgICAgPC9BdXRobkNvbnRleHQ+CiAgICAgICAgPC9BdXRoblN0YXRlbWVudD4KICAgIDwvQXNzZXJ0aW9uPgo8L3NhbWxwOlJlc3BvbnNlPgo= 2 | -------------------------------------------------------------------------------- /test/data/good_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | O=Internet Widgits Pty Ltd 18 | 17223777059262469726 19 | 20 | 21 | 22 | 23 | ql07diGZymd3QR1wTMOt6n5TbWOUmPg7Oumx1dtzfr75eYELnz3eHuwWHJ8r6ZjK+Oac5Qa7blluei7VTkod/En8JvUn63yoPNtFMWciL38bjPE9bkWBi4qugptmhOSg2nAjqUNu1n5DfPN32AB7VAmk6lfe+Q29vlHbliPfAIBxUpxZHUe4aGcHG7E0+telG/Zjy5sZXnLyrSHrOenkdBEDkUQf5jiIDgphWeEx3O2/wdgwTLpjMWX2Dk27BxivGitzcd/RBHUAA4LGEqsx6p7LLEzrlxwpA0818bhKDL1MT8Y4bfbkfDtj5rsqG4ZcYlembMday5Te4e5rGxnH2A== 24 | 25 | 26 | 27 | 28 | KIwhFfRvambizmOl1TCmbYZF6E/62Ye16byOe+G2Ruu8shHsSH1yc5HuzOQ4eQVtWn3rSU7Q8iNJQGPWbxhxc4KGBvUhAYvK7dpNZ5ZNoQNP0ABE3MLr5d5uo5KhMk+TudBj8rh4FiO0UnsRns3Xd+4c9kf3o7rTw7FT05ll7QGAxCOwEeV54El542FQ+RKgVXoNMHaHZFZeYG8LcrKC7lCq9wuTqe6md1rA+JOhqXle8O0jqqAzYhT9VdR9iq0X 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /test/data/response_audience_no_timing.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPgogICAgPHNhbWxwOlN0YXR1cz4KICAgICAgICA8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPgogICAgPC9zYW1scDpTdGF0dXM+CiAgICA8QXNzZXJ0aW9uIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iXzMiIElzc3VlSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zOTJaIiBWZXJzaW9uPSIyLjAiPgogICAgICAgIDxEYXRhIElEPSJfNSI+VGhpcyBkYXRhIGhhcyBubyBtZWFuaW5nLjwvRGF0YT4KICAgICAgICA8SXNzdWVyPmh0dHA6Ly9pZHAuZXhhbXBsZS5jb20vbWV0YWRhdGEueG1sPC9Jc3N1ZXI+CiAgICAgICAgPFN1YmplY3Q+CiAgICAgICAgICAgIDxOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPnRzdHVkZW50PC9OYW1lSUQ+CiAgICAgICAgICAgIDxTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI+CiAgICAgICAgICAgICAgICA8U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfNCIgTm90T25PckFmdGVyPSIyMDE0LTAzLTEyVDIxOjQwOjA1LjM5MloiIFJlY2lwaWVudD0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiIC8+CiAgICAgICAgICAgIDwvU3ViamVjdENvbmZpcm1hdGlvbj4KICAgICAgICA8L1N1YmplY3Q+CiAgICAgICAgPENvbmRpdGlvbnM+CiAgICAgICAgICAgIDxBdWRpZW5jZVJlc3RyaWN0aW9uPgogICAgICAgICAgICAgICAgPEF1ZGllbmNlPmh0dHBzOi8vc3AuZXhhbXBsZS5jb20vbWV0YWRhdGEueG1sPC9BdWRpZW5jZT4KICAgICAgICAgICAgPC9BdWRpZW5jZVJlc3RyaWN0aW9uPgogICAgICAgIDwvQ29uZGl0aW9ucz4KICAgICAgICA8QXR0cmlidXRlU3RhdGVtZW50PgogICAgICAgICAgICA8QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2dpdmVubmFtZSI+CiAgICAgICAgICAgICAgICA8QXR0cmlidXRlVmFsdWU+VGVzdDwvQXR0cmlidXRlVmFsdWU+CiAgICAgICAgICAgIDwvQXR0cmlidXRlPgogICAgICAgIDwvQXR0cmlidXRlU3RhdGVtZW50PgogICAgICAgIDxBdXRoblN0YXRlbWVudCBBdXRobkluc3RhbnQ9IjIwMTQtMDMtMTJUMjE6MzU6MDUuMzU0WiIgU2Vzc2lvbkluZGV4PSJfMyI+CiAgICAgICAgICAgIDxBdXRobkNvbnRleHQ+CiAgICAgICAgICAgICAgICA8QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L0F1dGhuQ29udGV4dENsYXNzUmVmPgogICAgICAgICAgICA8L0F1dGhuQ29udGV4dD4KICAgICAgICA8L0F1dGhuU3RhdGVtZW50PgogICAgPC9Bc3NlcnRpb24+Cjwvc2FtbHA6UmVzcG9uc2U+Cg== 2 | -------------------------------------------------------------------------------- /test/data/unsigned_assertion.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://idp.example.com/metadata.xml 4 | 5 | tstudent 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://sp.example.com/metadata.xml 13 | 14 | 15 | 16 | 17 | Test 18 | 19 | 20 | tstudent@example.com 21 | 22 | 23 | tstudent 24 | 25 | 26 | CN=Students,CN=Users,DC=idp,DC=example,DC=com 27 | 28 | 29 | Student 30 | 31 | 32 | Test Student 33 | 34 | 35 | 36 | 37 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/data/good_assertion_signed_data.xml: -------------------------------------------------------------------------------- 1 | 2 | http://idp.example.com/metadata.xml 3 | 4 | 5 | tstudent 6 | 7 | 8 | 9 | 10 | 11 | 12 | https://sp.example.com/metadata.xml 13 | 14 | 15 | 16 | 17 | Test 18 | 19 | 20 | tstudent@example.com 21 | 22 | 23 | tstudent 24 | 25 | 26 | CN=Students,CN=Users,DC=idp,DC=example,DC=com 27 | 28 | 29 | Student 30 | 31 | 32 | Test Student 33 | 34 | 35 | 36 | 37 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/data/response_notbefore_future.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPgogICAgPHNhbWxwOlN0YXR1cz4KICAgICAgICA8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPgogICAgPC9zYW1scDpTdGF0dXM+CiAgICA8QXNzZXJ0aW9uIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iXzMiIElzc3VlSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zOTJaIiBWZXJzaW9uPSIyLjAiPgogICAgICAgIDxEYXRhIElEPSJfNSI+VGhpcyBkYXRhIGhhcyBubyBtZWFuaW5nLjwvRGF0YT4KICAgICAgICA8SXNzdWVyPmh0dHA6Ly9pZHAuZXhhbXBsZS5jb20vbWV0YWRhdGEueG1sPC9Jc3N1ZXI+CiAgICAgICAgPFN1YmplY3Q+CiAgICAgICAgICAgIDxOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPnRzdHVkZW50PC9OYW1lSUQ+CiAgICAgICAgICAgIDxTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI+CiAgICAgICAgICAgICAgICA8U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfNCIgTm90T25PckFmdGVyPSIyMDE0LTAzLTEyVDIxOjQwOjA1LjM5MloiIFJlY2lwaWVudD0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiIC8+CiAgICAgICAgICAgIDwvU3ViamVjdENvbmZpcm1hdGlvbj4KICAgICAgICA8L1N1YmplY3Q+CiAgICAgICAgPENvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDU0LTAzLTEyVDIxOjM1OjA1LjM4N1oiIE5vdE9uT3JBZnRlcj0iMjA1NC0wMy0xMlQyMjozNTowNS4zODdaIj4KICAgICAgICAgICAgPEF1ZGllbmNlUmVzdHJpY3Rpb24+CiAgICAgICAgICAgICAgICA8QXVkaWVuY2U+aHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9tZXRhZGF0YS54bWw8L0F1ZGllbmNlPgogICAgICAgICAgICA8L0F1ZGllbmNlUmVzdHJpY3Rpb24+CiAgICAgICAgPC9Db25kaXRpb25zPgogICAgICAgIDxBdHRyaWJ1dGVTdGF0ZW1lbnQ+CiAgICAgICAgICAgIDxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZ2l2ZW5uYW1lIj4KICAgICAgICAgICAgICAgIDxBdHRyaWJ1dGVWYWx1ZT5UZXN0PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICAgICAgICAgPC9BdHRyaWJ1dGU+CiAgICAgICAgPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ+CiAgICAgICAgPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zNTRaIiBTZXNzaW9uSW5kZXg9Il8zIj4KICAgICAgICAgICAgPEF1dGhuQ29udGV4dD4KICAgICAgICAgICAgICAgIDxBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydDwvQXV0aG5Db250ZXh0Q2xhc3NSZWY+CiAgICAgICAgICAgIDwvQXV0aG5Db250ZXh0PgogICAgICAgIDwvQXV0aG5TdGF0ZW1lbnQ+CiAgICA8L0Fzc2VydGlvbj4KPC9zYW1scDpSZXNwb25zZT4K 2 | -------------------------------------------------------------------------------- /test/data/empty_session_index.xml: -------------------------------------------------------------------------------- 1 | PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgRGVzdGluYXRpb249Imh0dHBzOi8vc3AuZXhhbXBsZS5jb20vYXNzZXJ0IiBJRD0iXzIiIEluUmVzcG9uc2VUbz0iXzEiIFZlcnNpb249IjIuMCIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCI+DQogIDxzYW1scDpTdGF0dXM+DQogICAgPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPg0KICA8L3NhbWxwOlN0YXR1cz4NCiAgPHNhbWw6QXNzZXJ0aW9uIElEPSJfMyIgSXNzdWVJbnN0YW50PSIyMDE2LTAyLTEwVDIxOjEyOjA5WiIgVmVyc2lvbj0iMi4wIiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiPg0KICAgIDxzYW1sOklzc3Vlcj5odHRwczovL2lkcC5leGFtcGxlLmNvbS9tZXRhZGF0YS54bWw8L3NhbWw6SXNzdWVyPg0KICAgIDxzYW1sOlN1YmplY3Q+DQogICAgICA8c2FtbDpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDplbWFpbEFkZHJlc3MiLz4NCiAgICAgIDxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj4NCiAgICAgICAgPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfMSIgTm90T25PckFmdGVyPSIyMDE2LTAyLTEwVDIxOjE1OjA5WiIgUmVjaXBpZW50PSIiLz4NCiAgICAgIDwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPg0KICAgIDwvc2FtbDpTdWJqZWN0Pg0KICAgIDxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDE2LTAyLTEwVDIxOjA5OjA5WiIgTm90T25PckFmdGVyPSIyMDE2LTAyLTEwVDIxOjE1OjA5WiI+DQogICAgICA8c2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgICAgICA8c2FtbDpBdWRpZW5jZT5odHRwczovL3NwLmV4YW1wbGUuY29tL21ldGFkYXRhLnhtbDwvc2FtbDpBdWRpZW5jZT4NCiAgICAgIDwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgIDwvc2FtbDpDb25kaXRpb25zPg0KICAgIDxzYW1sOkF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNi0wMi0xMFQyMToxMjowOFoiIFNlc3Npb25Ob3RPbk9yQWZ0ZXI9IjIwMTYtMDItMTFUMjE6MTI6MDlaIj4NCiAgICAgIDxzYW1sOkF1dGhuQ29udGV4dD4NCiAgICAgICAgPHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+DQogICAgICA8L3NhbWw6QXV0aG5Db250ZXh0Pg0KICAgIDwvc2FtbDpBdXRoblN0YXRlbWVudD4NCiAgICA8c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQogICAgICA8QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2dpdmVubmFtZSI+DQogICAgICAgIDxBdHRyaWJ1dGVWYWx1ZT5UZXN0PC9BdHRyaWJ1dGVWYWx1ZT4NCiAgICAgIDwvQXR0cmlidXRlPg0KICAgIDwvc2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQogIDwvc2FtbDpBc3NlcnRpb24+DQo8L3NhbWxwOlJlc3BvbnNlPg== 2 | -------------------------------------------------------------------------------- /test/data/empty_nameid.xml: -------------------------------------------------------------------------------- 1 | PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgRGVzdGluYXRpb249Imh0dHBzOi8vc3AuZXhhbXBsZS5jb20vYXNzZXJ0IiBJRD0iXzIiIEluUmVzcG9uc2VUbz0iXzEiIFZlcnNpb249IjIuMCIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCI+DQogIDxzYW1scDpTdGF0dXM+DQogICAgPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPg0KICA8L3NhbWxwOlN0YXR1cz4NCiAgPHNhbWw6QXNzZXJ0aW9uIElEPSJfMyIgSXNzdWVJbnN0YW50PSIyMDE2LTAyLTEwVDIxOjEyOjA5WiIgVmVyc2lvbj0iMi4wIiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiPg0KICAgIDxzYW1sOklzc3Vlcj5odHRwczovL2lkcC5leGFtcGxlLmNvbS9tZXRhZGF0YS54bWw8L3NhbWw6SXNzdWVyPg0KICAgIDxzYW1sOlN1YmplY3Q+DQogICAgICA8c2FtbDpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDplbWFpbEFkZHJlc3MiLz4NCiAgICAgIDxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj4NCiAgICAgICAgPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfMSIgTm90T25PckFmdGVyPSIyMDE2LTAyLTEwVDIxOjE1OjA5WiIgUmVjaXBpZW50PSIiLz4NCiAgICAgIDwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPg0KICAgIDwvc2FtbDpTdWJqZWN0Pg0KICAgIDxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDE2LTAyLTEwVDIxOjA5OjA5WiIgTm90T25PckFmdGVyPSIyMDE2LTAyLTEwVDIxOjE1OjA5WiI+DQogICAgICA8c2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgICAgICA8c2FtbDpBdWRpZW5jZT5odHRwczovL3NwLmV4YW1wbGUuY29tL21ldGFkYXRhLnhtbDwvc2FtbDpBdWRpZW5jZT4NCiAgICAgIDwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgIDwvc2FtbDpDb25kaXRpb25zPg0KICAgIDxzYW1sOkF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNi0wMi0xMFQyMToxMjowOFoiIFNlc3Npb25JbmRleD0iXzQiIFNlc3Npb25Ob3RPbk9yQWZ0ZXI9IjIwMTYtMDItMTFUMjE6MTI6MDlaIj4NCiAgICAgIDxzYW1sOkF1dGhuQ29udGV4dD4NCiAgICAgICAgPHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+DQogICAgICA8L3NhbWw6QXV0aG5Db250ZXh0Pg0KICAgIDwvc2FtbDpBdXRoblN0YXRlbWVudD4NCiAgICA8c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQogICAgICA8QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2dpdmVubmFtZSI+DQogICAgICAgIDxBdHRyaWJ1dGVWYWx1ZT5UZXN0PC9BdHRyaWJ1dGVWYWx1ZT4NCiAgICAgIDwvQXR0cmlidXRlPg0KICAgIDwvc2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQogIDwvc2FtbDpBc3NlcnRpb24+DQo8L3NhbWxwOlJlc3BvbnNlPg== -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | references: 4 | defaults: &defaults 5 | working_directory: ~/Clever/saml2 6 | environment: 7 | CIRCLE_ARTIFACTS: /tmp/circleci-artifacts 8 | CIRCLE_TEST_REPORTS: /tmp/circleci-test-results 9 | 10 | orbs: 11 | node: circleci/node@5.0.3 12 | 13 | executors: 14 | tester: 15 | <<: *defaults 16 | docker: 17 | - image: cimg/base:stable 18 | node-v12: 19 | <<: *defaults 20 | docker: 21 | - image: cimg/node:12.22 22 | 23 | commands: 24 | clone-ci-scripts: 25 | description: Clone the ci-scripts repo 26 | steps: 27 | - run: 28 | name: Clone ci-scripts 29 | command: cd .. && git clone --depth 1 -v https://github.com/Clever/ci-scripts.git && cd ci-scripts && git show --oneline -s 30 | 31 | jobs: 32 | build: 33 | executor: node-v12 34 | steps: 35 | - checkout 36 | - run: npm install 37 | - persist_to_workspace: 38 | root: ~/Clever 39 | paths: ["."] 40 | 41 | test: 42 | parameters: 43 | node-version: 44 | type: string 45 | executor: tester 46 | steps: 47 | - checkout 48 | - node/install: 49 | node-version: << parameters.node-version >> 50 | - node/install-packages: 51 | with-cache: false 52 | override-ci-command: npm install 53 | - run: npm run test 54 | 55 | publish: 56 | executor: node-v12 57 | steps: 58 | - attach_workspace: 59 | at: ~/Clever 60 | - clone-ci-scripts 61 | - run: if [ "${CIRCLE_BRANCH}" == "master" ]; then ../ci-scripts/circleci/npm-publish $NPM_TOKEN .; fi; 62 | 63 | publish_utility: 64 | executor: node-v12 65 | steps: 66 | - attach_workspace: 67 | at: ~/Clever 68 | - clone-ci-scripts 69 | - run: ../ci-scripts/circleci/catalog-sync $CATAPULT_URL $CATAPULT_USER $CATAPULT_PASS saml2 utility 70 | workflows: 71 | version: 2 72 | build_test_publish: 73 | jobs: 74 | - build 75 | - test: 76 | matrix: 77 | parameters: 78 | node-version: ["14", "16", "18", "20", "22", "24", "latest"] 79 | - publish: 80 | requires: 81 | - build 82 | - test 83 | - publish_utility: 84 | requires: 85 | - build 86 | - test 87 | -------------------------------------------------------------------------------- /test/data/response_unsigned_assertion.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPg0KICA8c2FtbHA6U3RhdHVzPg0KICAgIDxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz4NCiAgPC9zYW1scDpTdGF0dXM+DQo8QXNzZXJ0aW9uIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iXzMiIElzc3VlSW5zdGFudD0iMjAxNC0wMy0xMlQyMTozNTowNS4zOTJaIiBWZXJzaW9uPSIyLjAiPg0KICA8RGF0YSBJRD0iXzUiPlRoaXMgZGF0YSBoYXMgbm8gbWVhbmluZy48L0RhdGE+DQogIDxJc3N1ZXI+aHR0cDovL2lkcC5leGFtcGxlLmNvbS9tZXRhZGF0YS54bWw8L0lzc3Vlcj4NCiAgPFN1YmplY3Q+DQogICAgPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OnRyYW5zaWVudCI+dHN0dWRlbnQ8L05hbWVJRD4NCiAgICA8U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPg0KICAgICAgPFN1YmplY3RDb25maXJtYXRpb25EYXRhIEluUmVzcG9uc2VUbz0iXzQiIE5vdE9uT3JBZnRlcj0iMjAxNC0wMy0xMlQyMTo0MDowNS4zOTJaIiBSZWNpcGllbnQ9Imh0dHBzOi8vc3AuZXhhbXBsZS5jb20vYXNzZXJ0Ii8+DQogICAgPC9TdWJqZWN0Q29uZmlybWF0aW9uPg0KICA8L1N1YmplY3Q+DQogIDxDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAxNC0wMy0xMlQyMTozNTowNS4zODdaIiBOb3RPbk9yQWZ0ZXI9IjIwMTQtMDMtMTJUMjI6MzU6MDUuMzg3WiI+DQogICAgPEF1ZGllbmNlUmVzdHJpY3Rpb24+DQogICAgICA8QXVkaWVuY2U+aHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9tZXRhZGF0YS54bWw8L0F1ZGllbmNlPg0KICAgIDwvQXVkaWVuY2VSZXN0cmljdGlvbj4NCiAgPC9Db25kaXRpb25zPg0KICA8QXR0cmlidXRlU3RhdGVtZW50Pg0KICAgIDxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZ2l2ZW5uYW1lIj4NCiAgICAgIDxBdHRyaWJ1dGVWYWx1ZT5UZXN0PC9BdHRyaWJ1dGVWYWx1ZT4NCiAgICA8L0F0dHJpYnV0ZT4NCiAgPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ+DQogIDxBdXRoblN0YXRlbWVudCBBdXRobkluc3RhbnQ9IjIwMTQtMDMtMTJUMjE6MzU6MDUuMzU0WiIgU2Vzc2lvbkluZGV4PSJfMyI+DQogICAgPEF1dGhuQ29udGV4dD4NCiAgICAgIDxBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydDwvQXV0aG5Db250ZXh0Q2xhc3NSZWY+DQogICAgPC9BdXRobkNvbnRleHQ+DQogIDwvQXV0aG5TdGF0ZW1lbnQ+DQo8U2lnbmF0dXJlIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48U2lnbmVkSW5mbz48Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz48UmVmZXJlbmNlIFVSST0iI181Ij48VHJhbnNmb3Jtcz48VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9UcmFuc2Zvcm1zPjxEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIvPjxEaWdlc3RWYWx1ZT4xaWVPaWxkbnBmUml1NlZBZzBjeHBLTjlkZ1E9PC9EaWdlc3RWYWx1ZT48L1JlZmVyZW5jZT48L1NpZ25lZEluZm8+PFNpZ25hdHVyZVZhbHVlPkRZL3MzTmF6V2Q2VWpGVzA2TkdIbTUxSEtrclp3aHFRTXF5ZWdGY0JBT1VFd2VKZW95ekVmOWJaUmRacSs4cFdlNUNVT2NJWE1SWTRicjFNbFNnSEVDYzNYckI0aUNLYTdMbkFqRytnWXFDNnZwVGlsSERxaTJoRkhSTUZWTnMwZS9RVkRwNmkvWUg3a3RWcTJpY0VDNzNmNkJKSldlZjltaWxnVnN1Q05GU0k1OHM2bEhGd0VyVGFKV2tBd2grVHhlTWFPV0UyYmdkQTJ0Mlh4QUFBOW1LSk5VaGpsQUs1OGFiNjhnbVhwdlQ3NUtNSlcybzdaQzVyZmJmVXREU1NvOG51aU9WREo0MFZZcGxla3VjdGlrTWMyYUVrdTJweW1NV1Z4SXZUaW03TVBxSVMrMzRuczJDOXFJTEtlUkZZa24wY25qOFZybUtta0oyUUxJYjFaUT09PC9TaWduYXR1cmVWYWx1ZT48L1NpZ25hdHVyZT48L0Fzc2VydGlvbj4NCjwvc2FtbHA6UmVzcG9uc2U+ -------------------------------------------------------------------------------- /test/data/good_assertion_no_session_index.xml: -------------------------------------------------------------------------------- 1 | 2 | http://idp.example.com/metadata.xml 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | bzIFJU/QWpxqY/8wYIi1MhtaIYY= 13 | 14 | 15 | LUAuLKGIAyGcMldwk2gTbyrcrLRZhJZkfK/PgxmHRxJ3lI+xn1A1n8RvHV8OWhFCG7sdTuSEDcqHN6nBQpZZaJ18qIkupV5vwPm3Mu6HFYSKAOrn245sjcjFCG9lJgxOiyeozE8QZ3FNeLnMYuSl7zB9nmjFQJMcHxmrVoCINjbokzjpNiXw56jUqlLJ+kT9ToKjHgcjChlJX75yYSuv+JT8s1UBT3PM7KoqTl97/KS2y7NQR+3hm9vk8uzcrrXgqr7WnizS17FG9q+ivic7w04F/S+yT3FVP5s0TCuck7ER5cYxYEzh+YWF6T7Ar0urn/2gfPMZ32l3tm0KLNaSMw== 16 | 17 | 18 | 19 | 20 | 21 | tstudent 22 | 23 | 24 | 25 | 26 | 27 | 28 | https://sp.example.com/metadata.xml 29 | 30 | 31 | 32 | 33 | Test 34 | 35 | 36 | tstudent@example.com 37 | 38 | 39 | tstudent 40 | 41 | 42 | CN=Students,CN=Users,DC=idp,DC=example,DC=com 43 | 44 | 45 | Student 46 | 47 | 48 | Test Student 49 | 50 | 51 | 52 | 53 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /test/data/good_assertion.xml: -------------------------------------------------------------------------------- 1 | 2 | http://idp.example.com/metadata.xml 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | /otGbaGvPsxvHXpaxzS5QXWvJRQ= 13 | 14 | 15 | BOeWxdgnJw1hx2Vvwja947xDb8/5T+zFI1o8xw4aPH7lxxWVXk9s8UOYP99yjH1c+2iFNzm5VNaZG5op08bxZSHRsgU4DQ35jMO/D8Ra42zKRXHOd0TunjZ8WQhYV8RoESHKjsUGyjLhlavFMyUDMr+O4d3GSn+r5lBlw40zwyn7f7j+or8gyemp618vlTXrT31L9+xZaLRKgF8I0ZC4WpfJZGWOj7x4u/X1xfggf0jtDmbLrY8aMIXrH1cn46VnMqIrEwMC1zIJfPU+GeBQRDgcGhzq2ttaA2v3rGMzamk3qlqgMOEbI3kBWXSTuddPRkn5GVhQkb9nGa/0neAWzQ== 16 | 17 | 18 | 19 | 20 | 21 | tstudent 22 | 23 | 24 | 25 | 26 | 27 | 28 | https://sp.example.com/metadata.xml 29 | 30 | 31 | 32 | 33 | Test 34 | 35 | 36 | tstudent@example.com 37 | 38 | 39 | tstudent 40 | 41 | 42 | CN=Students,CN=Users,DC=idp,DC=example,DC=com 43 | 44 | 45 | Student 46 | 47 | 48 | Test Student 49 | 50 | 51 | 52 | 53 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 54 | 55 | 56 | -------------------------------------------------------------------------------- /test/data/response_external_signed_assertion.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPg0KICA8c2FtbHA6U3RhdHVzPg0KICAgIDxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz4NCiAgPC9zYW1scDpTdGF0dXM+DQogIDxBc3NlcnRpb24geG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfMyIgSXNzdWVJbnN0YW50PSIyMDE0LTAzLTEyVDIxOjM1OjA1LjM5MloiIFZlcnNpb249IjIuMCI+DQogICAgPERhdGEgSUQ9Il81Ij5UaGlzIGRhdGEgaGFzIG5vIG1lYW5pbmcuPC9EYXRhPg0KICAgIDxJc3N1ZXI+aHR0cDovL2lkcC5leGFtcGxlLmNvbS9tZXRhZGF0YS54bWw8L0lzc3Vlcj4NCiAgICA8U3ViamVjdD4NCiAgICAgIDxOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPnRzdHVkZW50PC9OYW1lSUQ+DQogICAgICA8U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPg0KCTxTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBJblJlc3BvbnNlVG89Il80IiBOb3RPbk9yQWZ0ZXI9IjIwMTQtMDMtMTJUMjE6NDA6MDUuMzkyWiIgUmVjaXBpZW50PSJodHRwczovL3NwLmV4YW1wbGUuY29tL2Fzc2VydCIvPg0KICAgICAgPC9TdWJqZWN0Q29uZmlybWF0aW9uPg0KICAgIDwvU3ViamVjdD4NCiAgICA8Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMTQtMDMtMTJUMjE6MzU6MDUuMzg3WiIgTm90T25PckFmdGVyPSIyMDE0LTAzLTEyVDIyOjM1OjA1LjM4N1oiPg0KICAgICAgPEF1ZGllbmNlUmVzdHJpY3Rpb24+DQoJPEF1ZGllbmNlPmh0dHBzOi8vc3AuZXhhbXBsZS5jb20vbWV0YWRhdGEueG1sPC9BdWRpZW5jZT4NCiAgICAgIDwvQXVkaWVuY2VSZXN0cmljdGlvbj4NCiAgICA8L0NvbmRpdGlvbnM+DQogICAgPEF0dHJpYnV0ZVN0YXRlbWVudD4NCiAgICAgIDxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZ2l2ZW5uYW1lIj4NCgk8QXR0cmlidXRlVmFsdWU+VGVzdDwvQXR0cmlidXRlVmFsdWU+DQogICAgICA8L0F0dHJpYnV0ZT4NCiAgICA8L0F0dHJpYnV0ZVN0YXRlbWVudD4NCiAgICA8QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE0LTAzLTEyVDIxOjM1OjA1LjM1NFoiIFNlc3Npb25JbmRleD0iXzMiPg0KICAgICAgPEF1dGhuQ29udGV4dD4NCgk8QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L0F1dGhuQ29udGV4dENsYXNzUmVmPg0KICAgICAgPC9BdXRobkNvbnRleHQ+DQogICAgPC9BdXRoblN0YXRlbWVudD4NCiAgPC9Bc3NlcnRpb24+DQo8U2lnbmF0dXJlIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48U2lnbmVkSW5mbz48Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+PFJlZmVyZW5jZSBVUkk9IiNfMiI+PFRyYW5zZm9ybXM+PFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvVHJhbnNmb3Jtcz48RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiLz48RGlnZXN0VmFsdWU+S1dPVllha0JVQXgzbFhqQm5BeExiRHJWRzhRPTwvRGlnZXN0VmFsdWU+PC9SZWZlcmVuY2U+PC9TaWduZWRJbmZvPjxTaWduYXR1cmVWYWx1ZT5qQjBHbW85anVmZk9VVXY5bWIvaU1iSXA5YjFxZTkxL0RtMUZCcytTb0tMTzh1KzZ4T0xNTHArQ1h2bmxMK3VpVFlnVE1HYmRGWjZlNnpFSG96TFNCeWpOWjQ3aWVHVG9ocGh0c2VqQitZMTdDNUZjclQxS05ZVWtPMkNZd0l6cSt4TVJwK0MrQXIwQTJoRzRiMktxT0drc2JrZWp0TDY3bVNiNG9KaExKTUZ4Mk5FaU5VN1E2eTlGeHhJZW5IS0hXUFgzeEVxdHFVU3RvcXhRY2p3aWpYTm9IMUdKZWJUWEsvQW9NZG10bTMzS0pON1ova1lkWlFZdndGRmg2dzZHZTdVZVB4OVVXQmtUZUNSLytNb25RTG1lUzQwbDBHb3ZRU3BiYkdZd0RUbWlXYmZwVFlYdTFGRGN1cVMrTFkxM1RwTFpJai9BVHRHajM3Qm94Uk4zVXc9PTwvU2lnbmF0dXJlVmFsdWU+PC9TaWduYXR1cmU+PC9zYW1scDpSZXNwb25zZT4= -------------------------------------------------------------------------------- /test/data/response_notbefore_future_encrypted_decoded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 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 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/data/good_assertion_commented_out_digest.xml: -------------------------------------------------------------------------------- 1 | 2 | http://idp.example.com/metadata.xml 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | /otGbaGvPsxvHXpaxzS5QXWvJRQ= 13 | 14 | 15 | BOeWxdgnJw1hx2Vvwja947xDb8/5T+zFI1o8xw4aPH7lxxWVXk9s8UOYP99yjH1c+2iFNzm5VNaZG5op08bxZSHRsgU4DQ35jMO/D8Ra42zKRXHOd0TunjZ8WQhYV8RoESHKjsUGyjLhlavFMyUDMr+O4d3GSn+r5lBlw40zwyn7f7j+or8gyemp618vlTXrT31L9+xZaLRKgF8I0ZC4WpfJZGWOj7x4u/X1xfggf0jtDmbLrY8aMIXrH1cn46VnMqIrEwMC1zIJfPU+GeBQRDgcGhzq2ttaA2v3rGMzamk3qlqgMOEbI3kBWXSTuddPRkn5GVhQkb9nGa/0neAWzQ== 16 | 17 | 18 | 19 | 20 | 21 | tstudent 22 | 23 | 24 | 25 | 26 | 27 | 28 | https://sp.example.com/metadata.xml 29 | 30 | 31 | 32 | 33 | Test 34 | 35 | 36 | tstudent@example.com 37 | 38 | 39 | tstudent 40 | 41 | 42 | CN=Students,CN=Users,DC=idp,DC=example,DC=com 43 | 44 | 45 | Student 46 | 47 | 48 | Test Student 49 | 50 | 51 | 52 | 53 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 54 | 55 | 56 | -------------------------------------------------------------------------------- /test/data/good_assertion_explicit_namespaces.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://idp.example.com/metadata.xml 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | bzIFJU/QWpxqY/8wYIi1MhtaIYY= 14 | 15 | 16 | LUAuLKGIAyGcMldwk2gTbyrcrLRZhJZkfK/PgxmHRxJ3lI+xn1A1n8RvHV8OWhFCG7sdTuSEDcqHN6nBQpZZaJ18qIkupV5vwPm3Mu6HFYSKAOrn245sjcjFCG9lJgxOiyeozE8QZ3FNeLnMYuSl7zB9nmjFQJMcHxmrVoCINjbokzjpNiXw56jUqlLJ+kT9ToKjHgcjChlJX75yYSuv+JT8s1UBT3PM7KoqTl97/KS2y7NQR+3hm9vk8uzcrrXgqr7WnizS17FG9q+ivic7w04F/S+yT3FVP5s0TCuck7ER5cYxYEzh+YWF6T7Ar0urn/2gfPMZ32l3tm0KLNaSMw== 17 | 18 | 19 | 20 | 21 | 22 | tstudent 23 | 24 | 25 | 26 | 27 | 28 | 29 | https://sp.example.com/metadata.xml 30 | 31 | 32 | 33 | 34 | Test 35 | 36 | 37 | tstudent@example.com 38 | 39 | 40 | tstudent 41 | 42 | 43 | CN=Students,CN=Users,DC=idp,DC=example,DC=com 44 | 45 | 46 | Student 47 | 48 | 49 | Test Student 50 | 51 | 52 | 53 | 54 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test/data/response_notbefore_future_signed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | This data has no meaning. 7 | http://idp.example.com/metadata.xml 8 | 9 | 10 | I7HHjuQfXmELXf7TyRClXhzshwQ=K5JAWPa2KVtx2r4s5FN0XagYCUaxlN2OQbbzvqxZRbsnqFhluYaBR0Hlv/aygvGkv7OFBfpvojKsshHxPOArNT7CM1YNhV2RQ9v5IL7A396XvNpWdcMgGRL4FcAEzOcgAwmRYjYUfqChbY7cFKyMvyVVowdE4wGKyYAZiRwC8npbjZNuqTekofheF0fxnYm3CRzT5akztMugY0HHmy9WsochrDtoglwkjrZTSBlgYLGD3Yk7mCZos6IGo9zK6eF/ycPxGqR597WQOtLr9dnmhs0IE3iKQaS2hY2WwoPqJZgDPOoHtFBaDrkVY/JG0ucrg0eVkKtNHRKTYSgzv+JK/w== 11 | MIIDGTCCAgGgAwIBAgIJAO8HJfrb3JZeMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgwMTE3MTdaFw0yNDAzMTcwMTE3MTdaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFf1kCef6FTPMxQSoThAZGFNmixh8fRDLsUo58pEFwztBRUPWS6s6Ql8mA75aAEdo4+JVyE8QPi5F+fWbnToWkIw7E7YGl6s+EScSMQYHKCLq4mPHPMHtZspFowNp+Vax88SSUo1TKlpVNVIGim8JQ5SRi3p0aD6UAiu9WxQ5s+xHnDwgvQiu3Sa4COl5NQjkC1r2LrhJnJQQiw0hsn1nGgg15jEaDCZa8uPw1EtHv8smoZpjTbwRBVjXtzLskYIRyYLQjvqR+/QAd0XZcav0LdTwQR6obg/CwSgv7qG/WN6t25VIIGQDIUkVMBhLDmCh8QRpTvx1YWumSWW4D2k2kCAwEAAaNQME4wHQYDVR0OBBYEFLpo8Vz1m19xvPmzx+2wf2PaSTIpMB8GA1UdIwQYMBaAFLpo8Vz1m19xvPmzx+2wf2PaSTIpMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALhwpLS6C+97nWrEICI5yetQjexCJGltMESg1llNYjsbIuJ/S4XbrVzhN4nfNGMSbj8rb/9FT6TSru5QLjJQQmj38pqsWtEhR2vBLclqGqEcJfvPMdn1qAJhJfhrs0KUpsX6xFTnSkNoyGxCP8Wh2C1L0NL5r+x58lkma5vL6ncwWYY+0C3bt1XbBRdeOZHUwuYTIcD+BCNixQiNor7KjO1TzpOb6V3m1SKHu8idDM5fUcKooGbV3WuE7AJrAG5fvt59V9MtMPc2FklVFminfTeYKboEaxZJxuPDbQs2IyJ/0lI8P0Mv4LIKj4+OipQ/fGbZuE7cOioPKKl02dE7eCA= 12 | 13 | tstudent 14 | 15 | 16 | 17 | 18 | 19 | 20 | https://sp.example.com/metadata.xml 21 | 22 | 23 | 24 | 25 | Test 26 | 27 | 28 | 29 | 30 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/data/response_notbefore_future_encrypted.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPg0KICAgIDxzYW1scDpTdGF0dXM+DQogICAgICAgIDxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz4NCiAgICA8L3NhbWxwOlN0YXR1cz4NCiAgICANCjxzYW1sOkVuY3J5cHRlZEFzc2VydGlvbj48eGVuYzpFbmNyeXB0ZWREYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyIgeG1sbnM6ZHNpZz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgVHlwZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjRWxlbWVudCI+PHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI2FlczEyOC1jYmMiLz48ZHNpZzpLZXlJbmZvIHhtbG5zOmRzaWc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjx4ZW5jOkVuY3J5cHRlZEtleT48eGVuYzpFbmNyeXB0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjcnNhLW9hZXAtbWdmMXAiLz48eGVuYzpDaXBoZXJEYXRhPjx4ZW5jOkNpcGhlclZhbHVlPlduVU5MUnF0SEdrWE9uMXRKc2FWaDNBeXp2TDkrRnJKWWNoeE5BbkZDcGVWbG5nSC9oM3BSOFlLdG5BWEtmZHVSL2tVbXVRNFU4ZW14cDc3OXdjYzNqY2NEajJFcXZTUlhsNDM1MkhrQVV3T2Y2eWc3RURILzFKeFMrbHJRdURCd08yTCtmbVo1ckczdjdLeHlqc29GamMrQzhaNGNKaE5LWDcraFMyUWxBcHRDekNmNUhwaWk4TG9KVTk5bXUrZHJHckZZZ1A5SWV4QzZyWGRKSUNjM2NwWlh2d3ZKNDJYcXh5alNvTzU3OWFZTFdLZFdjdlVRVkhXaExIbTl4TTFkOVRDSGFRK0Q0NHlMM2xLUGViQVNMZGxwVWZ3S2V1UEs2MkZkN052ODVac2lWMm9WeEdzUmVmYk9zRk5hMEduTFNKSEpTYmxGYmZDQnlLaHJIV3BTQT09PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWRLZXk+PC9kc2lnOktleUluZm8+DQogICA8eGVuYzpDaXBoZXJEYXRhPg0KICAgICAgPHhlbmM6Q2lwaGVyVmFsdWU+blVBYjk3SW0rbzBPN0pRd3V1R1dNdHpPR0hMZnFxVzVlVGVjejZYd0VldjBtQ3BsbHlRUzhHYnFIWHA1RWpVcXg1czZja3J5UXdKK2svT09uUTBFVnVCMStER1V6TmNjODJGWTF0NE9NRjJiRnVtUVBvK29GbUUyMWpHMnJabzhZSFdyMzNIVDNibzVYZUxPQ1JwTFRGRy9ZZ2lOSDRZN0dZblR4Sy9XZUtlN1JmY092QTZiWXBReWc0Qm1hdTZaeHBZaU42bmdMbFFqMmt4bFJHSG5yMWY0eFVGbjF0RVhvYThGTTNBTndiSlV2K1dyWEt4ZjlnZDNWSG9XL2VvVDVrK3pxLy9VejN4Wi9QTVhDa3loeGp0cmsxYWxkVTB5cEIxblV0UGo0N0lDNEJId2l1dEpneExMaTRrb2tRb0J0dU1PNzFyQ0c3bTFVUFI2Yy9idXlpaGMvZ0RuUTVWditzT3NndFA1NndoeTdoeVl1Y3hQRDUxMElSNlcySW5kMFp5eXNwcDRkM1JtZXBzSUZNRHNmcTE4VzZMWmFUQ1FSd0xyNTZORlJibjBaempEYy9GNEFhU1pleFdCTEg5VG9CcXdDVnpDNmorZjdGMWhEMHFQMU9jZ1dvcERFeHlTVllCNUtKQlIwUDNIRFBWdlg5VmNVN2lLVklQTUlRWEhVRnlMQjlZWjZBTCt4L1AvR2k1UG93MEh6bmU0TTFzQzk3eWc1RHU4WlQvcXM4cTBoVnJneTgweVR0Y3VwK1ZIZU96M3lxVWlWMDZJVlR1eStDRzZWbTR6am13RjB2b3BuanFKcElXRjMvN3ZZc1FmYlNJbld0OUdNdGYvQTgyNW4vRi8vMVpwRjFUL0pxTFRwR3NIczRRYmREdDJoR3pudThyWnpnMjZOT1dLR0wwVnZtdEJncmVWT3VnclYrV3FDNnVsZC9KWWFFZjFTSnNNOTZGcXdyME5tSXdWRFhJM09zZXc3QkRkTDVTRUV0UFRheHFXbVlybGpmRmZ0TXNLbGFBenU3SFpjU1V2Zi8wMTRobUJiaTBaY3N1cmVzQVBYMlFOcUJCaDJRYm95TS90VStxZSt2MXVsMTA3K2RLNFRnZU5oQWtsMHFnU1JsMmVNTkJDWUVPREZ0d0RmSVE3T3lLT1pFMzJsVzhmeGlMV3lleDdxczlDd2pCODRHeCtGMjVlSllPU0xJL0xvMUo4eE9McVN1UnVIYjRNNjR6bUZyalBENHdjcUZ2bTQ4d2UzWlVPVUVIREMyWDY4MjVoOWRvRGsrRDFtZFJoN3B5SEd0QmR6NTR4Tk5lajY5ZG1PNEJBcWRIZXhBNkNPTiszTndNYW02WmJoZm5RNkpscGVIUmtRZzkyeGh1d2NwWmo5bGpkSTl2bFM5T05XS09INGYwY3R1NEc3eFNjcGpDZkpBWlhuM2ZjeEg2U1VXY2g1UG1PYWFVazdCRmRLdTdzYitXcjNFWWsxd2F4aWtuNjNHdXJra1VhL2YrY1dDRWJZVXpZdWlHOUpkUVF1K1BHSmVjaXpKc21hL2lRTjl4NUxGUFNnM040L0RKZnVuRU9zN2tvVzhGR00zVWdnZ3h1N1VxY3lRNVphLzdVVmxoMmhtUFpsc09TNFlSNjh2VHFmaVYwQldsdmNoaE5ORTFxL3RYTWMxeHNhbGJVOS85UVcxcGxYTzMyb0F3ajVnSG0rcERSSUluakRKMDkxTFEzdnNweGVBbWJwOWJBYisyRC9DSXJaU21MWVhZMTY4aGFpVFFPYURHZXdtOElncm15UnhEWHkwWDFOU0FhL1U5Szd4cjZWNVhoaVVBVnVyVGN3Y1pnTVNOS29GMllwMlo5ajE4d0hpU09nd1Rna25UN0Z4K3BPMVdRMVBPVFJkN2JGa3RlMHR2a1BQaCttSk40cmN2N2ZpT3ljaEVnckdYNUo4YVp5ZUk5L2F6Z0RCVzdFdE1IRWNIakkyTFR0bEdXaG8wVjhBbzVFd09zd3lkRU5iTUFFNVBoWFhNc29kUXdadm1LZEt6U1AzWkR1VEhSUWVHcTdwc2NQc20xWERtZWxZOFFEeC84RUFpNzAwNy9leXA0Z1BKZVBTVlF3bHJGamFzS20rS1dQc1NqWG5CTGZ1TzVjOFZ6SDFhMDk5dlBxYTVZQzFQUUdPd3B4ZENxUG5HRmxuK2pTa05oaTNQcTZKNnZiTjVmbXBQS3VuWks3Y2E5b3VXNGlYRTBoUGhPY3l4bWZFeVV4R3NPQWtLSlBlZzdSVjRMUnpDNnB0cElDc0NXNU9PdW5nblhVSElWVnlRN0hXbDhBTStHclI2VjBidjBEcjh3U29IMmpjakRMclYxRHhtZktjd1kxV2JVNHZEWlBKYjFBZy85c2VJNEdwTmIyOFdmY3I5QUNhdlVsKzJEVjR2VXFKckRQRTFwRzFUVm1uUHhzQnNIbURiTThGL0FKUXRjRkNNYjRQcDdXbytrU3VWNVVibDlrR0VDMitGTkVTWlJsdlUxTVNNOFVBeGhkOHp0Tk1xcitVMTFDM2JlcWo2WjFpT1dDN21VU1dJMjByT2crTi9CY0pVUkZ4Mmo5QVpnS2J6dnBHcG4rSURSUXB2Sy9Saz08L3hlbmM6Q2lwaGVyVmFsdWU+DQogICA8L3hlbmM6Q2lwaGVyRGF0YT4NCjwveGVuYzpFbmNyeXB0ZWREYXRhPjwvc2FtbDpFbmNyeXB0ZWRBc3NlcnRpb24+PC9zYW1scDpSZXNwb25zZT4= -------------------------------------------------------------------------------- /test/data/redirect_response.xml: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /test/data/response_notbefore_future_encrypted_then_signed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | VNpShLvByJ91Q9vRHRCHCpMrj8I=tuwHh4kcJJAZIzRwYS9rzNkCIF4HGU9YhLJ9Nwft48axCJrUj0hkiIdZf3+vin6YUFj4JStPK0YBEIQsB5pxr91JZWnYLkotgD/T+rKhVkzxOMn3GcK24856cSFmQLmL53KRqzYSJIDY5y0c6E/kxDe9r+PMG4/ch83mjGOSPgHMFDYebIGEpw+7Y79qcGTfYUrnx7oIOOUspZNuaSv2yr3gqAmG8ZM06/F8FzunbW2S0nP8ymv09yfhoZf7XtJALDC6fmw/M0czbWWMVu+OC9pcRmCod5to5kud4BIoGILCpsLb9jy8uKPPpPuuFh0U8sMij45A3IHAJwi2btUJ6Q== 6 | MIIDGTCCAgGgAwIBAgIJAJQd/RSI51tKMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgyMDMxMDNaFw0yNDAzMTcyMDMxMDNaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxerkURM4678nuft7LQI7g5jySUHwHROCheAVt+kemVeg7JNFzPaF1AOm2n4S4xq4aI03/HW725sxZTJIit6TBSiboC6yuN/cM/mzwjhbV+gCQRz2DrI7MkGGujn5bH+vu3qzxpXSoSqrkuHWrdeNGHLBP0C/0pHU2RZJOGG1h+S+tiW+EGKz1PItfL7mg8V2EhieUBYLgxGxVsNYwtL7dWcib7Y4476Yx25d34k1IgBrvkyo3yx1GizwG00+0FR3/ykMYOexwiZzCrKbZoz1Bf0itu9vqjbzDy9gbkEQBIcZxpE5GOwAtyLNKgBdSyFj3zbRTUIyOtNdTv5CN34WMCAwEAAaNQME4wHQYDVR0OBBYEFFIQ7r0sopn/h79pX1qiQaWzcMGoMB8GA1UdIwQYMBaAFFIQ7r0sopn/h79pX1qiQaWzcMGoMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHcMfEAswmSVRsRofaibLeP72Hm8zutb25ntpm3gcak+DikE4ZwI/HGYw2YpzGZ9v8ysxc/egc7lLKn+yOlObRdIFJmXu5MSf0G6D5/NRv8RagCa3x6KgjgZOTx5MNR8KX2y79bOupMMj/PnI4jA2jXbFFSUwz6MQFP/4VyhlpYqdhn3Qpuu8YVrW7KHcYm6RQHlrC70WCcfZEWLEHjU/uRwFK1+hMsULbbu3O8/zmJsU6O4b2ZbjCoPvsAZYPK0/OJYbyUxfpfHZ82KmF261HEKIchEWPkpiZivtrPfIOZFy6iV4bt0PT/SGoIbKOxh0Nxxyt2mHnpd030tUXNYLTc= 7 | 8 | 9 | 10 | 11 | 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 14 | 15 | -------------------------------------------------------------------------------- /test/data/good_response_twice_signed_dsig_ns_at_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | VmOQiP59NeSBPwrhe5MDQJlNw/E=pPycwjnj6ezRb9vrmEQ0CTBlkRa7inhDCHUj2Z5s6pOuBZq2bdxY1jvplHz5FW6/2SPtsST5Wj6RZMClHGV8rlTBjgA92+EtGJHgaZYemvFTA1n/7SWI9vjP2Doy9JF8AeZlmN9xgZL/wVsKkdv/lk7B6stWfUI/PDRN5JVUYDvoSC2j1pxkdJ6zhFL9XWs9wUNlO2vsP1XsHrQ7ndn4h5K6J9frfc0IX6R7NBu/pDUk2Vx6Xh1RlhuZRD33KN38e58vs1qm1isFcoTgMhdAVjS41yf92b5KFuDp0x4dliV099QUZFtNH+7SH7pJXEkeLQnXpF/73jXLoMUjdn7qNQ== 6 | MIIDGTCCAgGgAwIBAgIJAO8HJfrb3JZeMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgwMTE3MTdaFw0yNDAzMTcwMTE3MTdaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFf1kCef6FTPMxQSoThAZGFNmixh8fRDLsUo58pEFwztBRUPWS6s6Ql8mA75aAEdo4+JVyE8QPi5F+fWbnToWkIw7E7YGl6s+EScSMQYHKCLq4mPHPMHtZspFowNp+Vax88SSUo1TKlpVNVIGim8JQ5SRi3p0aD6UAiu9WxQ5s+xHnDwgvQiu3Sa4COl5NQjkC1r2LrhJnJQQiw0hsn1nGgg15jEaDCZa8uPw1EtHv8smoZpjTbwRBVjXtzLskYIRyYLQjvqR+/QAd0XZcav0LdTwQR6obg/CwSgv7qG/WN6t25VIIGQDIUkVMBhLDmCh8QRpTvx1YWumSWW4D2k2kCAwEAAaNQME4wHQYDVR0OBBYEFLpo8Vz1m19xvPmzx+2wf2PaSTIpMB8GA1UdIwQYMBaAFLpo8Vz1m19xvPmzx+2wf2PaSTIpMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALhwpLS6C+97nWrEICI5yetQjexCJGltMESg1llNYjsbIuJ/S4XbrVzhN4nfNGMSbj8rb/9FT6TSru5QLjJQQmj38pqsWtEhR2vBLclqGqEcJfvPMdn1qAJhJfhrs0KUpsX6xFTnSkNoyGxCP8Wh2C1L0NL5r+x58lkma5vL6ncwWYY+0C3bt1XbBRdeOZHUwuYTIcD+BCNixQiNor7KjO1TzpOb6V3m1SKHu8idDM5fUcKooGbV3WuE7AJrAG5fvt59V9MtMPc2FklVFminfTeYKboEaxZJxuPDbQs2IyJ/0lI8P0Mv4LIKj4+OipQ/fGbZuE7cOioPKKl02dE7eCA= 7 | 8 | 9 | 10 | 11 | This data has no meaning. 12 | http://idp.example.com/metadata.xml 13 | 14 | 15 | nS72XwOKD7SxpBrvb8MFkrmrPJM=cf4xvQneMFGQOsIgG/xrg8dpYbCvBZ5GUZkIMNA7BTT2tBuiP0djR/iS4uHPqnkbYLVnJd2gwh7Mg/7GySAVSSimfsNUk0LxKd59Nmw8z+iVTKzFnK7O6r4ifkPvWpIM28J1fJmqUINXRXBD1JQSY2p/4TPS1DQAUpYf8Yh1R4SWX0Xqiu2XgIrTXVrqh3X76fm4XMFmyL7FNt1wn8qzobqpfDYciNz1ZCfg9NwdFY4AeWSD3HeByJn9ct0CgNyDu5B6ii4CldfEUS6S15IlicuVimVteNXcSbyNN9/EOkBjCk9PtzgqzX5X4T0rF5CU6s2dSUAjCsmIEPWUr38B/w== 16 | MIIDGTCCAgGgAwIBAgIJAO8HJfrb3JZeMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgwMTE3MTdaFw0yNDAzMTcwMTE3MTdaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFf1kCef6FTPMxQSoThAZGFNmixh8fRDLsUo58pEFwztBRUPWS6s6Ql8mA75aAEdo4+JVyE8QPi5F+fWbnToWkIw7E7YGl6s+EScSMQYHKCLq4mPHPMHtZspFowNp+Vax88SSUo1TKlpVNVIGim8JQ5SRi3p0aD6UAiu9WxQ5s+xHnDwgvQiu3Sa4COl5NQjkC1r2LrhJnJQQiw0hsn1nGgg15jEaDCZa8uPw1EtHv8smoZpjTbwRBVjXtzLskYIRyYLQjvqR+/QAd0XZcav0LdTwQR6obg/CwSgv7qG/WN6t25VIIGQDIUkVMBhLDmCh8QRpTvx1YWumSWW4D2k2kCAwEAAaNQME4wHQYDVR0OBBYEFLpo8Vz1m19xvPmzx+2wf2PaSTIpMB8GA1UdIwQYMBaAFLpo8Vz1m19xvPmzx+2wf2PaSTIpMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALhwpLS6C+97nWrEICI5yetQjexCJGltMESg1llNYjsbIuJ/S4XbrVzhN4nfNGMSbj8rb/9FT6TSru5QLjJQQmj38pqsWtEhR2vBLclqGqEcJfvPMdn1qAJhJfhrs0KUpsX6xFTnSkNoyGxCP8Wh2C1L0NL5r+x58lkma5vL6ncwWYY+0C3bt1XbBRdeOZHUwuYTIcD+BCNixQiNor7KjO1TzpOb6V3m1SKHu8idDM5fUcKooGbV3WuE7AJrAG5fvt59V9MtMPc2FklVFminfTeYKboEaxZJxuPDbQs2IyJ/0lI8P0Mv4LIKj4+OipQ/fGbZuE7cOioPKKl02dE7eCA= 17 | 18 | tstudent 19 | 20 | 21 | 22 | 23 | 24 | 25 | https://sp.example.com/metadata.xml 26 | 27 | 28 | 29 | 30 | Test 31 | 32 | 33 | 34 | 35 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/data/response_notbefore_future_signed_then_encrypted.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 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 9 | 10 | -------------------------------------------------------------------------------- /test/data/good_response_twice_signed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AOtFKxIx0k7nIKQfj+FI0UCa1y4=DfgTCB/5JZ8mS0rb/N1aUsSzMVTYLYb0FbRtDyMDXemYVILXcN/rnLKHQBuH1Yjxe+pPXMBdkceK6aD+Ir+B7K+zNFtkqYCqEWYbBRuQI/TpPwxQ/3hNm7i5ml2d09ngZGlZlvN+v7/3QsoL/Ygda/xYLV9Zsp3nhbLOU0wLMlr1wB2yWzW94OidpwSzKf3d+jEo4+xWG7JTeAwLQiVcjI9NOOF+d7ZzymMccTeXmNqHVwBO8HMbGfVUItw4Ji+iFkAoageNPK0GAcDRhSnTJ1SeNGWdfUX5myTi7Vp6SfJAyBxJVeT/4n9WANbiLaYFL9Cc6qnC7EuUE7qkavq7hA== 6 | MIIDGTCCAgGgAwIBAgIJAO8HJfrb3JZeMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgwMTE3MTdaFw0yNDAzMTcwMTE3MTdaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFf1kCef6FTPMxQSoThAZGFNmixh8fRDLsUo58pEFwztBRUPWS6s6Ql8mA75aAEdo4+JVyE8QPi5F+fWbnToWkIw7E7YGl6s+EScSMQYHKCLq4mPHPMHtZspFowNp+Vax88SSUo1TKlpVNVIGim8JQ5SRi3p0aD6UAiu9WxQ5s+xHnDwgvQiu3Sa4COl5NQjkC1r2LrhJnJQQiw0hsn1nGgg15jEaDCZa8uPw1EtHv8smoZpjTbwRBVjXtzLskYIRyYLQjvqR+/QAd0XZcav0LdTwQR6obg/CwSgv7qG/WN6t25VIIGQDIUkVMBhLDmCh8QRpTvx1YWumSWW4D2k2kCAwEAAaNQME4wHQYDVR0OBBYEFLpo8Vz1m19xvPmzx+2wf2PaSTIpMB8GA1UdIwQYMBaAFLpo8Vz1m19xvPmzx+2wf2PaSTIpMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALhwpLS6C+97nWrEICI5yetQjexCJGltMESg1llNYjsbIuJ/S4XbrVzhN4nfNGMSbj8rb/9FT6TSru5QLjJQQmj38pqsWtEhR2vBLclqGqEcJfvPMdn1qAJhJfhrs0KUpsX6xFTnSkNoyGxCP8Wh2C1L0NL5r+x58lkma5vL6ncwWYY+0C3bt1XbBRdeOZHUwuYTIcD+BCNixQiNor7KjO1TzpOb6V3m1SKHu8idDM5fUcKooGbV3WuE7AJrAG5fvt59V9MtMPc2FklVFminfTeYKboEaxZJxuPDbQs2IyJ/0lI8P0Mv4LIKj4+OipQ/fGbZuE7cOioPKKl02dE7eCA= 7 | 8 | 9 | 10 | 11 | This data has no meaning. 12 | http://idp.example.com/metadata.xml 13 | 14 | 15 | yn+85TrLn8fAxUeVzVHteQpDmmQ=kSpgT3WImsWeiKAVZn0lRkuZNFgl97Up4u1Eei9b0VZGKknGMBlgpeFB0yWT1WX0QUsSAbBbNKgyEC28PjZ08qbQzv/dAUx6lZp6CdfD97BXxhtylNfs7dL/MLatj4aXQkwAduZUDmb8q6LR/2Liz/cC/QyNZygib2PLi6NWdaYR7Kdxf/P44JHJRs1kFTZ5JXCbj8itv6i+pY2OfOqS0W2galaK7sBrFb0tKWqZkvXD8wTQsb6cdR201ofyNplM/m5TAkl1ORGnjSi23UN6RFmAnWXvre2XaclBKD8IvdiTebbK4J8DQ/fyj5vTkfNXh0JTNS0qArBwSBmVo246yQ== 16 | MIIDGTCCAgGgAwIBAgIJAO8HJfrb3JZeMA0GCSqGSIb3DQEBBQUAMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDAzMTgwMTE3MTdaFw0yNDAzMTcwMTE3MTdaMCMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFf1kCef6FTPMxQSoThAZGFNmixh8fRDLsUo58pEFwztBRUPWS6s6Ql8mA75aAEdo4+JVyE8QPi5F+fWbnToWkIw7E7YGl6s+EScSMQYHKCLq4mPHPMHtZspFowNp+Vax88SSUo1TKlpVNVIGim8JQ5SRi3p0aD6UAiu9WxQ5s+xHnDwgvQiu3Sa4COl5NQjkC1r2LrhJnJQQiw0hsn1nGgg15jEaDCZa8uPw1EtHv8smoZpjTbwRBVjXtzLskYIRyYLQjvqR+/QAd0XZcav0LdTwQR6obg/CwSgv7qG/WN6t25VIIGQDIUkVMBhLDmCh8QRpTvx1YWumSWW4D2k2kCAwEAAaNQME4wHQYDVR0OBBYEFLpo8Vz1m19xvPmzx+2wf2PaSTIpMB8GA1UdIwQYMBaAFLpo8Vz1m19xvPmzx+2wf2PaSTIpMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALhwpLS6C+97nWrEICI5yetQjexCJGltMESg1llNYjsbIuJ/S4XbrVzhN4nfNGMSbj8rb/9FT6TSru5QLjJQQmj38pqsWtEhR2vBLclqGqEcJfvPMdn1qAJhJfhrs0KUpsX6xFTnSkNoyGxCP8Wh2C1L0NL5r+x58lkma5vL6ncwWYY+0C3bt1XbBRdeOZHUwuYTIcD+BCNixQiNor7KjO1TzpOb6V3m1SKHu8idDM5fUcKooGbV3WuE7AJrAG5fvt59V9MtMPc2FklVFminfTeYKboEaxZJxuPDbQs2IyJ/0lI8P0Mv4LIKj4+OipQ/fGbZuE7cOioPKKl02dE7eCA= 17 | 18 | tstudent 19 | 20 | 21 | 22 | 23 | 24 | https://sp.example.com/metadata.xml 25 | 26 | 27 | 28 | 29 | Test 30 | 31 | 32 | 33 | 34 | urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/data/post_response.xml: -------------------------------------------------------------------------------- 1 | PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzYW1scDpSZXNwb25zZSB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBJRD0iXzIiIFZlcnNpb249IjIuMCIgSW5SZXNwb25zZVRvPSJfMSIgRGVzdGluYXRpb249Imh0dHBzOi8vc3AuZXhhbXBsZS5jb20vYXNzZXJ0Ij4KICA8c2FtbHA6U3RhdHVzPgogICAgPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPgogIDwvc2FtbHA6U3RhdHVzPgogIDxFbmNyeXB0ZWRBc3NlcnRpb24geG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPgogICAgPEVuY3J5cHRlZERhdGEgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyIgVHlwZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjQ29udGVudCI+CiAgICAgIDxFbmNyeXB0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjYWVzMjU2LWNiYyIvPgogICAgICA8S2V5SW5mbyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CiAgICAgICAgPGU6RW5jcnlwdGVkS2V5IHhtbG5zOmU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI+CiAgICAgICAgICA8ZTpFbmNyeXB0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjcnNhLW9hZXAtbWdmMXAiPgogICAgICAgICAgICA8RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiLz4KICAgICAgICAgIDwvZTpFbmNyeXB0aW9uTWV0aG9kPgogICAgICAgICAgPEtleUluZm8+CiAgICAgICAgICAgIDxkczpYNTA5RGF0YSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CiAgICAgICAgICAgICAgPGRzOlg1MDlJc3N1ZXJTZXJpYWw+CiAgICAgICAgICAgICAgICA8ZHM6WDUwOUlzc3Vlck5hbWU+Tz1JbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQ8L2RzOlg1MDlJc3N1ZXJOYW1lPgogICAgICAgICAgICAgICAgPGRzOlg1MDlTZXJpYWxOdW1iZXI+MTcyMjM3NzcwNTkyNjI0Njk3MjY8L2RzOlg1MDlTZXJpYWxOdW1iZXI+CiAgICAgICAgICAgICAgPC9kczpYNTA5SXNzdWVyU2VyaWFsPgogICAgICAgICAgICA8L2RzOlg1MDlEYXRhPgogICAgICAgICAgPC9LZXlJbmZvPgogICAgICAgICAgPGU6Q2lwaGVyRGF0YT4KICAgICAgICAgICAgPGU6Q2lwaGVyVmFsdWU+bGFqK1VIdG50RTJSL2hTc3QydXUreWFwc0toV2xvdXpiNUpoSkhJZmpsSjVnNElEbldsK1h3MFRaa2lNMDd3Qk9rQzUrNUZvaXZrTDNUeEhUaWxSQkRNSGdVQ0FFT2xSNnN6b1ZKTzdDOUt4WEh1WFdoSzVBTWhJVmFBSFNTNDRPbEMzZVpTUlFFdFBieFJlNjJNUEFmdWl1Mzk2RWtXVzZpQ0g2azdJaUVZTG5Fd1B5ZGFQOHVBd05mQVpxaGZxbEdidFJPTFFFWVpZSlk2VXlZMURCV3NZbHZ1NEkrTVpITlUvRGd6SHpjdVFEYVhXcUxLSVBQUGhuQWZ1eTM5b3JsV3Y4SmMvQ1RxMmFMRjZ1Tng2WFZrZFFPTi9HcGlzWDVpbnRlaWIyYWtnTUh5dzMxaW1zb3ZVK0RnRjVSZ24xaWFQbU9leXNTaGlxeWo2UTVEamhnPT08L2U6Q2lwaGVyVmFsdWU+CiAgICAgICAgICA8L2U6Q2lwaGVyRGF0YT4KICAgICAgICA8L2U6RW5jcnlwdGVkS2V5PgogICAgICA8L0tleUluZm8+CiAgICAgIDxDaXBoZXJEYXRhPgogICAgICAgIDxDaXBoZXJWYWx1ZT41dnRnbU9uSE1VNy9YUTREb0ZSR2VpUThYRFpQay9KRFNVbFFJQXpoMHB6aWFPY0FrTTkzNDduaHFwK1FSeVk5bHh3ajVtbWN4UXdVMmdHcVVuQ3JaRkJocysraFdOeUIvaTcya1FvOHlGQk53NjNFQ3VzRjRvN3B6MjFQUmFPT3RGYjREZ29PZ21BVFVmVzNjUmY1OHVjcHgyZWNUaENwcStVVEUzaFhTcWJQbVBKSm5PNkVCL3N1N1hHc3NrWjY3V3orMldVRUFJM0d1OVpiY09vby81NzZ1VExRbzRiVkc4S01TNHJLeDNQQU9ibUZiNklhMmhhWngrUmYvTWJiaUhkbktXZTZJZzladEhSTWVBbm5ObStEOENXVUFMYzltVWFDcUhOWmpGVWpRMG5GMUJveHgySjZNMGNrREFXWWxFRnMvb3I4cTQ3ai9leFA5M2RMS0lvTVFzZk5sVW5OSlBoZ09QVkpZc2tWTWhuZG5KOVVOdzFIKzR5RjN2QjZjVWdBcGRHZllDdXBrUXVRUkJhVkF1SDJlWWF4WGZJaTYralFObEFNdHhBZGlqL2RHbkVyeXhyaTl3R09wQk4xRFo5WGpXL3RLQVJZbVFaamc5V1dNNHc3STQrMjY3SG1LTm1weHhtWFJjZEo5T3gxYTNPSDFKV2o5Z0dETUVXRjVDZWxBNlRMNXRDM3l6VFRJKzkyN3JUc0c2UmVCUU1mbXZudEtnNys3ZmNCN1pxYktIYVQ5U2VLZHJLSWhGbmJQaE1ySi9uMmZWdEJhbnNnTDlkTnpZdWtERjk5WkxsamJUS0pFR2htQ09vcGRNdFJDSDhJTWNzQlc2RnFqSXpoWTVjS3NWbTBkQTNobGl1cXFTbEJvYnFSZHhQTGh0WTVmUXdNaXNnakl5N0tzS295MXlxWkRLa285OHZYb2YxdWN5UHZnRGU2NHJhVHBPUkVUTDNSaVZadUR6aDBOdW1HV0VmbGNrZTdUQ1VQVWJmWmtKMnVkMFJDdHdBOVI0UWQ1MVY5ZjNha3BpK2pHQTZuOEJDTkRGenluNmt6VWdYUG14NCtQSXRkRTIzaVIvRFdVQmthRmwyTmpqZExJZzJCMTZ5RERGOFltWFh4MVg0NGtBMW1QejhzVTk3U2ZRL0dLanhnQmdWdGp5TDJBMUhSWCtSekd4b0FvTGhDMURHcGxwRjcrUFFQUHlJNTVDTkRzMDlyUDdieUFOeW1sUnRBUjYwUXdVM3R5eGFvRnA1b0RKdEVoeGw5TGdYT3V0dldxcTNsb01YR3FZaE5USG1SLzlaaTVyOHRwcVNoS3NnTTczMDNMV2tpbnEwSDhUQ0lDQmZHTXp2aW5GaWhoNHRkbTF1b2d6dzhISitJenJ1YzdLTEE5eHFZZ0lLYThUUUJFeE1TWTVzczVZSENJRDk1NFFxdFowUnFtQUR6aFV2Rll1ZzhhZ0pUOVA5SW9IZTRYTXpaMjcxRHd1RzFqRy9QM0pJM1VMMDlvSzF3Wllzb2ptQnk4QS95NVl1NlYwWlN5UWY3Y0ZRRDdLY1o5bDY3VU83UWh2WWdRWDhJVXZkV2o4STM4WTArMVVHYkhodXk3SE4reUJDQ3MvcGpUTmtvK1prMURUZ2h5ZkhXVDJNWHhEUHVzTER2MmYxa0tpY1I2SW9melE4WVpad2lkcjMvdFJRRndjQlAvbXV5bHMyNXJWMkVTOWhVbHd0dC9EQ2ptU3hmY2E5ZE96aGpuMmhNVFRadkhmTml6ZVQ5N0pxdUNMdERwZWxONzFlci9idHFHWThYV3ZCMlBBTXFvK2dDcXFxQUpxbjVDMys4bXppSS82NlF1UlVFYkE4RG5kSy95YXp6R3ErcEluaDBId21GYWszb1ROcjk5WmlTTDlIQ3B2cFpueHJOdGV6UmdIeVcwVmp6R3FYL2Y0V2wzRitmQjVrK2s3M2RaeDZoR2Q2VVZUNmZYZy9IUmRQaHRGWUZNaVdRNnlTUkNUY1ZCekJFT1hJNTF4dEdndUtSQ2RqVTNHY0Y5WlpaSDVBMFluYmdUMXVjbkprL0dZd0lYR3loOFZxT052Tmo4NVRVUW1qTk9iZTBicUFMQ0xDMkh3S215Wk9mVUl4R3FMTzRDOEFWOXlBdytxUm9nRGM2U1h6ZHN0QU9YUGsxR1JHbXhtNmd6QWJyeWlXRUtQTlc2dStEQlhqV2VHUldmK0tnbHZKL3hmTHFSR2FNRGxESGh6bTQyTTVzRkdOQ1Jqb2VieHk4djlpenMrSTVLb0JJcGhwWkh5UStyL0hHRTJWRWhOMEJONUV6K2NJWEF6SG95d1JSaEZETkJsR1djN2psRGYvYjROd0FQQlNFQWZzMkdaMG9FblNVa245enQ3V1BSTjRsMTVERmx0K1Z0TWFoYWM4OXMwSlFRVWhjMHBRM1kvaXVpTC9HemNnV2lvbmp1UDl6KzhGMVRVYVJWOUpGTktKaVNHcXRESXlMMWJ3bkF5dktmR04xamxqWXhucmZ6K2pDSEN3ZWQ5Z0hFckxVSHdDdlNoOHhwTmp6Ris0TkhEUmMvL1c0djJqZ0trWkl6RkdCWkJ2NGo0dkFLVnhOQUhMSFduRTBEd1liTXhTTWp5NjkwR3IrTFMyVkN1MzNoWjlGQ0l1cGljNjRXRHlWRCtlcTNXNlVFNDE1Nno5cnRwcHZoSjNObldRanNDWU12dkFseUN5dFVIVzkraGE3OElPYXJPM3M2c1Z2QU9IMVVTLzlueUoyUnFoaWxWc0tDZkwvbDFieWJGY1NqZENONXBnYnh1U0o2TFNpTFFYRGhSUzRkOUt1VlJPT0RZZklVaTVQcnNFWkVHdlJaS3dRL0g4OTg4WHBPbmVQVFk5WElRY0Q4RFlRMU5UYlhmVEZ1bWRRSkVsemIxbnZpSjE3WVUxcXhBKzJaLzBKVzF4OUhiUDhsajlZTEZSRnc3VDRGaXlObHY4UXF0ZkhUcHUvTEVDMEVaV205eEJ2UDdYUzBVTm1nL01RbjBrUzJaMWJvNkZYVmpyeTlOYWVFTWtGSGVSWXVMeTh6eVBsN1ZBNmU1cExTUjFUbkk5V3I4ODB4RWV6QSt6bjFWS1VjOVh1T3VYVEp6Zjd1NmhrM2QxVXR0ejgyYk1xQzdFeVJRSW8yNGkzb0RpaTY0Uk0yaXhha3loYm9xMDZwNnBsQkRFdXpoZ1FMcFQ0UGZOa0lhSEpJMHl2NVZHcFJ3T2U4MU0rMHNabXVibEczQzEwbmxVWWhtTXN4ZDdxa1hTdnBsRHUxbDBaSDZsczUwQUs1ZG5wRkVoUUFzY0F6UVBLMGNydlZUL3NqZ0dicGMycGpCaHpyTGhFWkxBY2h0YlB3T2ZOWjc3YWZ5R2drM0NjUjBVTGl2Qmp6VHZnanJ5cElhN0tNZUtrTWZZNGtIMUVzNk8vckJJQUVjRFJNVFUrL2QwL3MrZHN2SGZ3THpzcHFQYm1hTkNxRGttOWJMUXB0V1NuanVydVpxM3hGVnJSWURMaFhpa21EMER0OWZ2VGU3TUt4TXdyRzdoMnU5ZkZ2MFZ1VnM5N0lBbnQvM2RURWMycGp4cm84OXA1cDBGZ0xFRjkwOXdGREgwTHpValovLzBJcURBSWsyN0ltNDNHQjBNN25NSHB0aXhjalFNek1ERGNueTJvdnB3eCthV2JCbm5EZU9HUG5FV0xGaHdRQng1TVI2Q05uT2tRMXdQcW1HVHpMZEQ1aHhIRVpEYnY2eEYzWXdDNlc2UjRmS0tWY082aTFBZFZpcUQwRlF3UnlrSm9NNkE5VFgyVDBJTkpZS2tQdGFXbU1hcis5TlhLdWxEbWtaOThaYWVZMjBRTnhBMjhLbGovRSswdkZkNjZTUmh0WjFhbmZZdzRwbFZUNUNDSlp1VUg1MlNYTVFsSDZHR2lENWgvSGc4UmpmTFhqUlgxeGxkYm9YaUlEY21BTDFheGFwckdVSFVjN3lreG1IVVVoL05RK1RCRW1vQ2xMVnprUVBKTFQxN0R6cTZyYTRlb1VMWEpTYzNzT0VDWEpSaXh0eHY4bXNUODlMQmxldUZtNno2NUNoT3JMQVhMTi9IVUNHbUwvWVA4SVRxZ3pVYmVzMEFFVlQza2ZBd1VTZkZRSE1aVE5MOEdnVXY0ZXhVZTVEcEpYVkQ2Y05OU1BLTG80T0Q4Y2ljaGw1by9naFhVMmhnRHM3QjZWOGdYK2Q5RzF4bnp2TjMrM1BYSEdHMm15L3d6WVJ6VUJna2VaU3pLRE5WYzhuT1FaNU14N04zNEJGYkdqSm5YUEhPZk9jVjZ1V2hsN2doS2JFWWNSYW1BcEpFNTRWeEU1eThqT2NGZ21CdU9VcGM0VzgyazVhV0Q3QVdibmt2VnBEeFZVZEEwaitpQWxsYUNXWTRZWEFPMzRkSUVYdGhSYlRUNmNuTTlaRVVPZ1JsRlJkdmNySXFhVVZIVWl0MzNhUWN1MjMvRVpZMHFNRDFtK0ZZckxIT1U1UVh3VjFtVzR2aXdBNFNrRTMvRnFUM3UyR29ibEJqVVAyaGx3NTAra3NCSXVjZWJFdG1EZE54MWN1azVIVkFzMWQyOEoyVmZhWkFmWEFPV3F0Y3N2cm9wYTRNWDBpSmVVWE9lTkV4cFhhdGZCcEtPOXEyNHdhQTZwRnVRS3ROM01JdDVtMTFSc0JnNjVwelhNRldXV2JwV3ZGenYyUFlRdXlBYmZFK2R5MWRoQlBJdzhSVzVYMG1Sbjl3K3Y1M3VncGYrV3ZCTytYOXlReUFnekh0WjlRQzRRRWVxTE54T1MwdFRBVkhzWUo4Q3VnRTVGem92NVlIZXM4Ui9rTVVoSEJiWEJ5U1JuaFVxdG1wclJMT0I4THE0amx4UStpRzNoeitZOTQxY21CejdxaUpCYXAwdmk1a3NHaDRpKzFpaFUwRTRQRWUxS1VnNGJ3Q0RVVkgvYnlsWVVJb2RJWGlXN05qb1MxaVFFd3QrNHduVzArL081aExEYU00blBYNEovVFJxT2haWkRmM3B5UjAxMHEzZU5KbThLMGgxVEdaemZJZTZRZnZqTnl2dUVmZUR6U0RuZHZiMXEvNWlhK1RWdEl0ZkEveVJEc1VQUTE2V045eWRQUEFoSm5uTERvazNLa2VidzVPUXJ6S0pTTVhHR01aQWQ0RzhVV2JCVVE2S3YyU0NLOTFXSmVkQmxBNHdHOUN4bm5NcjhraDNIditwQXVSa3VaTWNDNC9Lc2o3U2NlTFAxOEY5Q0U4ZXBnTGxhTGhEOEkrZjdsWHNjZTc3OTQrUDZCcEpUQy9EQzhvdE1XaTlkZ050bE9uZHhIRU1xUk1DRWpMbDAxNlhFK2NQMFo4Z3Zma00rWTFrR3dyclZOZGVNYi9TOUJzK2JsQ3ZUMW16NkhzRmJ3PT08L0NpcGhlclZhbHVlPgogICAgICA8L0NpcGhlckRhdGE+CiAgICA8L0VuY3J5cHRlZERhdGE+CiAgPC9FbmNyeXB0ZWRBc3NlcnRpb24+Cjwvc2FtbHA6UmVzcG9uc2U+Cg== -------------------------------------------------------------------------------- /test/data/response_notbefore_future_encrypted_then_signed_base64.xml: -------------------------------------------------------------------------------- 1 | PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgeG1sbnM6c2FtbHA9InVybjpv 2 | YXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5h 3 | bWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9InBmeDk1ZmI2MjQ1LTI3YWUtNjA5ZC0xYzlk 4 | LWQxN2NmY2EwNTU2NyIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5hdGlv 5 | bj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9 6 | Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPg0KICA8ZHM6U2lnbmVkSW5mbz48 7 | ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIw 8 | MDEvMTAveG1sLWV4Yy1jMTRuIyIvPg0KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGht 9 | PSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz4NCiAgPGRzOlJl 10 | ZmVyZW5jZSBVUkk9IiNwZng5NWZiNjI0NS0yN2FlLTYwOWQtMWM5ZC1kMTdjZmNhMDU1NjciPjxk 11 | czpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8y 12 | MDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3Jp 13 | dGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5z 14 | Zm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAv 15 | MDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPlZOcFNoTHZCeUo5MVE5dlJIUkNIQ3BN 16 | cmo4ST08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6 17 | U2lnbmF0dXJlVmFsdWU+dHV3SGg0a2NKSkFaSXpSd1lTOXJ6TmtDSUY0SEdVOVloTEo5TndmdDQ4 18 | YXhDSnJVajBoa2lJZFpmMyt2aW42WVVGajRKU3RQSzBZQkVJUXNCNXB4cjkxSlpXbllMa290Z0Qv 19 | VCtyS2hWa3p4T01uM0djSzI0ODU2Y1NGbVFMbUw1M0tScXpZU0pJRFk1eTBjNkUva3hEZTlyK1BN 20 | RzQvY2g4M21qR09TUGdITUZEWWViSUdFcHcrN1k3OXFjR1RmWVVybng3b0lPT1VzcFpOdWFTdjJ5 21 | cjNncUFtRzhaTTA2L0Y4Rnp1bmJXMlMwblA4eW12MDl5ZmhvWmY3WHRKQUxEQzZmbXcvTTBjemJX 22 | V01WdStPQzlwY1JtQ29kNXRvNWt1ZDRCSW9HSUxDcHNMYjlqeTh1S1BQcFB1dUZoMFU4c01pajQ1 23 | QTNJSEFKd2kyYnRVSjZRPT08L2RzOlNpZ25hdHVyZVZhbHVlPg0KPGRzOktleUluZm8+PGRzOlg1 24 | MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJREdUQ0NBZ0dnQXdJQkFnSUpBSlFkL1JTSTUx 25 | dEtNQTBHQ1NxR1NJYjNEUUVCQlFVQU1DTXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdk 26 | cGRITWdVSFI1SUV4MFpEQWVGdzB4TkRBek1UZ3lNRE14TUROYUZ3MHlOREF6TVRjeU1ETXhNRE5h 27 | TUNNeElUQWZCZ05WQkFvTUdFbHVkR1Z5Ym1WMElGZHBaR2RwZEhNZ1VIUjVJRXgwWkRDQ0FTSXdE 28 | UVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTHhlcmtVUk00Njc4bnVmdDdMUUk3 29 | ZzVqeVNVSHdIUk9DaGVBVnQra2VtVmVnN0pORnpQYUYxQU9tMm40UzR4cTRhSTAzL0hXNzI1c3ha 30 | VEpJaXQ2VEJTaWJvQzZ5dU4vY00vbXp3amhiVitnQ1FSejJEckk3TWtHR3VqbjViSCt2dTNxenhw 31 | WFNvU3Fya3VIV3JkZU5HSExCUDBDLzBwSFUyUlpKT0dHMWgrUyt0aVcrRUdLejFQSXRmTDdtZzhW 32 | MkVoaWVVQllMZ3hHeFZzTll3dEw3ZFdjaWI3WTQ0NzZZeDI1ZDM0azFJZ0Jydmt5bzN5eDFHaXp3 33 | RzAwKzBGUjMveWtNWU9leHdpWnpDcktiWm96MUJmMGl0dTl2cWpiekR5OWdia0VRQkljWnhwRTVH 34 | T3dBdHlMTktnQmRTeUZqM3piUlRVSXlPdE5kVHY1Q04zNFdNQ0F3RUFBYU5RTUU0d0hRWURWUjBP 35 | QkJZRUZGSVE3cjBzb3BuL2g3OXBYMXFpUWFXemNNR29NQjhHQTFVZEl3UVlNQmFBRkZJUTdyMHNv 36 | cG4vaDc5cFgxcWlRYVd6Y01Hb01Bd0dBMVVkRXdRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFRkJR 37 | QURnZ0VCQUhjTWZFQXN3bVNWUnNSb2ZhaWJMZVA3MkhtOHp1dGIyNW50cG0zZ2NhaytEaWtFNFp3 38 | SS9IR1l3MllwekdaOXY4eXN4Yy9lZ2M3bExLbit5T2xPYlJkSUZKbVh1NU1TZjBHNkQ1L05SdjhS 39 | YWdDYTN4NktnamdaT1R4NU1OUjhLWDJ5NzliT3VwTU1qL1BuSTRqQTJqWGJGRlNVd3o2TVFGUC80 40 | VnlobHBZcWRobjNRcHV1OFlWclc3S0hjWW02UlFIbHJDNzBXQ2NmWkVXTEVIalUvdVJ3RksxK2hN 41 | c1VMYmJ1M084L3ptSnNVNk80YjJaYmpDb1B2c0FaWVBLMC9PSllieVV4ZnBmSFo4MkttRjI2MUhF 42 | S0ljaEVXUGtwaVppdnRyUGZJT1pGeTZpVjRidDBQVC9TR29JYktPeGgwTnh4eXQybUhucGQwMzB0 43 | VVhOWUxUYz08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48 44 | L2RzOlNpZ25hdHVyZT4NCiAgICA8c2FtbHA6U3RhdHVzPg0KICAgICAgICA8c2FtbHA6U3RhdHVz 45 | Q29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+ 46 | DQogICAgPC9zYW1scDpTdGF0dXM+DQogICAgDQo8c2FtbDpFbmNyeXB0ZWRBc3NlcnRpb24+PHhl 47 | bmM6RW5jcnlwdGVkRGF0YSB4bWxuczp4ZW5jPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3ht 48 | bGVuYyMiIHhtbG5zOmRzaWc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIFR5 49 | cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI0VsZW1lbnQiPjx4ZW5jOkVuY3J5 50 | cHRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNh 51 | ZXMxMjgtY2JjIi8+PGRzaWc6S2V5SW5mbyB4bWxuczpkc2lnPSJodHRwOi8vd3d3LnczLm9yZy8y 52 | MDAwLzA5L3htbGRzaWcjIj48eGVuYzpFbmNyeXB0ZWRLZXk+PHhlbmM6RW5jcnlwdGlvbk1ldGhv 53 | ZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3JzYS1vYWVwLW1n 54 | ZjFwIi8+PHhlbmM6Q2lwaGVyRGF0YT48eGVuYzpDaXBoZXJWYWx1ZT5XblVOTFJxdEhHa1hPbjF0 55 | SnNhVmgzQXl6dkw5K0ZySlljaHhOQW5GQ3BlVmxuZ0gvaDNwUjhZS3RuQVhLZmR1Ui9rVW11UTRV 56 | OGVteHA3Nzl3Y2MzamNjRGoyRXF2U1JYbDQzNTJIa0FVd09mNnlnN0VESC8xSnhTK2xyUXVEQndP 57 | MkwrZm1aNXJHM3Y3S3h5anNvRmpjK0M4WjRjSmhOS1g3K2hTMlFsQXB0Q3pDZjVIcGlpOExvSlU5 58 | OW11K2RyR3JGWWdQOUlleEM2clhkSklDYzNjcFpYdnd2SjQyWHF4eWpTb081NzlhWUxXS2RXY3ZV 59 | UVZIV2hMSG05eE0xZDlUQ0hhUStENDR5TDNsS1BlYkFTTGRscFVmd0tldVBLNjJGZDdOdjg1WnNp 60 | VjJvVnhHc1JlZmJPc0ZOYTBHbkxTSkhKU2JsRmJmQ0J5S2hySFdwU0E9PTwveGVuYzpDaXBoZXJW 61 | YWx1ZT48L3hlbmM6Q2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkS2V5PjwvZHNpZzpLZXlJbmZv 62 | Pg0KICAgPHhlbmM6Q2lwaGVyRGF0YT4NCiAgICAgIDx4ZW5jOkNpcGhlclZhbHVlPm5VQWI5N0lt 63 | K28wTzdKUXd1dUdXTXR6T0dITGZxcVc1ZVRlY3o2WHdFZXYwbUNwbGx5UVM4R2JxSFhwNUVqVXF4 64 | NXM2Y2tyeVF3SitrL09PblEwRVZ1QjErREdVek5jYzgyRlkxdDRPTUYyYkZ1bVFQbytvRm1FMjFq 65 | RzJyWm84WUhXcjMzSFQzYm81WGVMT0NScExURkcvWWdpTkg0WTdHWW5UeEsvV2VLZTdSZmNPdkE2 66 | YllwUXlnNEJtYXU2WnhwWWlONm5nTGxRajJreGxSR0hucjFmNHhVRm4xdEVYb2E4Rk0zQU53YkpV 67 | ditXclhLeGY5Z2QzVkhvVy9lb1Q1ayt6cS8vVXozeFovUE1YQ2t5aHhqdHJrMWFsZFUweXBCMW5V 68 | dFBqNDdJQzRCSHdpdXRKZ3hMTGk0a29rUW9CdHVNTzcxckNHN20xVVBSNmMvYnV5aWhjL2dEblE1 69 | VnYrc09zZ3RQNTZ3aHk3aHlZdWN4UEQ1MTBJUjZXMkluZDBaeXlzcHA0ZDNSbWVwc0lGTURzZnEx 70 | OFc2TFphVENRUndMcjU2TkZSYm4wWnpqRGMvRjRBYVNaZXhXQkxIOVRvQnF3Q1Z6QzZqK2Y3RjFo 71 | RDBxUDFPY2dXb3BERXh5U1ZZQjVLSkJSMFAzSERQVnZYOVZjVTdpS1ZJUE1JUVhIVUZ5TEI5WVo2 72 | QUwreC9QL0dpNVBvdzBIem5lNE0xc0M5N3lnNUR1OFpUL3FzOHEwaFZyZ3k4MHlUdGN1cCtWSGVP 73 | ejN5cVVpVjA2SVZUdXkrQ0c2Vm00emptd0Ywdm9wbmpxSnBJV0YzLzd2WXNRZmJTSW5XdDlHTXRm 74 | L0E4MjVuL0YvLzFacEYxVC9KcUxUcEdzSHM0UWJkRHQyaEd6bnU4clp6ZzI2Tk9XS0dMMFZ2bXRC 75 | Z3JlVk91Z3JWK1dxQzZ1bGQvSllhRWYxU0pzTTk2RnF3cjBObUl3VkRYSTNPc2V3N0JEZEw1U0VF 76 | dFBUYXhxV21ZcmxqZkZmdE1zS2xhQXp1N0haY1NVdmYvMDE0aG1CYmkwWmNzdXJlc0FQWDJRTnFC 77 | QmgyUWJveU0vdFUrcWUrdjF1bDEwNytkSzRUZ2VOaEFrbDBxZ1NSbDJlTU5CQ1lFT0RGdHdEZklR 78 | N095S09aRTMybFc4ZnhpTFd5ZXg3cXM5Q3dqQjg0R3grRjI1ZUpZT1NMSS9MbzFKOHhPTHFTdVJ1 79 | SGI0TTY0em1GcmpQRDR3Y3FGdm00OHdlM1pVT1VFSERDMlg2ODI1aDlkb0RrK0QxbWRSaDdweUhH 80 | dEJkejU0eE5OZWo2OWRtTzRCQXFkSGV4QTZDT04rM053TWFtNlpiaGZuUTZKbHBlSFJrUWc5Mnho 81 | dXdjcFpqOWxqZEk5dmxTOU9OV0tPSDRmMGN0dTRHN3hTY3BqQ2ZKQVpYbjNmY3hINlNVV2NoNVBt 82 | T2FhVWs3QkZkS3U3c2IrV3IzRVlrMXdheGlrbjYzR3Vya2tVYS9mK2NXQ0ViWVV6WXVpRzlKZFFR 83 | dStQR0plY2l6SnNtYS9pUU45eDVMRlBTZzNONC9ESmZ1bkVPczdrb1c4RkdNM1VnZ2d4dTdVcWN5 84 | UTVaYS83VVZsaDJobVBabHNPUzRZUjY4dlRxZmlWMEJXbHZjaGhOTkUxcS90WE1jMXhzYWxiVTkv 85 | OVFXMXBsWE8zMm9Bd2o1Z0htK3BEUklJbmpESjA5MUxRM3ZzcHhlQW1icDliQWIrMkQvQ0lyWlNt 86 | TFlYWTE2OGhhaVRRT2FER2V3bThJZ3JteVJ4RFh5MFgxTlNBYS9VOUs3eHI2VjVYaGlVQVZ1clRj 87 | d2NaZ01TTktvRjJZcDJaOWoxOHdIaVNPZ3dUZ2tuVDdGeCtwTzFXUTFQT1RSZDdiRmt0ZTB0dmtQ 88 | UGgrbUpONHJjdjdmaU95Y2hFZ3JHWDVKOGFaeWVJOS9hemdEQlc3RXRNSEVjSGpJMkxUdGxHV2hv 89 | MFY4QW81RXdPc3d5ZEVOYk1BRTVQaFhYTXNvZFF3WnZtS2RLelNQM1pEdVRIUlFlR3E3cHNjUHNt 90 | MVhEbWVsWThRRHgvOEVBaTcwMDcvZXlwNGdQSmVQU1ZRd2xyRmphc0ttK0tXUHNTalhuQkxmdU81 91 | YzhWekgxYTA5OXZQcWE1WUMxUFFHT3dweGRDcVBuR0ZsbitqU2tOaGkzUHE2SjZ2Yk41Zm1wUEt1 92 | blpLN2NhOW91VzRpWEUwaFBoT2N5eG1mRXlVeEdzT0FrS0pQZWc3UlY0TFJ6QzZwdHBJQ3NDVzVP 93 | T3VuZ25YVUhJVlZ5UTdIV2w4QU0rR3JSNlYwYnYwRHI4d1NvSDJqY2pETHJWMUR4bWZLY3dZMVdi 94 | VTR2RFpQSmIxQWcvOXNlSTRHcE5iMjhXZmNyOUFDYXZVbCsyRFY0dlVxSnJEUEUxcEcxVFZtblB4 95 | c0JzSG1EYk04Ri9BSlF0Y0ZDTWI0UHA3V28ra1N1VjVVYmw5a0dFQzIrRk5FU1pSbHZVMU1TTThV 96 | QXhoZDh6dE5NcXIrVTExQzNiZXFqNloxaU9XQzdtVVNXSTIwck9nK04vQmNKVVJGeDJqOUFaZ0ti 97 | enZwR3BuK0lEUlFwdksvUms9PC94ZW5jOkNpcGhlclZhbHVlPg0KICAgPC94ZW5jOkNpcGhlckRh 98 | dGE+DQo8L3hlbmM6RW5jcnlwdGVkRGF0YT48L3NhbWw6RW5jcnlwdGVkQXNzZXJ0aW9uPjwvc2Ft 99 | bHA6UmVzcG9uc2U+ 100 | -------------------------------------------------------------------------------- /test/data/response_notbefore_future_signed_then_encrypted_base64.xml: -------------------------------------------------------------------------------- 1 | PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6 2 | cHJvdG9jb2wiIElEPSJfMiIgVmVyc2lvbj0iMi4wIiBJblJlc3BvbnNlVG89Il8xIiBEZXN0aW5h 3 | dGlvbj0iaHR0cHM6Ly9zcC5leGFtcGxlLmNvbS9hc3NlcnQiPg0KICAgIDxzYW1scDpTdGF0dXM+ 4 | DQogICAgICAgIDxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FN 5 | TDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz4NCiAgICA8L3NhbWxwOlN0YXR1cz4NCiAgICANCjxFbmNy 6 | eXB0ZWRBc3NlcnRpb24geG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRp 7 | b24iPjx4ZW5jOkVuY3J5cHRlZERhdGEgeG1sbnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAw 8 | MS8wNC94bWxlbmMjIiB4bWxuczpkc2lnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRz 9 | aWcjIiBUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNFbGVtZW50Ij48eGVu 10 | YzpFbmNyeXB0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94 11 | bWxlbmMjYWVzMTI4LWNiYyIvPjxkc2lnOktleUluZm8geG1sbnM6ZHNpZz0iaHR0cDovL3d3dy53 12 | My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+PHhlbmM6RW5jcnlwdGVkS2V5Pjx4ZW5jOkVuY3J5cHRp 13 | b25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNyc2Et 14 | b2FlcC1tZ2YxcCIvPjx4ZW5jOkNpcGhlckRhdGE+PHhlbmM6Q2lwaGVyVmFsdWU+TUgvSElYMmw5 15 | QVA0c1dJRmhCeTlKYm9ZWHd1eXlaRU9HSEtveW1helovdHZMRE5JZGxsbGs0TjZrbjU0cEdkdkNw 16 | cTJ2Z0EyamRCdkcydVJ6eVZrQU5aZGI2RWFMQ3RWaE5wRUl5cnkrbklhVzJ4d2hwL0lHU0FmbU9H 17 | eTh3MGc5Tjhqc1lxZ3VlK0wzQ3VjbUIzUkh2eUF4ODV5N09DV3Raa1Jkd3JMbi9YL1lBOGYxZGNa 18 | ajd3MkRPN21WWVhybkl4OEJVTDNDc3JQNU0vSUpWdjZ3UldPRTBzRG9iSDVFS1FBSmtUQWlhTDMw 19 | dHdHOVA3WTJiYjdtekQzN1F4cVJUY29tMjh0Ry9DQXAydlBxaitCdWdYeDd6Uk1RanhkZk5Cc1RV 20 | L2FvYnp5WDFEZWJIazJzb0ovK2tFTTF3UnBRNnpXeUFONVpRNHlta2wwcjdVS053PT08L3hlbmM6 21 | Q2lwaGVyVmFsdWU+PC94ZW5jOkNpcGhlckRhdGE+PC94ZW5jOkVuY3J5cHRlZEtleT48L2RzaWc6 22 | S2V5SW5mbz4NCiAgIDx4ZW5jOkNpcGhlckRhdGE+DQogICAgICA8eGVuYzpDaXBoZXJWYWx1ZT5n 23 | c3hwZUNPM0JpelpqMVpxZ25HR2lMVWN6cFR3SUM0bjlMQ09VMEFXdUxSdndRUmJmRHQyOVdJNnJE 24 | RGpHWVBXUU03SFRTWC9WTVVoRzQ4YnYrWjdEem9qbmpWOExZaXF0WVF3ci92ZWhpODg1ZnlvNlJZ 25 | cVhpb1cxbERDMHQ4YnNRaXpscEpmSzB0SkFEaUxiQnNubWRZbU9PeURSVHp2Wm9teEZFN3ZKYmFC 26 | NmdJVXhOa2I5MzdnUVo2VnBtVHhpSnJwRHQvZFJ0VmFLRmlBNWlWYmZyTDBnME1BeEZyYUVnalhr 27 | MFd1akdHc2t6bUNjcGM5bUtmS3VMS1h2bXR5M1pRTXU5Zk9zUUJEQW9odjBrQjVKOFpESVcyNTQ3 28 | akNDZVRqT256VE82RVJFNnlFcHhpV2V4Sy90VUFFT2NYY3U1aTV4cWM4ai9MclZxTUhxcVNuTlVW 29 | R2JZUFNvUGlhbXhhbjQzTzM2bkdmU3doRWd6ODBzdXNGRFFSOGV5Z0k1WkQ4VDZOQWM4LzZyd1pK 30 | eW9uMmFBczgydk5iemo2Ymo3ZVJ3K3hGS2dCNDFMRUxna0UvUFg5VDkxdDV1a1RzbVJyNXNnam13 31 | TWEzT0E1WVVYYy8rd0YyZVMrTlJiOU0yNmtYcU95aVpaQWhraXJudVhLQ0kvMTZ2aE9CbUJPRzRR 32 | ZVpaSC9OM2VIUmpMS1l5ZVRRclBSY2Q0SHplY2NjMGs4alRUQkZjMFJ6YTBTaERqYVZjQXE5WlIv 33 | Vmd6NExSc2FKMi9Gc0tuLzBFRCtrd3BRVmgzT0h5Zk5HMGpPUHNEUE8xeXFuenNBeStPZHFudWgv 34 | TzVBUXhZWHlGZGw1YXlyd2ZzTzNTY3BGWEhWWkRPMEZYSnpZOXQ3TndFNlRtdzRVVG1QbHIzNGE4 35 | T1ZOYU5NdGxXSHJFb2xOZG9YdStiNGZvQXljV1pxSGlnVXFJSDJpU1lRcW5nNHlqOVIvaHBEY01y 36 | STYyakZLWjk4c2pGaW8yVXNwVURXc1hXdkdSL0M1OW5qRy9EcU9wcUpKRHR6Q29ycXFtQktIOTRP 37 | WGxQUkJCK1FlUGlMaFNyU3M2UXhVNnA0cWIzTDkwRktsUjdhOG8waU1IbHBDYm5zZDZPekhoWGht 38 | UjhTZU1ET3BEWWhucStsUTJmcE5KVFFyOEtoUGgzYnBwekxIZTh5aWZQSDM0RTlVN1dvMFFTK0tk 39 | MWJaSzRPWUE5cWE0b0RhcVJYaXdGZnczWmRQS0RzbzZnTHQ1bkczVm1yS3dxUWxHNzZhc1dNbHhs 40 | QzFMbEc5QkFlWGM1ZnhmazU2OEl0VGJkSmp6ZmUyczZpY3NYaTkrcjA0OTlpMEt0L3ErTTFEMUZt 41 | dUtkRGl1cUNvSXQ2dDZLbEVldDNZT1Z0MW1lZUxuQnlHTmpVanFRQzVnQmRSM3pTU2ZYcmJoOFFx 42 | RitQQU4vUUp6OHlNSDF1UUlCUndZTnR6bTRXcjhISWN5d20rZm9aa1BoeGh6R0JaeG80cHp2K28w 43 | anZOeWZXbmltT01jYTM1OERtZmZPa0hvY0lKMWs5QlV2aUpIMmwvZEdwbFRzcVhTT1I3NW5nUUFa 44 | R1hFMVArNW9QVTRtR1cxbjBpK3RqNkc5S2ZqRm9Lei94cmpaa1BXM2NVVFFhU2g0Q05vR3YwK2p2 45 | WG54QmZzdmFzNTVzUWNFWEtqUDNGck9selV5UkR6SUVjNGRjbHZSOVZwRzVLKzNqZHRWU3lIcTJW 46 | eWcvMFRuZS9ydzhqUEhEdS85WTFVVzRYWFVSWjdQd0dTKzBlSmhoVzlpMXVZcFJrb0FWc1IwOFdB 47 | bXg4WFVQL1NGTWZqQVhuVWY0Uy9OSGJqcUVBQXNwblZPUHJ1ZUhtWnlVRTJRQTlEUGtCcEdJOHRr 48 | SlB1QWY1eTFUQ1dSMDF0U0E5Zzg1d3EzNTBRSWlMNzgvT1pOdjZkTVQvMDhQZ2x4ZjJFdEpUQUZT 49 | dEsrQVRuU0w1Y1p0MDRCSFpIMWpEWDJHZTBwaEhBUTEwTVZEYTNTU2o0QjR2TFdLSDR2Vm9QRTZX 50 | VHVpZVdGMmhaeEE2RGRMNTlrWFRMV0pYSHNBOUNTaUZ3dTNsRDZaK05IVVgxR0J3Z3lJL3ZNNUhz 51 | cVg4Mk1Xd2E3SW55WnZpS1llTk5rdXBZWkUrN2Vaa08waUQxeWFFQVlVeUtnN0NsVlpnWmo5b2Jv 52 | cWFVbDZBUnJmV1M0eXJraG5IUmdBazFSZ0tLODlPWW1YVUhBNmFQemJTaDVuOHZZUzYwaXdnTkN6 53 | bUlha3lUc2VnVzFZbVN4Rk53SzRlZG5XTVc2TlFkanZhRWRnYVZFUlZDRXg1bmxrbEVvaDJwTFFa 54 | T0hSYVVDblhrRzN5VWJ0R2QyM0F4WndIY1JnOFpxYVEvOVpLL0tpSTd1eWFoWHIrU0xiQ2E5SU92 55 | VEVucnN3SjFBSm9zTGRCbjIySktVME1hU0JyQThBL0RWd3lWa0JEOGNNWHlkcTNMblVib3NBODBH 56 | QkFGUGcycS9sVHNZWElCWUZKZktrYnlEb0I2clZ3Y3lSL05jL3dTbUpRUkZud3lCZEE3RFRhQVhN 57 | aGNXUzdwLzNZdVk1RmVZVjhEVTd4bWtlRmE4d3J3NXQ0OFFLbGxGQitsbTdSak15TmNYQXE0Ylgx 58 | bEcyUEo2Um04RzhrNmozTWNsV1FYcGVRSThuKzJ0d0dzV1FhcWNOUGJ0SXpWVGE4M2J3TmF3emVv 59 | ejFlL0txcXZGU2xackxMYXR6N2xYcUp0VFZqU1BuMXpZYis1ZVhyRmU4MFNlTzE4c3hGWHN4bmw4 60 | VS9PVlRvRDV1eHREOFJzSGpqRjVjTVYydkY0ckdGTkJjbno2Ukg2QTNkd0hCdlo2NFE1NFUwb2N6 61 | ZzZvSUdCbnMweE5NOUhVREE0SVFBYUdrU29HWTdzVEp5djB5Tjk3ZFMvSWVIZVV2ZXh2ODZlSFVl 62 | b2t3QXl1Yks4Z1JCQTl0a3F5Mi8veStCM1VlaXArZm9UWGlLaWt1dTFkN2p1bWpxYmE5MDBpRFUw 63 | MTRkVkphVU9LYkY0TE5XZG9PNkh4NTBoOEpoNjlVSS9LTnQ0TU9VWVFPNVZJaGM3OEJpUFRScjhE 64 | dXdNd1FTQ090RlYrcSt0VUxnK1UxRVpaVjdqU1F5NWJGN2lJbzJlN3BBMGRSaGM3aXVmV21NN3B2 65 | bzNIRU5ZNGFhZDVLdXM5VXNYWG80K2V2aVdiOXU5L2FtWFZwbWJyNTdmUmRmZGZXUHd4cmlFTGNX 66 | RVRiUWxUdTY5c3lPeTc0TTdmckt0TDg1bUJWRFRJenlna3lzWVIrWlNXMEVvTU1PUUVrOStkSkhX 67 | Vk1rRjhlVjNCSDBYbFkwczNFNFpCdlQySWdFWUNvd2YzS0FqUGJKcDE4N0JvWDN3Z2E4c2hpWnR4 68 | K0gvNkRZekxxeHV5c0JPVnl3eHVnOEx2Zk9wWEJiR0NoMWpOUWQvMnU5VVBxNjJVbnNJR2pqVndZ 69 | bVpSOW5IZHVWTTEvd3JUTkJOODVKems5ZzczdE1vK3RFRFNpUlhWZEdVR3crcVJmdjJHM3hQUFJJ 70 | NVRhb1BkRHlWWGFOSGwydWJlV2lGcDE3TDR2S3lOemp5VEowbDZ2dng5WE5MRy9oM1NUOHN2bGVx 71 | cXpvTzRwM0ZseUt4VGNQWkxINXc5cW5nbTlSdktsc1hjcU84ZVBxMWZobkxPNlVYNDBxcURKWThY 72 | NXNTVHNyK055QzdNQkF5K3lvWmlnQURrcDZ0RE5VTVJMMmp5UHI2aWpFRjcxUkVzald6V3N1Ylps 73 | Qkp1SGdaclR2dGZRT3dnUFNrYWlCQzdjaUdTUUlSeDhUaFpiNzRMOTVMbkFNakpMRkxqdVRxZnFs 74 | N2JSNGRTMyszWDI1WVRGb2E3Tk44T1FyUEJkUGNkemozNUpIR3Y4eGRZcXg3L1BCdTZ5aGhiaXdm 75 | Y1lpMFlqMm5sR3laUjFBenJTWVhDN1c0S1NlVTZjaDZXRmNzY280em1KL1A2TlMzQjBtRHJTNks2 76 | YzgrRTNuVU85VTZkSkJDZWdSb1VlclZCLzFXNFRIMjJMcWRycm1CUWoyaDRFb25CS0E0TFJjTXdo 77 | VEJMS0srM2lOdEJaQUR6K0dTYlVJOE9NRCtMV1dhU3p2RlU2Q0lPNUNZcVM4aDFzb2puM1lmQXYv 78 | YUR2RUZjRm1SQmpva1A4bXJzT0V4NGwrUTBrOURUTzRjdkMxQ3hHRlUxekZZUWNZMHZ6TkZKZTE1 79 | bjQ3RmZwbUFKNG5xRWpkK0xhOVBOM1c1UElOazlaL09reHJYeWZLTkZ5TUlEa2lWMkp5Qm85NU9S 80 | UGVYSEhFWEtkQWdsRGxscEllMmtpdTk5RnlSSlV6NmZNc2pEL3NYOVBxVGd1TDZ6L0dzN0taMDFz 81 | Q2ZudGtPZ2pQam9kb3YzWHFGTWZKRFFkVmYvVjQ2KzE5elhmdGlOUWcrNnU5WXF6MzN5c2QwSGVk 82 | UWpTekdBM1JWQi9EblRaenJjaEkzbStVQnZvTmNCR1ZtNFhlKzQvSkMzWWx1NDZOdHUzME1JT2kw 83 | cHZab0hoN2pwZzZMaENEbDBYdGd4Mi9PWXVVd0NzU3dtUk1QTEQxZHRRd1hNYy9FVVNJZjVBY1h2 84 | anI3TDgrN284eWs4RWpaRkRnTWw5eVVneEM4ZENzN2p4VjRFRWRKK2hkU3FMZERBZTZSTnpyQUEw 85 | cUVVZFhIOGpRWEd3NFJxOFNvRnFkakZVMndjR0E0VFpVelFuck15S2dOdVhPU2hGMmFtbEJocmlP 86 | T2hTT3puSnFxVkU0NTVyTXdHRE84NXFxUWp0S0RzdzlKcnY4NjRVTUJpbmhmOFpqaW54Y1orZFFU 87 | cjhNL2djMERjSWhaTlBZdGZQOElBMlZJRm1TR3llcm9tTlNML0krejk3N0h5blhTZ05ZY0lmcU9E 88 | WklnaTRCUmpaek94enFCQmJWOGVHeDhYU21SdWVjNnFkMmI1aThyR0lCWHZwZ1pGN0ZUTEFEVFRj 89 | ZU9xUy9xendsQm9mVFRZN2tPTFFYTFlMamFJcG1yZGVXNS9TWWZCOFE1dyt3RDlxcWNMczFPYXRI 90 | R21KTnRhZDFsUWUwNFpmUVlRVEtnVjU2MmV1cUxNZWpUbkV6dTFEcVk2czlqNW00eHdVL2QyN2xT 91 | Q0dCdHZBbXlwQTdqbnE5WURXa0tZQlVRWmVKNjdTWXlLN0VHUUVlcDYweUM2eDNtNWt3U1VHYTMr 92 | amJLYzVINU4xajJ1akhNbEhDTGlFWWM5K2NFYjBvQmhHajZ4bEpSbHhTcitpalQ0NlBrQ0ZlYTh2 93 | L1FHTENlblFBelFqTUVvSDM0b2xTQnRSZ0lXRHFpOEVCZjM2TTgraDQzTHc2Y21JRkdyYllFUUN6 94 | Z09kN1VzMzlkYVc2R2gra3VvVTJvdFNnVGw0NTh4ekhNdCs4N2hwbm5aaTdXTmdNUGhFRFVXKzdD 95 | YllYZzlWWCt6TFVrTFhnQlRrNkpCL1RnRXUzc1J1aVBJOWQ4S2lRcUNzVUVVK2dCYWhSeGdDRzZw 96 | N2ZJd1huR1Y2OXZVa1ZvVFd3eWxSWHdUcnJBOUdXQ0crM29pNkFxT2JoajRCTW5WUW5GalByT1RK 97 | WG1iajRUdFZKUUNKYkpTdjF4TGtyMVRxak12MFV4Y0N3N0EwY0pMbVB6RlZ0aWFVa2k3aXowZ29v 98 | SW1SYzVzdVVsMkxRZlZUYjNyVWZna3A0RXl5ZVo4a1lMNE81eDNYVkEzalgyU1dnbWp6ZGVYTFpk 99 | RGpLWlVxclNONFBydmlJTVN5TVUyTnEzdnNra3N6VTFoYU1jbEZPd1BqMU94eSt5bUYvL2NpcUtz 100 | OUdWVXpDRkl2Nno0N1QvZjVVamYxVGFZM1NybjdwSk5QMUVIZzZHeVVONWJEaS9HQlZNdU5qTTAz 101 | OUN0a2VGZnprbGNrK0dyeXJhYUh1bThRSklZeFJ3UmNVQnlqa1VDUmdVUUtVb1FXVTQvNWZEcG1M 102 | b04xQVFmZS8xaW15bVlOUkt4Tnd2S3ErVlhuWTc0OXZWdStrZThCM25IU1BicWtxMGh3WFFFV0hO 103 | d3c2UlZFYU5vV0JTZ0pEci9PSzAxdlFrWGxjMWNLanJ0TkJxWjFQTGVpVE9Rby9rVVMreHZTSnV1 104 | S0pDNm8vY2VERWpCekdmajV3eTN1VkNVRGRXTyt2QXpSVnErcWIrYzk1dUFVUXMrejRyVXBobzZh 105 | a0hlayszQXVKbFZoY09BRGJyMEIzZ25mQlVTbTJrSkVlNjNRcDl3M3BjVkJVdk8wMlFMM291Q1hE 106 | RmNJa3lFbDFLYUo0YXRReks0SnplOTd3NVVXWENPaks0L00wZU9zMkhJMU84aFZyb1NaZnBhN05N 107 | anhBMG9kOUNKR3NEZGdBVWQ3eHRnUnZQT2l0THlKNVphOWJmU0tJTld1eUMwYnN4d0tVZnhJcHli 108 | eE15cGJESmlrSFhTRkRBNEZJaGxTQml5VzNXRm5rWU90OGVTeU1zbVY0UzhhMDczejBHSVk3ZGxu 109 | djR5TVdBSEVzNG1KZVprVmptWCszZ3doSjwveGVuYzpDaXBoZXJWYWx1ZT4NCiAgIDwveGVuYzpD 110 | aXBoZXJEYXRhPg0KPC94ZW5jOkVuY3J5cHRlZERhdGE+PC9FbmNyeXB0ZWRBc3NlcnRpb24+PC9z 111 | YW1scDpSZXNwb25zZT4= 112 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2014 Clever, Inc. 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Maintenance Notice 2 | 3 | This library is currently in maintenance mode. Until further notice, the primary directive is to handle bug reports and security issues with this library. 4 | 5 | Any library alternatives and suggestions can be filed under an issue. 6 | 7 | # SAML2-js 8 | 9 | [![CircleCI](https://circleci.com/gh/Clever/saml2/tree/master.svg?style=svg)](https://circleci.com/gh/Clever/saml2/tree/master) 10 | 11 | `saml2-js` is a node module that abstracts away the complexities of the SAML protocol behind an easy to use interface. It achieves this this by helping you implement a service provider for the SAML protocol. It currently does not implement the features to act as an identity provider. 12 | 13 | ## Usage 14 | 15 | Install with [npm](https://www.npmjs.com/). 16 | 17 | ```bash 18 | npm install saml2-js --save 19 | ``` 20 | 21 | Include the SAML library. 22 | 23 | ```javascript 24 | var saml2 = require('saml2-js'); 25 | ``` 26 | 27 | ## Documentation 28 | 29 | This library exports two constructors. 30 | 31 | - [`ServiceProvider`](#ServiceProvider) - Represents a service provider that relies on a trusted [`IdentityProvider`](#IdentityProvider) for authentication and authorization in the SAML flow. 32 | - [`IdentityProvider`](#IdentityProvider) - Represents an online service that authenticates users in the SAML flow. 33 | 34 | 35 | 36 | **Note:** Some options can be set on the [SP](#ServiceProvider), [IdP](#IdentityProvider), and/or on a per-method basis. For the options that are set in multiple places, they are overridden in the following order: per-method basis *overrides* [IdP](#IdentityProvider) which *overrides* [SP](#ServiceProvider). 37 | 38 | 39 | 40 | ### ServiceProvider(options) 41 | Represents a service provider that relies on a trusted [`IdentityProvider`](#IdentityProvider) for authentication and authorization in the SAML flow. 42 | 43 | #### Options 44 | An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 45 | 46 | - `entity_id` - **Required** - Unique identifier for the service provider, often the URL of the metadata file. 47 | - `private_key` - **Required** - (PEM format string) - Private key for the service provider. 48 | - `certificate` - **Required** - (PEM format string) - Certificate for the service provider. 49 | - `assert_endpoint` - **Required** - URL of service provider assert endpoint. 50 | - `alt_private_keys` - (Array of PEM format strings) - Additional private keys to use when attempting to decrypt responses. Useful for adding backward-compatibility for old certificates after a rollover. 51 | - `alt_certs` - (Array of PEM format strings) - Additional certificates to expose in the SAML metadata. Useful for staging new certificates for rollovers. 52 | - `audience` - (String or RegExp) — If set, at least one of the `` values within the `` condition of a SAML authentication response must match. Defaults to `entity_id`. 53 | - `notbefore_skew` - (Number) – To account for clock skew between IdP and SP, accept responses with a NotBefore condition ahead of the current time (according to our clock) by this number of seconds. Defaults to 1. Set it to 0 for optimum security but no tolerance for clock skew. 54 | - `force_authn` - (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the [IdP](#IdentityProvider). This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis. 55 | - `auth_context` - Specifies `AuthnContextClassRef`. This can also be configured on a per-method basis. 56 | - `nameid_format` - Format for Name ID. This can also be configured on a per-method basis. 57 | - `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis. 58 | - `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis. 59 | 60 | #### Returns the following functions 61 | - [`create_login_request_url(IdP, options, cb)`](#create_login_request_url) - Get a URL to initiate a login. 62 | - [`redirect_assert(IdP, options, cb)`](#redirect_assert) - Gets a SAML response object if the login attempt is valid, used for redirect binding. 63 | - [`post_assert(IdP, options, cb)`](#post_assert) - Gets a SAML response object if the login attempt is valid, used for post binding. 64 | - [`create_logout_request_url(IdP, options, cb)`](#create_logout_request_url)- Creates a SAML Request URL to initiate a user logout. 65 | - [`create_logout_response_url(IdP, options, cb)`](#create_logout_response_url) - Creates a SAML Response URL to confirm a successful [IdP](#IdentityProvider) initiated logout. 66 | - [`create_metadata()`](#create_metadata) - Returns the XML metadata used during the initial SAML configuration. 67 | 68 | #### Example 69 | ```javascript 70 | 71 | var sp_options = { 72 | entity_id: "https://sp.example.com/metadata.xml", 73 | private_key: fs.readFileSync("key-file.pem").toString(), 74 | certificate: fs.readFileSync("cert-file.crt").toString(), 75 | assert_endpoint: "https://sp.example.com/assert", 76 | force_authn: true, 77 | auth_context: { comparison: "exact", class_refs: ["urn:oasis:names:tc:SAML:1.0:am:password"] }, 78 | nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", 79 | sign_get_request: false, 80 | allow_unencrypted_assertion: true 81 | } 82 | 83 | // Call service provider constructor with options 84 | var sp = new saml2.ServiceProvider(sp_options); 85 | 86 | // Example use of service provider. 87 | // Call metadata to get XML metatadata used in configuration. 88 | var metadata = sp.create_metadata(); 89 | 90 | ``` 91 | 92 | #### Service provider function definitions 93 | 94 | 95 | 96 | ##### create_login_request_url(IdP, options, cb) 97 | Get a URL to initiate a login. 98 | 99 | Takes the following arguments: 100 | - `IdP` - [IdP](#IdentityProvider) 101 | - `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 102 | - `relay_state` - SAML relay state. 103 | - `auth_context` - Specifies `AuthnContextClassRef`. This can also be configured on the [SP](#ServiceProvider). 104 | - `nameid_format` - Format for Name ID. This can also be configured on the [SP](#ServiceProvider). 105 | - `force_authn`- (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the [IdP](#IdentityProvider). This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 106 | - `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 107 | - `cb(error, login_url, request_id)` - Callback called with the login URL and ID of the request. 108 | 109 | 110 | 111 | 112 | ##### redirect_assert(IdP, options, cb) 113 | Gets a SAML response object if the login attempt is valid, used for redirect binding. 114 | 115 | Takes the following arguments: 116 | - `IdP` - [IdP](#IdentityProvider) 117 | - `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 118 | - `request_body` - (Object) - An object containing the parsed query string parameters. This object should contain the value for either a `SAMLResponse` or `SAMLRequest`. 119 | - `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 120 | - `require_session_index` - (Boolean) - If false, allow the assertion to be valid without a `SessionIndex` attribute on the `AuthnStatement` node. 121 | - `cb(error, response)` - Callback called with the [request response](#assert_response). 122 | 123 | 124 | Example of the SAML assert response returned: 125 | 126 | ```javascript 127 | { response_header: 128 | { id: '_abc-1', 129 | destination: 'https://sp.example.com/assert', 130 | in_response_to: '_abc-2' }, 131 | type: 'authn_response', 132 | user: 133 | { name_id: 'nameid', 134 | session_index: '_abc-3', 135 | attributes: 136 | { 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname': [ 'Test' ] } } } 137 | ``` 138 | 139 | 140 | 141 | ##### post_assert(IdP, options, cb) 142 | Gets a SAML response object if the login attempt is valid, used for post binding. 143 | 144 | Takes the following arguments: 145 | - `IdP` - [IdP](#IdentityProvider) 146 | - `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 147 | - `request_body` - (Object) - An object containing the parsed query string parameters. This object should contain the value for either a `SAMLResponse` or `SAMLRequest`. 148 | - `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 149 | - `require_session_index` - (Boolean) - If false, allow the assertion to be valid without a `SessionIndex` attribute on the `AuthnStatement` node. 150 | - `audience` - (String or RegExp) — If set, at least one of the `` values within the `` condition of a SAML authentication response must match. Defaults to `entity_id`. 151 | - `notbefore_skew` - (Number) – To account for clock skew between IdP and SP, accept responses with a NotBefore condition ahead of the current time (according to our clock) by this number of seconds. Defaults to 1. Set it to 0 for optimum security but no tolerance for clock skew. 152 | - `cb(error, response)` - Callback called with the [request response](#assert_response). 153 | 154 | 155 | 156 | 157 | ##### create_logout_request_url(IdP, options, cb) 158 | Creates a SAML Request URL to initiate a user logout. 159 | 160 | Takes the following arguments: 161 | - `IdP` - [IdP](#IdentityProvider). Note: Can pass `sso_logout_url` instead of IdP. 162 | - `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 163 | + `name_id` - Format for Name ID. This can also be configured on a per-method basis. 164 | + `session_index` - Session index to use for creating logout request. 165 | + `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 166 | + `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 167 | + `relay_state` - SAML relay state. 168 | - `cb(error, request_url)` - Callback called with the logout request url. 169 | 170 | 171 | 172 | 173 | ##### create_logout_response_url(IdP, options, cb) 174 | Creates a SAML Response URL to confirm a successful [IdP](#IdentityProvider) initiated logout. 175 | 176 | Takes the following arguments: 177 | - `IdP` - [IdP](#IdentityProvider). Note: Can pass `sso_logout_url` instead of IdP. 178 | - `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 179 | + `in_response_to` - The ID of the request that this is in response to. Should be checked against any sent request IDs. 180 | + `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). 181 | + `relay_state` - SAML relay state. 182 | - `cb(error, response_url)` - Callback called with the logout response url. 183 | 184 | 185 | 186 | ##### create_metadata() 187 | Returns the XML metadata used during the initial SAML configuration. 188 | 189 | 190 | 191 | ### IdentityProvider(options) 192 | Represents an online service that authenticates users in the SAML flow. 193 | 194 | Returns no functions, exists solely to be passed to an [SP](#ServiceProvider) function. 195 | 196 | #### Options 197 | An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. 198 | 199 | - `sso_login_url` - **Required** - Login url to use during a login request. 200 | - `sso_logout_url` - **Required** - Logout url to use during a logout request. 201 | - `certificates` - **Required** - (PEM format string or array of PEM format strings) - Certificate or certificates (array of certificate) for the identity provider. 202 | - `force_authn` - (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the [IdP](#IdentityProvider). This can also be configured on the [SP](#ServiceProvider) or on a per-method basis. 203 | - `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [[SP](#ServiceProvider) or on a per-method basis. 204 | - `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [SP](#ServiceProvider) or on a per-method basis. 205 | 206 | #### Example 207 | ```javascript 208 | 209 | // Initialize options object 210 | var idp_options = { 211 | sso_login_url: "https://idp.example.com/login", 212 | sso_logout_url: "https://idp.example.com/logout", 213 | certificates: [fs.readFileSync("cert-file1.crt").toString(), fs.readFileSync("cert-file2.crt").toString()], 214 | force_authn: true, 215 | sign_get_request: false, 216 | allow_unencrypted_assertion: false 217 | }; 218 | 219 | // Call identity provider constructor with options 220 | var idp = new saml2.IdentityProvider(idp_options); 221 | 222 | // Example usage of identity provider. 223 | // Pass identity provider into a service provider function with options and a callback. 224 | sp.post_assert(idp, {}, callback); 225 | 226 | ``` 227 | 228 | 229 | ## Example: Express implementation 230 | 231 | Library users will need to implement a set of URL endpoints, here is an example of [express](http://expressjs.com/) endpoints. 232 | 233 | ```javascript 234 | var saml2 = require('saml2-js'); 235 | var fs = require('fs'); 236 | var express = require('express'); 237 | var app = express(); 238 | // If you're using express <4.0: 239 | // var bodyParser = require('body-parser'); 240 | // app.use(bodyParser.urlencoded({ 241 | // extended: true 242 | // })); 243 | app.use(express.urlencoded()); 244 | 245 | // Create service provider 246 | var sp_options = { 247 | entity_id: "https://sp.example.com/metadata.xml", 248 | private_key: fs.readFileSync("key-file.pem").toString(), 249 | certificate: fs.readFileSync("cert-file.crt").toString(), 250 | assert_endpoint: "https://sp.example.com/assert" 251 | }; 252 | var sp = new saml2.ServiceProvider(sp_options); 253 | 254 | // Create identity provider 255 | var idp_options = { 256 | sso_login_url: "https://idp.example.com/login", 257 | sso_logout_url: "https://idp.example.com/logout", 258 | certificates: [fs.readFileSync("cert-file1.crt").toString(), fs.readFileSync("cert-file2.crt").toString()] 259 | }; 260 | var idp = new saml2.IdentityProvider(idp_options); 261 | 262 | // ------ Define express endpoints ------ 263 | 264 | // Endpoint to retrieve metadata 265 | app.get("/metadata.xml", function(req, res) { 266 | res.type('application/xml'); 267 | res.send(sp.create_metadata()); 268 | }); 269 | 270 | // Starting point for login 271 | app.get("/login", function(req, res) { 272 | sp.create_login_request_url(idp, {}, function(err, login_url, request_id) { 273 | if (err != null) 274 | return res.send(500); 275 | res.redirect(login_url); 276 | }); 277 | }); 278 | 279 | // Variables used in login/logout process 280 | var name_id, session_index; 281 | 282 | // Assert endpoint for when login completes 283 | app.post("/assert", function(req, res) { 284 | var options = {request_body: req.body}; 285 | sp.post_assert(idp, options, function(err, saml_response) { 286 | if (err != null) 287 | return res.send(500); 288 | 289 | // Save name_id and session_index for logout 290 | // Note: In practice these should be saved in the user session, not globally. 291 | name_id = saml_response.user.name_id; 292 | session_index = saml_response.user.session_index; 293 | 294 | res.send("Hello #{name_id}! session_index: #{session_index}."); 295 | }); 296 | }); 297 | 298 | // Starting point for logout 299 | app.get("/logout", function(req, res) { 300 | var options = { 301 | name_id: name_id, 302 | session_index: session_index 303 | }; 304 | 305 | sp.create_logout_request_url(idp, options, function(err, logout_url) { 306 | if (err != null) 307 | return res.send(500); 308 | res.redirect(logout_url); 309 | }); 310 | }); 311 | 312 | app.listen(3000); 313 | 314 | ``` 315 | -------------------------------------------------------------------------------- /lib/saml2.coffee: -------------------------------------------------------------------------------- 1 | _ = require 'underscore' 2 | async = require 'async' 3 | crypto = require 'crypto' 4 | debug = require('debug') 'saml2' 5 | url = require 'url' 6 | util = require 'util' 7 | xmlbuilder = require 'xmlbuilder2' 8 | xpath = require 'xpath' 9 | xmldom = require '@xmldom/xmldom' 10 | xmlenc = require 'xml-encryption' 11 | zlib = require 'zlib' 12 | SignedXml = require('xml-crypto').SignedXml 13 | 14 | XMLNS = 15 | SAML: 'urn:oasis:names:tc:SAML:2.0:assertion' 16 | SAMLP: 'urn:oasis:names:tc:SAML:2.0:protocol' 17 | MD: 'urn:oasis:names:tc:SAML:2.0:metadata' 18 | DS: 'http://www.w3.org/2000/09/xmldsig#' 19 | XENC: 'http://www.w3.org/2001/04/xmlenc#' 20 | EXC_C14N: 'http://www.w3.org/2001/10/xml-exc-c14n#' 21 | 22 | class SAMLError extends Error 23 | constructor: (@message, @extra) -> 24 | super @message 25 | 26 | # Creates an AuthnRequest and returns it as a string of xml along with the randomly generated ID for the created 27 | # request. 28 | create_authn_request = (issuer, assert_endpoint, destination, force_authn, context, nameid_format) -> 29 | if context? 30 | context_element = { 'saml:AuthnContextClassRef': context.class_refs, '@Comparison': context.comparison } 31 | 32 | id = '_' + crypto.randomBytes(21).toString('hex') 33 | xml = xmlbuilder.create 34 | AuthnRequest: 35 | '@xmlns': XMLNS.SAMLP 36 | '@xmlns:saml': XMLNS.SAML 37 | '@Version': '2.0' 38 | '@ID': id 39 | '@IssueInstant': (new Date()).toISOString() 40 | '@Destination': destination 41 | '@AssertionConsumerServiceURL': assert_endpoint 42 | '@ProtocolBinding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' 43 | '@ForceAuthn': force_authn 44 | 'saml:Issuer': issuer 45 | NameIDPolicy: 46 | '@Format': nameid_format or 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified' 47 | '@AllowCreate': 'true' 48 | RequestedAuthnContext: context_element 49 | .end() 50 | { id, xml } 51 | 52 | # Adds an embedded signature to a previously generated AuthnRequest 53 | sign_authn_request = (xml, private_key, options) -> 54 | signer = new SignedXml options 55 | signer.addReference({ 56 | xpath: "//*[local-name(.)='AuthnRequest']", 57 | transforms: ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'] 58 | digestAlgorithm: "http://www.w3.org/2001/04/xmlenc#sha256" 59 | }) 60 | signer.privateKey = private_key 61 | signer.canonicalizationAlgorithm = 'http://www.w3.org/2001/10/xml-exc-c14n#'; 62 | signer.signatureAlgorithm = options?.signatureAlgorithm || 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' 63 | 64 | signer.computeSignature xml 65 | 66 | 67 | return signer.getSignedXml() 68 | 69 | # Creates metadata and returns it as a string of XML. The metadata has one POST assertion endpoint. 70 | create_metadata = (entity_id, assert_endpoint, signing_certificates, encryption_certificates) -> 71 | signing_cert_descriptors = for signing_certificate in signing_certificates or [] 72 | certificate_to_keyinfo('signing', signing_certificate) 73 | 74 | encryption_cert_descriptors = for encryption_certificate in encryption_certificates or [] 75 | certificate_to_keyinfo('encryption', encryption_certificate) 76 | 77 | xmlbuilder.create 78 | 'md:EntityDescriptor': 79 | '@xmlns:md': XMLNS.MD 80 | '@xmlns:ds': XMLNS.DS 81 | '@entityID': entity_id 82 | '@validUntil': (new Date(Date.now() + 1000 * 60 * 60)).toISOString() 83 | 'md:SPSSODescriptor': 84 | '@protocolSupportEnumeration': 'urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol' 85 | 'md:KeyDescriptor': signing_cert_descriptors.concat(encryption_cert_descriptors) 86 | 'md:SingleLogoutService': 87 | '@Binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect' 88 | '@Location': assert_endpoint 89 | 'md:AssertionConsumerService': 90 | '@Binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' 91 | '@Location': assert_endpoint 92 | '@index': '0' 93 | .end() 94 | 95 | # Creates a LogoutRequest and returns it as a string of xml. 96 | create_logout_request = (issuer, name_id, session_index, destination) -> 97 | id = '_' + crypto.randomBytes( 21 ).toString( 'hex' ) 98 | xml = xmlbuilder.create 99 | 'samlp:LogoutRequest': 100 | '@xmlns:samlp': XMLNS.SAMLP 101 | '@xmlns:saml': XMLNS.SAML 102 | '@ID': id 103 | '@Version': '2.0' 104 | '@IssueInstant': (new Date()).toISOString() 105 | '@Destination': destination 106 | 'saml:Issuer': issuer 107 | 'saml:NameID': name_id 108 | 'samlp:SessionIndex': session_index 109 | .end() 110 | 111 | {id, xml} 112 | 113 | # Creates a LogoutResponse and returns it as a string of xml. 114 | create_logout_response = (issuer, in_response_to, destination, status='urn:oasis:names:tc:SAML:2.0:status:Success') -> 115 | xmlbuilder.create( 116 | {'samlp:LogoutResponse': 117 | '@Destination': destination 118 | '@ID': '_' + crypto.randomBytes(21).toString('hex') 119 | '@InResponseTo': in_response_to 120 | '@IssueInstant': (new Date()).toISOString() 121 | '@Version': '2.0' 122 | '@xmlns:samlp': XMLNS.SAMLP 123 | '@xmlns:saml': XMLNS.SAML 124 | 'saml:Issuer': issuer 125 | 'samlp:Status': 126 | 'samlp:StatusCode': '@Value': status 127 | }, { headless: true } 128 | ).end() 129 | 130 | # Takes a base64 encoded @key and returns it formatted with newlines and a PEM header according to @type. If it already 131 | # has a PEM header, it will just return the original key. 132 | format_pem = (key, type) -> 133 | return key if (/-----BEGIN [0-9A-Z ]+-----[^-]*-----END [0-9A-Z ]+-----/g.exec(key))? 134 | return "-----BEGIN #{type.toUpperCase()}-----\n" + key.match(/.{1,64}/g).join("\n") + "\n-----END #{type.toUpperCase()}-----" 135 | 136 | # Takes a compressed/base64 enoded @saml_request and @private_key and signs the request using RSA-SHA256. It returns 137 | # the result as an object containing the query parameters. 138 | sign_request = (saml_request, private_key, relay_state, response=false) -> 139 | action = if response then "SAMLResponse" else "SAMLRequest" 140 | data = "#{action}=" + encodeURIComponent(saml_request) 141 | if relay_state 142 | data += "&RelayState=" + encodeURIComponent(relay_state) 143 | data += "&SigAlg=" + encodeURIComponent('http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') 144 | 145 | saml_request_data = "#{action}=" + encodeURIComponent(saml_request) 146 | relay_state_data = if relay_state? then "&RelayState=" + encodeURIComponent(relay_state) else "" 147 | sigalg_data = "&SigAlg=" + encodeURIComponent('http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') 148 | sign = crypto.createSign 'RSA-SHA256' 149 | sign.update(saml_request_data + relay_state_data + sigalg_data) 150 | 151 | samlQueryString = {} 152 | 153 | if response 154 | samlQueryString.SAMLResponse = saml_request 155 | else 156 | samlQueryString.SAMLRequest = saml_request 157 | 158 | if relay_state 159 | samlQueryString.RelayState = relay_state 160 | 161 | samlQueryString.SigAlg = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' 162 | samlQueryString.Signature = sign.sign(format_pem(private_key, 'PRIVATE KEY'), 'base64') 163 | 164 | samlQueryString 165 | 166 | # Converts a pem certificate to a KeyInfo object for use with XML. 167 | certificate_to_keyinfo = (use, certificate) -> 168 | { 169 | '@use': use 170 | 'ds:KeyInfo': 171 | '@xmlns:ds': XMLNS.DS 172 | 'ds:X509Data': 173 | 'ds:X509Certificate': extract_certificate_data certificate 174 | } 175 | 176 | # Returns the raw certificate data with all extraneous characters removed. 177 | extract_certificate_data = (certificate) -> 178 | cert_data = /-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----/g.exec certificate 179 | cert_data = if cert_data? then cert_data[1] else certificate 180 | throw new Error('Invalid Certificate') unless cert_data? 181 | 182 | return cert_data.replace(/[\r\n]/g, '') 183 | 184 | # Takes in an xml @dom containing a SAML Status and returns true if at least one status is Success. 185 | check_status_success = (dom) -> 186 | status = dom.getElementsByTagNameNS(XMLNS.SAMLP, 'Status') 187 | return false unless status.length is 1 188 | for status_code in status[0].childNodes or [] 189 | if status_code.attributes? 190 | status = get_attribute_value status_code, 'Value' 191 | return status is 'urn:oasis:names:tc:SAML:2.0:status:Success' 192 | false 193 | 194 | get_status = (dom) -> 195 | status_list = {} 196 | status = dom.getElementsByTagNameNS(XMLNS.SAMLP, 'Status') 197 | return status_list unless status.length is 1 198 | 199 | for status_code in status[0].childNodes or [] 200 | if status_code.attributes? 201 | top_status = get_attribute_value status_code, 'Value' 202 | status_list[top_status] ?= [] 203 | for sub_status_code in status_code.childNodes or [] 204 | if sub_status_code?.attributes? 205 | status = get_attribute_value sub_status_code, 'Value' 206 | status_list[top_status].push status 207 | status_list 208 | 209 | to_error = (err) -> 210 | return null unless err? 211 | return new Error(util.inspect err) unless err instanceof Error 212 | err 213 | 214 | # Takes in an XML @dom of an object containing an EncryptedAssertion and attempts to decrypt it 215 | # using the @private_keys in the given order. 216 | # 217 | # @cb will be called with an error if the decryption fails, or the EncryptedAssertion cannot be 218 | # found. If successful, it will be called with the decrypted data as a string. 219 | decrypt_assertion = (dom, private_keys, cb) -> 220 | # This is needed because xmlenc sometimes throws an exception, and sometimes calls the passed-in 221 | # callback. 222 | cb = _.wrap cb, (fn, err, args...) -> setTimeout (-> fn to_error(err), args...), 0 223 | 224 | try 225 | encrypted_assertion = dom.getElementsByTagNameNS(XMLNS.SAML, 'EncryptedAssertion') 226 | unless encrypted_assertion.length is 1 227 | return cb new Error("Expected 1 EncryptedAssertion; found #{encrypted_assertion.length}.") 228 | 229 | encrypted_data = encrypted_assertion[0].getElementsByTagNameNS(XMLNS.XENC, 'EncryptedData') 230 | unless encrypted_data.length is 1 231 | return cb new Error("Expected 1 EncryptedData inside EncryptedAssertion; found #{encrypted_data.length}.") 232 | 233 | encrypted_assertion = encrypted_assertion[0].toString() 234 | errors = [] 235 | async.eachOfSeries private_keys, (private_key, index, cb_e) -> 236 | xmlenc.decrypt encrypted_assertion, {key: format_pem(private_key, 'PRIVATE KEY')}, (err, result) -> 237 | if err? 238 | errors.push new Error("Decrypt failed: #{util.inspect err}") if err? 239 | return cb_e() 240 | 241 | debug "Decryption successful with private key ##{index}." 242 | cb null, result 243 | , -> cb new Error("Failed to decrypt assertion with provided key(s): #{util.inspect errors}") 244 | catch err 245 | cb new Error("Decrypt failed: #{util.inspect err}") 246 | 247 | # This checks the signature of a saml document and returns either array containing the signed data if valid, or null 248 | # if the signature is invalid. Comparing the result against null is NOT sufficient for signature checks as it doesn't 249 | # verify the signature is signing the important content, nor is it preventing the parsing of unsigned content. 250 | check_saml_signature = (xml, certificate) -> 251 | doc = (new xmldom.DOMParser()).parseFromString(xml) 252 | 253 | # xpath failed to capture nodes of direct descendents of the root. 254 | # Call documentElement to explicitly start from the root element of the document. 255 | signature = xpath.select("./*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc.documentElement) 256 | return null unless signature.length is 1 257 | sig = new SignedXml( 258 | { 259 | publicCert: format_pem(certificate, 'CERTIFICATE') 260 | } 261 | ) 262 | # sig.keyInfoProvider = getKey: -> format_pem(certificate, 'CERTIFICATE') 263 | sig.loadSignature signature[0] 264 | try 265 | valid = sig.checkSignature xml 266 | if valid 267 | return get_signed_data(doc, sig) 268 | else 269 | return null 270 | catch e 271 | # temporary hack 272 | if (e.message.indexOf("invalid signature") != -1) 273 | return null; # returns null for incorrect signature 274 | else 275 | throw e; # throw back the error 276 | 277 | 278 | # Gets the data that is actually signed according to xml-crypto. This function should mirror the way xml-crypto finds 279 | # elements for security reasons. 280 | # deprecate 281 | get_signed_data = (doc, sig) -> 282 | return sig.getSignedReferences(); # use new API 283 | # Takes in an xml @dom of an object containing a SAML Response and returns an object containing the Destination and 284 | # InResponseTo attributes of the Response if present. It will throw an error if the Response is missing or does not 285 | # appear to be valid. 286 | parse_response_header = (dom) -> 287 | for response_type in ['Response', 'LogoutResponse', 'LogoutRequest'] 288 | response = dom.getElementsByTagNameNS(XMLNS.SAMLP, response_type) 289 | break if response.length > 0 290 | throw new Error("Expected 1 Response; found #{response.length}") unless response.length is 1 291 | 292 | response_header = { 293 | version: get_attribute_value response[0], 'Version' 294 | destination: get_attribute_value response[0], 'Destination' 295 | in_response_to: get_attribute_value response[0], 'InResponseTo' 296 | id: get_attribute_value response[0], 'ID' 297 | } 298 | 299 | # If no version attribute is supplied, assume v2 300 | version = response_header.version or '2.0' 301 | throw new Error "Invalid SAML Version #{version}" unless version is "2.0" 302 | response_header 303 | 304 | # Takes in an xml @dom of an object containing a SAML Assertion and returns the NameID. If there is no NameID found, 305 | # it will return null. It will throw an error if the Assertion is missing or does not appear to be valid. 306 | get_name_id = (dom) -> 307 | assertion = dom.getElementsByTagNameNS(XMLNS.SAML, 'Assertion') 308 | throw new Error("Expected 1 Assertion; found #{assertion.length}") unless assertion.length is 1 309 | 310 | subject = assertion[0].getElementsByTagNameNS(XMLNS.SAML, 'Subject') 311 | throw new Error("Expected 1 Subject; found #{subject.length}") unless subject.length is 1 312 | 313 | nameid = subject[0].getElementsByTagNameNS(XMLNS.SAML, 'NameID') 314 | return null unless nameid.length is 1 315 | 316 | nameid[0].firstChild?.data 317 | 318 | get_attribute_value = (node, attributeName) -> 319 | attributes = node.attributes or [] 320 | attribute = _.filter attributes, (attr) -> attr.name is attributeName 321 | attribute[0]?.value 322 | 323 | # Takes in an xml @dom of an object containing a SAML Assertion and returns the SessionIndex. It will throw an error 324 | # if there is no SessionIndex, no Assertion, or the Assertion does not appear to be valid. Optionally you can pass a 325 | # second argument `false` making SessionIndex optional. Doing so returns `null` instead of throwing an Error if the 326 | # SessionIndex attribute does not exist. 327 | get_session_info = (dom, index_required=true) -> 328 | assertion = dom.getElementsByTagNameNS(XMLNS.SAML, 'Assertion') 329 | throw new Error("Expected 1 Assertion; found #{assertion.length}") unless assertion.length is 1 330 | 331 | authn_statement = assertion[0].getElementsByTagNameNS(XMLNS.SAML, 'AuthnStatement') 332 | throw new Error("Expected 1 AuthnStatement; found #{authn_statement.length}") unless authn_statement.length is 1 333 | 334 | info = 335 | index: get_attribute_value authn_statement[0], 'SessionIndex' 336 | not_on_or_after: get_attribute_value authn_statement[0], 'SessionNotOnOrAfter' 337 | 338 | if index_required and not info.index? 339 | throw new Error("SessionIndex not an attribute of AuthnStatement.") 340 | 341 | info 342 | 343 | # Takes in an xml @dom of an object containing a SAML Assertion and returns and object containing the attributes 344 | # contained within the Assertion. It will throw an error if the Assertion is missing or does not appear to be valid. 345 | parse_assertion_attributes = (dom) -> 346 | assertion = dom.getElementsByTagNameNS(XMLNS.SAML, 'Assertion') 347 | throw new Error("Expected 1 Assertion; found #{assertion.length}") unless assertion.length is 1 348 | 349 | attribute_statement = assertion[0].getElementsByTagNameNS(XMLNS.SAML, 'AttributeStatement') 350 | throw new Error("Expected 1 AttributeStatement inside Assertion; found #{attribute_statement.length}") unless attribute_statement.length <= 1 351 | return {} if attribute_statement.length is 0 352 | 353 | assertion_attributes = {} 354 | for attribute in attribute_statement[0].getElementsByTagNameNS(XMLNS.SAML, 'Attribute') 355 | attribute_name = get_attribute_value attribute, 'Name' 356 | throw new Error("Invalid attribute without name") unless attribute_name? 357 | attribute_values = attribute.getElementsByTagNameNS(XMLNS.SAML, 'AttributeValue') 358 | assertion_attributes[attribute_name] = _.map(attribute_values, (attribute_value) -> 359 | attribute_value.childNodes[0]?.data or '') 360 | assertion_attributes 361 | 362 | # Takes in an object containing SAML Assertion Attributes and returns an object with certain common attributes changed 363 | # into nicer names. Attributes that are not expected are ignored, and attributes with more than one value with have 364 | # all values except the first one dropped. 365 | pretty_assertion_attributes = (assertion_attributes) -> 366 | claim_map = 367 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "email" 368 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname": "given_name" 369 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "name" 370 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn": "upn" 371 | "http://schemas.xmlsoap.org/claims/CommonName": "common_name" 372 | "http://schemas.xmlsoap.org/claims/Group": "group" 373 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "role" 374 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname": "surname" 375 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier": "ppid" 376 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "name_id" 377 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod": "authentication_method" 378 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid": "deny_only_group_sid" 379 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid": "deny_only_primary_sid" 380 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid": "deny_only_primary_group_sid" 381 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid": "group_sid" 382 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid": "primary_group_sid" 383 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid": "primary_sid" 384 | "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname": "windows_account_name" 385 | 386 | _.chain(assertion_attributes) 387 | .pairs() 388 | .filter(([k, v]) -> (claim_map[k]? and v.length > 0)) 389 | .map(([k, v]) -> [claim_map[k], v[0]]) 390 | .object() 391 | .value() 392 | 393 | # takes in an XML string, returns an XML string 394 | # applies all inclusive namespaces for signature assertions onto assertion tag 395 | # used as recommended workaround for xml-crypto library limitation with inclusive namespaces 396 | # see https://github.com/yaronn/xml-crypto/issues/48#issuecomment-129705816 397 | add_namespaces_to_child_assertions = (xml_string) -> 398 | doc = new xmldom.DOMParser().parseFromString xml_string 399 | 400 | response_elements = doc.getElementsByTagNameNS XMLNS.SAMLP, 'Response' 401 | return xml_string if response_elements.length isnt 1 402 | response_element = response_elements[0] 403 | 404 | assertion_elements = response_element.getElementsByTagNameNS XMLNS.SAML, 'Assertion' 405 | return xml_string if assertion_elements.length isnt 1 406 | assertion_element = assertion_elements[0] 407 | 408 | inclusive_namespaces = assertion_element.getElementsByTagNameNS(XMLNS.EXC_C14N, 'InclusiveNamespaces')[0] 409 | namespaces = if inclusive_namespaces and prefixList = inclusive_namespaces.getAttribute('PrefixList')?.trim() 410 | ("xmlns:#{ns}" for ns in prefixList.split(' ')) 411 | else 412 | (attr.name for attr in response_element.attributes when attr.name.match /^xmlns:/) 413 | 414 | # add the namespaces that are present in response and missing in assertion. 415 | for ns in namespaces 416 | if response_element.getAttribute(ns) and !assertion_element.getAttribute(ns) 417 | new_attribute = doc.createAttribute ns 418 | new_attribute.value = response_element.getAttribute ns 419 | assertion_element.setAttributeNode new_attribute 420 | 421 | return new xmldom.XMLSerializer().serializeToString response_element 422 | 423 | # Takes a DOM of a saml_response, private keys with which to attempt decryption and the 424 | # certificate(s) of the identity provider that issued it and will return a user object containing 425 | # the attributes or an error if keys are incorrect or the response is invalid. 426 | parse_authn_response = (saml_response, sp_private_keys, idp_certificates, allow_unencrypted, ignore_signature, require_session_index, ignore_timing, notbefore_skew, sp_audience, cb) -> 427 | user = {} 428 | 429 | async.waterfall [ 430 | (cb_wf) -> 431 | # Decrypt the assertion 432 | decrypt_assertion saml_response, sp_private_keys, (err, result) -> 433 | return cb_wf null, result unless err? 434 | return cb_wf err, result unless allow_unencrypted and err.message == "Expected 1 EncryptedAssertion; found 0." 435 | assertion = saml_response.getElementsByTagNameNS(XMLNS.SAML, 'Assertion') 436 | unless assertion.length is 1 437 | return cb_wf new Error("Expected 1 Assertion or 1 EncryptedAssertion; found #{assertion.length}") 438 | cb_wf null, assertion[0].toString() 439 | (result, cb_wf) -> 440 | # Validate the signature 441 | debug result 442 | if ignore_signature 443 | return cb_wf null, (new xmldom.DOMParser()).parseFromString(result) 444 | 445 | saml_response_str = saml_response.toString() 446 | for cert, i in idp_certificates or [] 447 | try 448 | signed_data = check_saml_signature(result, cert) or check_saml_signature saml_response_str, cert 449 | catch ex 450 | return cb_wf new Error("SAML Assertion signature check failed! (Certificate \##{i+1} may be invalid. #{ex.message}") 451 | unless signed_data 452 | continue # Cert was not valid, try the next one 453 | 454 | for sd in signed_data 455 | signed_dom = (new xmldom.DOMParser()).parseFromString(sd) 456 | 457 | assertion = signed_dom.getElementsByTagNameNS(XMLNS.SAML, 'Assertion') 458 | if assertion.length is 1 459 | return cb_wf null, signed_dom 460 | 461 | encryptedAssertion = signed_dom.getElementsByTagNameNS(XMLNS.SAML, 'EncryptedAssertion') 462 | if encryptedAssertion.length is 1 463 | return decrypt_assertion saml_response, sp_private_keys, (err, result) -> 464 | return cb_wf null, (new xmldom.DOMParser()).parseFromString(result) unless err? 465 | return cb_wf err 466 | return cb_wf new Error("Signed data did not contain a SAML Assertion!") 467 | return cb_wf new Error("SAML Assertion signature check failed! (checked #{idp_certificates.length} certificate(s))") 468 | (decrypted_assertion, cb_wf) -> 469 | # Validate the assertion conditions 470 | conditions = decrypted_assertion.getElementsByTagNameNS(XMLNS.SAML, 'Conditions')[0] 471 | if conditions? 472 | if ignore_timing != true 473 | for attribute in conditions.attributes 474 | condition = attribute.name.toLowerCase() 475 | if condition == 'notbefore' and Date.parse(attribute.value) > Date.now() + (notbefore_skew * 1000) 476 | return cb_wf new SAMLError('SAML Response is not yet valid', {NotBefore: attribute.value}) 477 | if condition == 'notonorafter' and Date.parse(attribute.value) <= Date.now() 478 | return cb_wf new SAMLError('SAML Response is no longer valid', {NotOnOrAfter: attribute.value}) 479 | 480 | audience_restriction = conditions.getElementsByTagNameNS(XMLNS.SAML, 'AudienceRestriction')[0] 481 | audiences = audience_restriction?.getElementsByTagNameNS(XMLNS.SAML, 'Audience') 482 | if audiences?.length > 0 483 | validAudience = _.find audiences, (audience) -> 484 | audienceValue = audience.firstChild?.data?.trim() 485 | !_.isEmpty(audienceValue?.trim()) and ( 486 | (_.isRegExp(sp_audience) and sp_audience.test(audienceValue)) or 487 | (_.isString(sp_audience) and sp_audience.toLowerCase() == audienceValue.toLowerCase()) 488 | ) 489 | if !validAudience? 490 | return cb_wf new SAMLError('SAML Response is not valid for this audience') 491 | return cb_wf null, decrypted_assertion 492 | (validated_assertion, cb_wf) -> 493 | # Populate attributes 494 | try 495 | session_info = get_session_info validated_assertion, require_session_index 496 | user.name_id = get_name_id validated_assertion 497 | user.session_index = session_info.index 498 | if session_info.not_on_or_after? 499 | user.session_not_on_or_after = session_info.not_on_or_after 500 | 501 | assertion_attributes = parse_assertion_attributes validated_assertion 502 | user = _.extend user, pretty_assertion_attributes(assertion_attributes) 503 | user = _.extend user, attributes: assertion_attributes 504 | cb_wf null, { user } 505 | catch err 506 | return cb_wf err 507 | ], cb 508 | 509 | parse_logout_request = (dom) -> 510 | request = dom.getElementsByTagNameNS(XMLNS.SAMLP, "LogoutRequest") 511 | throw new Error("Expected 1 LogoutRequest; found #{request.length}") unless request.length is 1 512 | 513 | request = {} 514 | 515 | issuer = dom.getElementsByTagNameNS(XMLNS.SAML, 'Issuer') 516 | request.issuer = issuer[0].firstChild?.data if issuer.length is 1 517 | name_id = dom.getElementsByTagNameNS(XMLNS.SAML, 'NameID') 518 | request.name_id = name_id[0].firstChild?.data if name_id.length is 1 519 | session_index = dom.getElementsByTagNameNS(XMLNS.SAMLP, 'SessionIndex') 520 | request.session_index = session_index[0].firstChild?.data if session_index.length is 1 521 | 522 | request 523 | 524 | set_option_defaults = (request_options, idp_options, sp_options) -> 525 | _.defaults({}, request_options, idp_options, sp_options) 526 | 527 | module.exports.ServiceProvider = 528 | class ServiceProvider 529 | # Initializes a service provider given the passed options. 530 | # 531 | # @entity_id, @private_key, @assert_endpoint, @certificate, @alt_private_keys, @alt_certs can 532 | # only be set here and are used by exported functions. 533 | # 534 | # Rest of options can be set/overwritten by the identity provider and/or at function call. 535 | constructor: (options) -> 536 | {@entity_id, @private_key, @certificate, @assert_endpoint, @alt_private_keys, @alt_certs} = options 537 | 538 | options.audience ?= @entity_id 539 | options.notbefore_skew ?= 1 540 | 541 | @alt_private_keys = [].concat(@alt_private_keys or []) 542 | @alt_certs = [].concat(@alt_certs or []) 543 | 544 | @shared_options = _.pick(options, 545 | "force_authn", "auth_context", "nameid_format", "sign_get_request", "allow_unencrypted_assertion", "audience", "notbefore_skew") 546 | 547 | # Returns: 548 | # Redirect URL at which a user can login 549 | # ID of the request 550 | # Params: 551 | # identity_provider 552 | # options 553 | # cb 554 | create_login_request_url: (identity_provider, options, cb) -> 555 | options = set_option_defaults options, identity_provider.shared_options, @shared_options 556 | 557 | { id, xml } = create_authn_request @entity_id, @assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format 558 | zlib.deflateRaw xml, (err, deflated) => 559 | return cb err if err? 560 | try 561 | uri = url.parse identity_provider.sso_login_url, true 562 | catch ex 563 | return cb ex 564 | delete uri.search # If you provide search and query search overrides query :/ 565 | if options.sign_get_request 566 | _.extend(uri.query, sign_request(deflated.toString('base64'), @private_key, options.relay_state)) 567 | else 568 | uri.query.SAMLRequest = deflated.toString 'base64' 569 | uri.query.RelayState = options.relay_state if options.relay_state? 570 | cb null, url.format(uri), id 571 | 572 | # Returns: 573 | # An xml string with an AuthnRequest with an embedded xml signature 574 | # Params: 575 | # identity_provider 576 | # options 577 | create_authn_request_xml: (identity_provider, options) -> 578 | options = set_option_defaults options, identity_provider.shared_options, @shared_options 579 | 580 | { id, xml } = create_authn_request @entity_id, @assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format 581 | return sign_authn_request(xml, @private_key, options) 582 | 583 | # Returns: 584 | # An object containing the parsed response for a redirect assert. 585 | # This type of assert inflates the response before parsing it. 586 | # Params: 587 | # identity_provider 588 | # options 589 | # cb 590 | redirect_assert: (identity_provider, options, cb) -> 591 | options = _.defaults(_.extend(options, {get_request: true}), {require_session_index: true}) 592 | options = set_option_defaults options, identity_provider.shared_options, @shared_options 593 | @_assert identity_provider, options, cb 594 | 595 | # Returns: 596 | # An object containing the parsed response for a post assert. 597 | # Params: 598 | # identity_provider 599 | # options 600 | # cb 601 | post_assert: (identity_provider, options, cb) -> 602 | options = _.defaults(_.extend(options, {get_request: false}), {require_session_index: true}) 603 | options = set_option_defaults options, identity_provider.shared_options, @shared_options 604 | @_assert identity_provider, options, cb 605 | 606 | # Private function, called by redirect and post assert to return a response to 607 | # corresponding assert. 608 | _assert: (identity_provider, options, cb) -> 609 | unless options.request_body?.SAMLResponse? or options.request_body?.SAMLRequest? 610 | return setImmediate cb, new Error("Request body does not contain SAMLResponse or SAMLRequest.") 611 | 612 | unless _.isNumber(options.notbefore_skew) 613 | return setImmediate cb, new Error("Configuration error: `notbefore_skew` must be a number") 614 | 615 | saml_response = null 616 | response = {} 617 | 618 | async.waterfall [ 619 | (cb_wf) -> 620 | raw = Buffer.from(options.request_body.SAMLResponse or options.request_body.SAMLRequest, 'base64') 621 | 622 | # Inflate response for redirect requests before parsing it. 623 | if (options.get_request) 624 | return zlib.inflateRaw raw, cb_wf 625 | setImmediate cb_wf, null, raw 626 | 627 | (response_buffer, cb_wf) => 628 | debug saml_response 629 | saml_response_abnormalized = add_namespaces_to_child_assertions(response_buffer.toString()) 630 | saml_response = (new xmldom.DOMParser()).parseFromString(saml_response_abnormalized) 631 | 632 | try 633 | response = { response_header: parse_response_header(saml_response) } 634 | catch err 635 | return cb err 636 | switch 637 | when saml_response.getElementsByTagNameNS(XMLNS.SAMLP, 'Response').length is 1 638 | unless check_status_success(saml_response) 639 | return cb_wf new SAMLError("SAML Response was not success!", {status: get_status(saml_response)}) 640 | 641 | response.type = 'authn_response' 642 | 643 | parse_authn_response( 644 | saml_response, 645 | [@private_key].concat(@alt_private_keys), 646 | identity_provider.certificates, 647 | options.allow_unencrypted_assertion, 648 | options.ignore_signature, 649 | options.require_session_index, 650 | options.ignore_timing, 651 | options.notbefore_skew, 652 | options.audience 653 | cb_wf) 654 | 655 | when saml_response.getElementsByTagNameNS(XMLNS.SAMLP, 'LogoutResponse').length is 1 656 | unless check_status_success(saml_response) 657 | return cb_wf new SAMLError("SAML Response was not success!", {status: get_status(saml_response)}) 658 | 659 | response.type = 'logout_response' 660 | setImmediate cb_wf, null, {} 661 | 662 | when saml_response.getElementsByTagNameNS(XMLNS.SAMLP, 'LogoutRequest').length is 1 663 | response.type = 'logout_request' 664 | setImmediate cb_wf, null, parse_logout_request saml_response 665 | 666 | (result, cb_wf) -> 667 | _.extend response, result 668 | cb_wf null, response 669 | ], cb 670 | 671 | # ----- Optional ----- 672 | 673 | # Returns: 674 | # Redirect URL, at which a user is logged out. 675 | # Params: 676 | # identity_provider 677 | # options 678 | # cb 679 | create_logout_request_url: (identity_provider, options, cb) => 680 | identity_provider = { sso_logout_url: identity_provider, options: {} } if _.isString(identity_provider) 681 | options = set_option_defaults options, identity_provider.shared_options, @shared_options 682 | {id, xml} = create_logout_request @entity_id, options.name_id, options.session_index, identity_provider.sso_logout_url 683 | zlib.deflateRaw xml, (err, deflated) => 684 | return cb err if err? 685 | try 686 | uri = url.parse identity_provider.sso_logout_url, true 687 | catch ex 688 | return cb ex 689 | query = null 690 | if options.sign_get_request 691 | query = sign_request deflated.toString('base64'), @private_key, options.relay_state 692 | else 693 | query = SAMLRequest: deflated.toString 'base64' 694 | query.RelayState = options.relay_state if options.relay_state? 695 | uri.query = _.extend(query, uri.query) 696 | uri.search = null 697 | uri.query = query 698 | cb null, url.format(uri), id 699 | 700 | # Returns: 701 | # Redirect URL to confirm a successful logout. 702 | # Params: 703 | # identity_provider 704 | # options 705 | # cb 706 | create_logout_response_url: (identity_provider, options, cb) -> 707 | identity_provider = { sso_logout_url: identity_provider, options: {} } if _.isString(identity_provider) 708 | options = set_option_defaults options, identity_provider.shared_options, @shared_options 709 | 710 | xml = create_logout_response @entity_id, options.in_response_to, identity_provider.sso_logout_url 711 | zlib.deflateRaw xml, (err, deflated) => 712 | return cb err if err? 713 | try 714 | uri = url.parse identity_provider.sso_logout_url 715 | catch ex 716 | return cb ex 717 | if options.sign_get_request 718 | uri.query = sign_request deflated.toString('base64'), @private_key, options.relay_state, true 719 | else 720 | uri.query = SAMLResponse: deflated.toString 'base64' 721 | uri.query.RelayState = options.relay_state if options.relay_state? 722 | cb null, url.format(uri) 723 | 724 | # Returns: 725 | # XML metadata, used during initial SAML configuration 726 | create_metadata: => 727 | certs = [@certificate].concat @alt_certs 728 | create_metadata @entity_id, @assert_endpoint, certs, certs 729 | 730 | module.exports.IdentityProvider = 731 | class IdentityProvider 732 | constructor: (options) -> 733 | {@sso_login_url, @sso_logout_url, @certificates} = options 734 | @certificates = [ @certificates ] unless _.isArray(@certificates) 735 | @shared_options = _.pick(options, "force_authn", "sign_get_request", "allow_unencrypted_assertion") 736 | 737 | if process.env.NODE_ENV is "test" 738 | module.exports.create_authn_request = create_authn_request 739 | module.exports.sign_authn_request = sign_authn_request 740 | module.exports.create_metadata = create_metadata 741 | module.exports.format_pem = format_pem 742 | module.exports.sign_request = sign_request 743 | module.exports.check_saml_signature = check_saml_signature 744 | module.exports.check_status_success = check_status_success 745 | module.exports.pretty_assertion_attributes = pretty_assertion_attributes 746 | module.exports.decrypt_assertion = decrypt_assertion 747 | module.exports.parse_response_header = parse_response_header 748 | module.exports.parse_logout_request = parse_logout_request 749 | module.exports.get_name_id = get_name_id 750 | module.exports.get_session_info = get_session_info 751 | module.exports.parse_assertion_attributes = parse_assertion_attributes 752 | module.exports.add_namespaces_to_child_assertions = add_namespaces_to_child_assertions 753 | module.exports.set_option_defaults = set_option_defaults 754 | module.exports.extract_certificate_data = extract_certificate_data 755 | --------------------------------------------------------------------------------