├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .pre-commit.sh ├── .snyk ├── .travis.yml ├── @types └── xml-encryption.d.ts ├── LICENSE ├── Makefile ├── README.md ├── docs ├── .nojekyll ├── CNAME ├── README.md ├── _coverpage.md ├── _media │ ├── bg.jpg │ ├── favicon.ico │ └── lock.png ├── _sidebar.md ├── advance.md ├── basic.md ├── configuration.md ├── encrypted-saml-response.md ├── examples.md ├── gitlab.md ├── guide.md ├── idp-configuration.md ├── idp.md ├── index.html ├── key-generation.md ├── metadata-distribution.md ├── multi-entities.md ├── okta-inbound.md ├── okta.md ├── onelogin.md ├── prerequistite.md ├── saml-request.md ├── saml-response.md ├── signed-saml-request.md ├── signed-saml-response.md ├── sp-configuration.md ├── sp.md └── template.md ├── index.ts ├── package.json ├── src ├── api.ts ├── binding-post.ts ├── binding-redirect.ts ├── entity-idp.ts ├── entity-sp.ts ├── entity.ts ├── extractor.ts ├── flow.ts ├── libsaml.ts ├── metadata-idp.ts ├── metadata-sp.ts ├── metadata.ts ├── types.ts ├── urn.ts ├── utility.ts └── validator.ts ├── test ├── README.md ├── extractor.ts ├── flow.ts ├── index.ts ├── issues.ts ├── key │ ├── idp │ │ ├── README.md │ │ ├── cert.cer │ │ ├── cert2.cer │ │ ├── encryptKey.pem │ │ ├── encryptionCert.cer │ │ ├── nocrypt.pem │ │ ├── privkey.pem │ │ └── privkey2.pem │ ├── keypass.txt │ └── sp │ │ ├── cert.cer │ │ ├── encryptKey.pem │ │ ├── encryptionCert.cer │ │ ├── knownGoodCert.cer │ │ ├── knownGoodEncryptKey.pem │ │ └── privkey.pem └── misc │ ├── attack_response_signed.xml │ ├── dumpes_issuer_response.xml │ ├── failed_response.xml │ ├── false_signed_request_sha1.xml │ ├── false_signed_request_sha256.xml │ ├── false_signed_request_sha512.xml │ ├── idpmeta.xml │ ├── idpmeta_nosign.xml │ ├── idpmeta_onelogoutservice.xml │ ├── idpmeta_rollingcert.xml │ ├── idpmeta_share_cert.xml │ ├── invalid_response.xml │ ├── logout_request.xml │ ├── multiple_entitydescriptor.xml │ ├── request.xml │ ├── response.xml │ ├── response_signed.xml │ ├── response_signed_cert1.xml │ ├── response_signed_cert2.xml │ ├── signed_request_sha1.xml │ ├── signed_request_sha256.xml │ ├── signed_request_sha512.xml │ ├── signed_response_sha1.xml │ ├── signed_response_sha256.xml │ ├── signed_response_sha512.xml │ ├── sp_metadata_98.xml │ ├── spmeta.xml │ ├── spmeta_noassertsign.xml │ └── spmeta_noauthnsign.xml ├── tsconfig.json ├── tslint.json ├── types.d.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.{json,js,ts,jsx,html,css}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [.eslintrc] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [tngan] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Dependency directory 17 | # Commenting this out is preferred by some people, see 18 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 19 | node_modules 20 | 21 | build 22 | types/ 23 | 24 | .yarnclean 25 | 26 | .nyc_output 27 | 28 | #jetbrains IDEs 29 | .idea 30 | 31 | #vscode 32 | .vscode 33 | 34 | *.tgz 35 | 36 | package-lock.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | examples 3 | test 4 | @types 5 | docs 6 | yarn* 7 | .nyc_output -------------------------------------------------------------------------------- /.pre-commit.sh: -------------------------------------------------------------------------------- 1 | echo "Linting" 2 | npm run lint 3 | LINTRESULT=$? 4 | 5 | echo "Compiling" 6 | $(npm bin)/tsc 7 | BUILDRESULT=$? 8 | 9 | if [[ $LINTRESULT -ne 0 || $BUILDRESULT -ne 0 ]]; then 10 | echo "Fix errors before commit" 11 | exit 1 12 | else 13 | echo "Ok to commit" 14 | exit 0 15 | fi 16 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.14.0 3 | ignore: {} 4 | # patches apply the minimum changes required to fix a vulnerability 5 | patch: 6 | SNYK-JS-LODASH-450202: 7 | - '@authenio/xml-encryption > async > lodash': 8 | patched: '2019-12-11T18:53:51.541Z' 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "10" 5 | - "12" 6 | - "14" 7 | 8 | env: 9 | - INSTALL_JDK=1 10 | - INSTALL_JDK=0 11 | 12 | before_install: 13 | - if [[ "$INSTALL_JDK" == "1" ]] ; then make install_jdk ; fi 14 | 15 | install: 16 | - yarn install --production=true 17 | 18 | script: 19 | - yarn add @authenio/samlify-xsd-schema-validator 20 | - yarn test --timeout=30s 21 | 22 | branches: 23 | only: 24 | - master 25 | - /^.*-alpha$/ 26 | - /^.*-rc.*$/ 27 | - /^feature\/.*$/ 28 | 29 | after_success: npm run coverage -------------------------------------------------------------------------------- /@types/xml-encryption.d.ts: -------------------------------------------------------------------------------- 1 | declare module "xml-encryption" { 2 | export interface EncryptOptions { 3 | rsa_pub: string | Buffer; 4 | pem: string | Buffer; 5 | encryptionAlgorithm: string; 6 | keyEncryptionAlgorithm: string; 7 | input_encoding?: string; 8 | } 9 | export interface DecryptOptions { 10 | key: string | Buffer; 11 | } 12 | export interface Callback { 13 | (err:Error, result): void; 14 | } 15 | export function encrypt(content: string, options: EncryptOptions, callback: Callback): string; 16 | export function encryptKeyInfo(symmetricKey: string, options: EncryptOptions, callback: Callback): string; 17 | export function decrypt(xml: string | Document, options: DecryptOptions, callback: Callback): string; 18 | export function decryptKeyInfo(doc: string | Document, options: DecryptOptions): string; 19 | const _default: { decrypt, encrypt, decryptKeyInfo, encryptKeyInfo }; 20 | export default _default; 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-present Tony Ngan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = "samlify" 2 | 3 | install: ;@echo "install ${PROJECT}"; \ 4 | npm install; 5 | 6 | clean: ; 7 | rm -rf node_modules 8 | 9 | rebuild: ; 10 | rm -rf build; \ 11 | tsc; \ 12 | 13 | pretest: ; 14 | mkdir -p build/test; \ 15 | cp -a test/key test/misc build/test; 16 | 17 | install_jdk: 18 | sudo add-apt-repository ppa:openjdk-r/ppa -y 19 | sudo apt-get -qq update 20 | sudo apt-get install -y openjdk-9-jdk 21 | 22 | doc: ;@echo "prepare and serve the docs"; \ 23 | docsify serve ./docs 24 | 25 | .PHONY: rebuild pretest doc install_jdk 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # samlify · 2 | 3 | [![Build Status](https://travis-ci.org/tngan/samlify.svg?branch=master)](https://travis-ci.org/tngan/samlify) 4 | [![npm version](https://img.shields.io/npm/v/samlify.svg?style=flat)](https://www.npmjs.com/package/samlify) 5 | [![Coverage Status](https://img.shields.io/coveralls/tngan/samlify/master.svg)](https://coveralls.io/github/tngan/samlify?branch=master) 6 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/samlify) 7 | 8 | Highly configuarable Node.js SAML 2.0 library for Single Sign On 9 | 10 | ## Welcome PRs 11 | 12 | Welcome all PRs for maintaining this project, or provide a link to the repositories especially for use cases alongside with different frameworks. 13 | 14 | ### Sponsor 15 | 16 | | |
If you want to quickly implement SAML SSO, feel free to check out Auth0's NodeJS SDK and free plan at [auth0.com/overview](https://auth0.com/overview?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=samlify&utm_content=auth).
| 17 | | :----------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 18 | 19 | 20 | ### Installation 21 | 22 | To install the stable version 23 | 24 | Starting from v2.6, multiple schema validators are now supported. You can simply set the validator via the following global method. We have four validator modules right now, and you can write your own. The `setSchemaValidator` is required since v2.6, it will throw error if you don't set at the beginning. 25 | 26 | ```js 27 | import * as samlify from 'samlify'; 28 | import * as validator from '@authenio/samlify-xsd-schema-validator'; 29 | // import * as validator from '@authenio/samlify-validate-with-xmllint'; 30 | // import * as validator from '@authenio/samlify-node-xmllint'; 31 | // import * as validator from '@authenio/samlify-libxml-xsd'; // only support for version of nodejs <= 8 32 | 33 | // const validator = require('@authenio/samlify-xsd-schema-validator'); 34 | // const validator = require('@authenio/samlify-validate-with-xmllint'); 35 | // const validator = require('@authenio/samlify-node-xmllint'); 36 | // const validator = require('@authenio/samlify-libxml-xsd'); 37 | 38 | samlify.setSchemaValidator(validator); 39 | ``` 40 | 41 | Now you can create your own schema validator and even suppress it but you have to take the risk for accepting malicious response. 42 | 43 | ```typescript 44 | samlify.setSchemaValidator({ 45 | validate: (response: string) => { 46 | /* implment your own or always returns a resolved promise to skip */ 47 | return Promise.resolve('skipped'); 48 | } 49 | }); 50 | ``` 51 | 52 | For those using Windows, `windows-build-tools` should be installed globally before installing samlify if you are using `libxml` validator. 53 | 54 | ```console 55 | yarn global add windows-build-tools 56 | ``` 57 | 58 | ### Development 59 | 60 | This project is now developed using TypeScript, also support Yarn which is a new package manager. 61 | 62 | ```console 63 | yarn global add typescript 64 | yarn 65 | ``` 66 | 67 | ### Get Started 68 | 69 | ```javascript 70 | const saml = require('samlify'); 71 | ``` 72 | 73 | See full documentation [here](https://samlify.js.org/) 74 | 75 | ### Example 76 | 77 | [react-samlify](https://github.com/passify/react-samlify) SP example powered by React, TypeScript and Webpack 78 | 79 | ### Talks 80 | 81 | [An introduction to Single Sign On](http://www.slideshare.net/TonyNgan/an-introduction-of-single-sign-on) 82 | 83 | ### License 84 | 85 | [MIT](LICENSE) 86 | 87 | ### Copyright 88 | 89 | Copyright (C) 2016-present Tony Ngan, released under the MIT License. 90 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tryretool/samlify/c960ef6d64382d4a021590a69b1e10ce17bb9cf8/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | samlify.js.org 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## samlify 2 | 3 | > High-level API library for Single Sign On with SAML 2.0 4 | 5 | This module provides a library for scaling Single Sign On implementation. Developers can easily configure the entities by importing the metadata. 6 | 7 | We provide a simple interface that's highly configurable. 8 | 9 | ### Thanks 10 | 11 |
Icons made by Madebyoliver from www.flaticon.com is licensed by CC 3.0 BY
12 | 13 | 14 | ### Installation 15 | To install the stable version 16 | 17 | ```console 18 | $ npm install samlify 19 | ``` 20 | 21 | or 22 | 23 | ```console 24 | $ yarn add samlify 25 | ``` 26 | 27 | ### Use cases 28 | 29 | + IdP-initiated Single Sign On 30 | + IdP-initiated Single Log-out 31 | + SP-initiated Single Sign On 32 | + SP-initiated Single Log-out (in development) 33 | 34 | Simple solution of Identity Provider is provided in this module for test and educational use. Work with other 3rd party Identity Provider is also supported. 35 | 36 | ### Glimpse of code 37 | 38 | !> **API is changed since v2. All file attributes like metadata and keyFile, it's expected to be normalized as string. It allows easy integration with database storage and import from local file system.** 39 | 40 | !> **The constructor of entity is also modified to accept a single configuration object instead of putting metadata and advanced configurations in separate arguments.** 41 | 42 | ```javascript 43 | const saml = require('samlify'); 44 | // configure a service provider 45 | const sp = saml.ServiceProvider({ 46 | metadata: fs.readFileSync('./metadata_sp.xml') 47 | }); 48 | // configure the corresponding identity provider 49 | const idp = saml.IdentityProvider({ 50 | metadata: fs.readFileSync('./metadata_idp.xml') 51 | }); 52 | // parse when receive a SAML Response from IdP 53 | router.post('/acs', (req, res) => { 54 | sp.parseLoginResponse(idp, 'post', req) 55 | .then(parseResult => { 56 | // Write your own validation and render function here 57 | }) 58 | .catch(console.error); 59 | }); 60 | ``` 61 | 62 | Our default validation is to validate signature and the issuer name of Identity Provider. The code base is self explained. More use cases are provided in this documentation to fit in the real world application. 63 | 64 | ### License 65 | 66 | MIT 67 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | ![logo](_media/lock.png) 2 | 3 | # samlify 2.7.0 4 | 5 | > Node.js SAML2 API 6 | 7 | - Simple and active maintenance 8 | - Includes Identity and Service Provider 9 | - Highly configurable 10 | 11 | [GitHub](https://github.com/tngan/samlify) 12 | [Get Started](#samlify) 13 | 14 | 15 | ![](_media/bg.jpg) 16 | -------------------------------------------------------------------------------- /docs/_media/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tryretool/samlify/c960ef6d64382d4a021590a69b1e10ce17bb9cf8/docs/_media/bg.jpg -------------------------------------------------------------------------------- /docs/_media/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tryretool/samlify/c960ef6d64382d4a021590a69b1e10ce17bb9cf8/docs/_media/favicon.ico -------------------------------------------------------------------------------- /docs/_media/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tryretool/samlify/c960ef6d64382d4a021590a69b1e10ce17bb9cf8/docs/_media/lock.png -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | - **Get Started** 4 | - [Prerequisite](/prerequistite) 5 | - **Basic** 6 | - [Introduction](/basic) 7 | - [Identity Provider](/idp) 8 | - [Service Provider](/sp) 9 | - [SAML Request](/saml-request) 10 | - [Signed](/signed-saml-request) 11 | - [SAML Response](/saml-response) 12 | - [Signed](/signed-saml-response) 13 | - [Encrypted](/encrypted-saml-response) 14 | - [Key Generation](/key-generation) 15 | - **Advanced** 16 | - [Introduction](/advance) 17 | - [Metadata Distribution](/metadata-distribution) 18 | - [IDP/SP Configuration](/configuration) 19 | - [Identity Provider](/idp-configuration) 20 | - [Service Provider](/sp-configuration) 21 | - [Attributes & Template](/template) 22 | - [Helper Functions](/helpers) 23 | - [Multiple Entities](/multi-entities) 24 | - **Examples** 25 | - [Gitlab](/gitlab) 26 | - [OneLogin](/onelogin) 27 | - [Okta](/okta) 28 | - [Inbound SAML](/okta-inbound) 29 | -------------------------------------------------------------------------------- /docs/advance.md: -------------------------------------------------------------------------------- 1 | # Advanced 2 | 3 | Thanks for your patience. Reading documentation is a tough job, so that we keep as simple as possible. This chapter is about the advanced level tutorial. In real-world application, things become complicated and developers may need to do customizations. We hope to maintain a simple but highly configurable interface. Like in basic tutorial, we will go through step by step again. 4 | 5 | + Custom templates for SAML Request/Response 6 | + Scale with multiple Identity/Service Providers 7 | + Additional assertion validations 8 | + Metadata distribution 9 | + Configuration of Identity/Service Provider w/o metadata 10 | 11 | If you have ideas and want more examples, please don't hesitate to create an issue in our Github repository. 12 | -------------------------------------------------------------------------------- /docs/basic.md: -------------------------------------------------------------------------------- 1 | # Basics 2 | 3 | Don't be scared off. Even through SAML leaves a lot of options to developers, and this documentation will go through step by step on: 4 | 5 | + Basic knowledge on SSO for newbie 6 | + Default environment settings 7 | + How to configure a service provider 8 | + How to configure a identity provider 9 | + How to send a SAML Request 10 | + How to parse a SAML Response 11 | + How to integrate with different idp and sp (Examples) 12 | 13 | In this basic tutorial, we provide the simplest solution (without signature and encryption). The real world application is complicated, those topics are covered in the advanced part. 14 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | The easiest way to get SP and iDP ready is to import the metadata file directly. 4 | 5 | ```js 6 | // service provider 7 | const sp = saml.ServiceProvider({ 8 | metadata: fs.readFileSync('./metadata/sp.xml') 9 | }); 10 | 11 | // identity provider 12 | const idp = saml.IdentityProvider({ 13 | metadata: fs.readFileSync('./metadata/idp.xml') 14 | }); 15 | ``` 16 | 17 | Without importing a defined metadata, we provide an advanced way to configure the entities. The metadata can be created according to the parameters later on. 18 | 19 | ```js 20 | // service provider 21 | const sp = saml.ServiceProvider({ 22 | privateKey: readFileSync('./test/key/sp/privkey.pem'), 23 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 24 | isAssertionEncrypted: false, 25 | encPrivateKey: readFileSync('./test/key/sp/encryptKey.pem'), 26 | encPrivateKeyPass: 'g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN', 27 | // .... 28 | }); 29 | 30 | // identity provider 31 | const idp = saml.ServiceProvider({ 32 | privateKey: readFileSync('./test/key/idp/privkey.pem'), 33 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 34 | isAssertionEncrypted: false, 35 | encPrivateKey: readFileSync('./test/key/idp/encryptKey.pem'), 36 | encPrivateKeyPass: 'g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN', 37 | // .... 38 | }); 39 | ``` 40 | 41 | We will also generate the metadata for you if you use this advanced method to create your entity. See more [here](/metadata-distribution). 42 | 43 | ```js 44 | sp.getMetadata(); 45 | idp.getMetadata(); 46 | 47 | // or expose it to public (e.g. express.js) 48 | router.get('/metadata', (req, res) => { 49 | const metadata = sp.getMetadata(); 50 | return res.header('Content-Type','text/xml').send(metadata); 51 | }); 52 | ``` 53 | 54 | ## References 55 | 56 | + [Metadata for the OASIS Security Assertion Markup Language](https://www.oasis-open.org/committees/download.php/35391/sstc-saml-metadata-errata-2.0-wd-04-diff.pdf) 57 | + [SAML specification](http://saml.xml.org/saml-specifications) 58 | -------------------------------------------------------------------------------- /docs/encrypted-saml-response.md: -------------------------------------------------------------------------------- 1 | # Encrypted Assertion 2 | 3 | According to the guideline of SAML, our module leaves some security options for developers. If the assertion contains some sensitive information, Identity Provider may want to do encryption. In IdP's construction, add the following settings as follow: 4 | 5 | ```javascript 6 | const idp = IdentityProvider({ 7 | isAssertionEncrypted: true, 8 | metadata: fs.readFileSync('./metadata_idp.xml'), 9 | dataEncryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', 10 | keyEncryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-1_5' 11 | }); 12 | ``` 13 | 14 | If you remember SP configuration for signing a request, there are two parameters in the setting object. They are `privateKey` and `privateKeyPass`. **Warning:** If you are applying our solution instead of another 3rd party IdP, it's suggested not to use same key for both signing and encryption. 15 | 16 | In SP's metadata, the certificate must be included in order to allow idp to encrypt the assertion. 17 | 18 | ```xml 19 | 20 | 21 | 22 | MIID6TCCAtGg... 23 | 24 | 25 | 26 | ``` 27 | 28 | Now all you need to do is to use `sp.parseLoginResponse` again to parse and verify the response. 29 | 30 | ```javascript 31 | router.post('/acs', (req, res) => { 32 | sp.parseLoginResponse(idp, 'post', req) 33 | .then(parseResult => { 34 | // Use the parseResult to do customized action 35 | }) 36 | .catch(console.error); 37 | }); 38 | ``` 39 | 40 | Currently, we support the following encrpytion algorithms: 41 | 42 | **Data encryption algorithms** 43 | * http://www.w3.org/2001/04/xmlenc#tripledes-cbc 44 | * http://www.w3.org/2001/04/xmlenc#aes128-cbc 45 | * http://www.w3.org/2001/04/xmlenc#aes256-cbc 46 | 47 | **Key encryption algorithms** 48 | * http://www.w3.org/2001/04/xmlenc#rsa-1_5 49 | * http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p 50 | 51 | Credits to [auth0/node-xml-encryption](https://github.com/auth0/node-xml-encryption) 52 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ?> A tutorial is not only including text-book knowledge and guideline. Therefore, a number of examples are provided in this chapter. Different use cases for real application are covered in each example. 4 | 5 | **Entities** 6 | 7 | - [OneLogin](/onelogin) 8 | - [Gitlab](/gitlab) 9 | - [Okta](/okta) 10 | -------------------------------------------------------------------------------- /docs/gitlab.md: -------------------------------------------------------------------------------- 1 | # Work with Gitlab (samlify as idp) 2 | 3 | In this tutorial, we will walk through step by step to configure self-hosted and dockerized Gitlab CE, also integrates with samlify. 4 | 5 | ### Setup postgresql 6 | 7 | ``` 8 | docker run --name gitlab-postgresql -d \ 9 | --env 'DB_NAME=gitlabhq_production' \ 10 | --env 'DB_USER=gitlab' --env 'DB_PASS=password' \ 11 | --env 'DB_EXTENSION=pg_trgm' \ 12 | --volume /esaml2/postgresql:/var/lib/postgresql \ 13 | sameersbn/postgresql:9.6-2 14 | ``` 15 | !> Remember to configure file sharing when work with volume mount 16 | 17 | ### Setup redis 18 | 19 | ``` 20 | docker run --name gitlab-redis -d \ 21 | --volume /esaml2/redis:/var/lib/redis \ 22 | sameersbn/redis:latest 23 | ``` 24 | 25 | ### Running gitlab in container 26 | 27 | ``` 28 | docker run --name gitlab -d \ 29 | --link gitlab-postgresql:postgresql --link gitlab-redis:redisio \ 30 | --publish 10022:22 --publish 10080:80 \ 31 | --env 'GITLAB_PORT=10080' --env 'GITLAB_SSH_PORT=10022' \ 32 | --env 'GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alpha-numeric-string' \ 33 | --env 'GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alpha-numeric-string' \ 34 | --env 'GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alpha-numeric-string' \ 35 | --env 'OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=http://localhost:10080/users/auth/saml/callback' \ 36 | --env 'OAUTH_SAML_IDP_CERT_FINGERPRINT=77:36:12:0B:32:9A:6D:61:29:E1:0D:13:C0:FF:63:1A:B9:22:FC:3C' \ 37 | --env 'OAUTH_SAML_IDP_SSO_TARGET_URL=http://localhost:3001/sso/SingleSignOnService/gitlab' \ 38 | --env 'OAUTH_SAML_ISSUER=https://gitlab' \ 39 | --env 'OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress' \ 40 | --volume /esaml2/gitlab:/home/git/data \ 41 | sameersbn/gitlab:9.1.2 42 | ``` 43 | 44 | ### Get fingerprint (This is another way I found) 45 | 46 | ```console 47 | $ openssl x509 -in ./key/idp/cert.cer -sha1 -noout -fingerprint 48 | ``` 49 | 50 | ### Get metadata from gitlab 51 | 52 | `http://localhost:10080/users/auth/saml/metadata` 53 | 54 | remember to modify the acs endpoint to http://localhost:10080/users/auth/saml/callback 55 | 56 | ### The step-by-step configuration of IDP with samlify 57 | 58 | After setting up the gitlab, we need to set up the IDP with samlify. Beside, the identity provider is an experimental feature in this module. 59 | 60 | Since there are some required attributes are required and specified in the Gitlab metadata, so we need to add attributes to the response, so we need to customize response template when we construct the Identity provider. 61 | 62 | `email`, `name`, `first_name` and `last_name` (default email and name are `admin@example.com` and `Administrator` in docker-gitlab) 63 | 64 | And we need to change our metadata by setting `WantAuthnRequestsSigned` to false since the request from SP is not signed. 65 | 66 | Signed response is highly RECOMMENDED (compulsory in Gitlab's implementation), including assertion signature or/and entire message signature, so a new property `signatureConfig` is introduced into constructor of identity provider to specify the location, prefix of messsage signature, this configuration is exactly the same as [xml-crypto](https://github.com/yaronn/xml-crypto#examples). 67 | 68 | ```javascript 69 | const idp = require('samlify').IdentityProvider({ 70 | metadata: readFileSync('./misc/metadata_idp1.xml'), 71 | privateKey: './misc/privkey.pem', 72 | isAssertionEncrypted: false, 73 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 74 | loginResponseTemplate: { 75 | context: '{Issuer}{Issuer}{NameID}{Audience} AuthnContextClassRef', 76 | attributes: [ 77 | { name: "mail", valueTag: "user.email", nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", valueXsiType: "xs:string" }, 78 | { name: "name", valueTag: "user.name", nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", valueXsiType: "xs:string" }, 79 | { name: "first_name", valueTag: "user.first", nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", valueXsiType: "xs:string" }, 80 | { name: "last_name", valueTag: "user.last", nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", valueXsiType: "xs:string" }, 81 | ] 82 | }, 83 | signatureConfig: { 84 | prefix: 'ds', 85 | location: { reference: "/*[local-name(.)='Response']/*[local-name(.)='Issuer']", action: 'after' } 86 | } 87 | }); 88 | ``` 89 | 90 | ### The step-by-step configuration of SP with samlify 91 | 92 | ```javascript 93 | const sp = require('samlify').ServiceProvider({ 94 | metadata: readFileSync('./misc/metadata_sp1.xml') 95 | }); 96 | ``` 97 | 98 | the metadata is obtained from `http://localhost:10080/users/auth/saml/metadata` 99 | -------------------------------------------------------------------------------- /docs/guide.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tryretool/samlify/c960ef6d64382d4a021590a69b1e10ce17bb9cf8/docs/guide.md -------------------------------------------------------------------------------- /docs/idp-configuration.md: -------------------------------------------------------------------------------- 1 | # IDP Configuration 2 | 3 | You can use samlify as identity provider for testing/production purpose but you can also easily integrate samlify with the current identity provider setup. 4 | 5 | #### Required Parameters 6 | 7 | ?> You can either choose to import from metadata plus optional paramters, or defined properties plus optional parameters. 8 | 9 | - **metadata: String**
10 | IDP issued metadata to declare the structure and scope of the entity, as a common contract on how sso/slo should be proceeded. 11 | 12 | ```js 13 | const idp = new IdentityProvider({ 14 | // required 15 | metadata: readFileSync('./test/misc/idpmeta.xml'), 16 | // optional 17 | privateKey: readFileSync('./test/key/idp/privkey.pem'), 18 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 19 | encPrivateKey: readFileSync('./test/key/idp/encryptKey.pem'), 20 | encPrivateKeyPass: 'g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN', 21 | isAssertionEncrypted: true, 22 | }); 23 | ``` 24 | 25 | OR 26 | 27 | - **entityID: String**
Entity identifier. It is used to identify your entity, and match the equivalence in each saml request/response. 28 | 29 | - **signingCert: String**
30 | _Optional_: Specify the certificate used for signing purpose if you construct the idp without a metadata. 31 | 32 | - **encryptCert: String**
33 | _Optional_: Specify the certificate used for encryption purpose if you construct the idp without a metadata. 34 | 35 | - **singleSignOnService: SignOnService[]**
36 | _Optional_: Declare the single sign on service if you construct the idp without a metadata. 37 | 38 | - **singleLogoutService: SignLogoutService[]**
39 | _Optional_: Declare the single logout service if you construct the idp without a metadata. 40 | 41 | - **nameIDFormat: NameIDFormat[]**
42 | _Optional_: Declare the name id format that would respond if you construct the idp without a metadata. 43 | 44 | ```js 45 | const idp = new IdentityProvider({ 46 | // required 47 | entityID: 'http://hello-saml-idp.com/metadata', 48 | // optional parameters listed below 49 | }); 50 | ``` 51 | 52 | #### Optional Parameters 53 | 54 | - **wantAuthnRequestsSigned: Boolean**
55 | Declare if idp guarantees the authn request sent from sp is signed, reflects to the `WantAuthnRequestsSigned` in idp metadata, default to `false`. 56 | 57 | - **tagPrefix: {[key: TagPrefixKey]: string}**
58 | Declare the tag of specific xml document node. `TagPrefixKey` currently supports `encryptedAssertion` only. (See more [#220](https://github.com/tngan/samlify/issues/220)) 59 | 60 | - **loginResponseTemplate: {context: String, attributes: Attributes}**
61 | Customize the login response template, and user can reuse it in the callback function to do runtime interpolation. (See [more](/template)) 62 | 63 | - **wantLogoutResponseSigned: Boolean**
64 | Declare if idp guarantees the logout response from sp is signed. 65 | 66 | - **messageSigningOrder: SigningOrder**
67 | Declare the message signing order, either `sign-then-encrypt` (default) or `encrypt-then-sign`. 68 | 69 | - **relayState: String**
70 | Specify the relayState of the request. 71 | 72 | !> It will be deprecated soon and put into request level instead of entity level. 73 | 74 | - **isAssertionEncrypted: Boolean**
75 | Decalre if idp would encrypt the assertion in the response. 76 | 77 | !> It will be deprecated soon, then samlify will automatically detect if the document is encrypted. 78 | 79 | - **requestSignatureAlgorithm: SigningAlgorithm**
80 | The signature algorithm used in request. Default to `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`. We also support rsa-sha1 (not recommended) `http://www.w3.org/2000/09/xmldsig#rsa-sha1` and rsa-sha2 `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512`. 81 | 82 | - **dataEncryptionAlgorithm: EncryptionAlgorithm**
83 | The encryption algorithm used in response. Default to `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`. We also support aes256 `http://www.w3.org/2001/04/xmlenc#aes256-cbc` and tripledes `http://www.w3.org/2001/04/xmlenc#tripledes-cbc`. 84 | 85 | - **keyEncryptionAlgorithm: KeyEncryptionAlgorithm**
86 | The key encryption algorithm. Default to rsa-1_5 `http://www.w3.org/2001/04/xmlenc#rsa-1_5`. We also support rsa-oaep-mgf1p `http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p`. 87 | 88 | - **generateID: (): String**
89 | A function to generate the document identifier in root node. Default to `_${UUID_V4}`. 90 | -------------------------------------------------------------------------------- /docs/idp.md: -------------------------------------------------------------------------------- 1 | # Identity Provider 2 | 3 | Let's get started with entry point: 4 | ```javascript 5 | const saml = require('samlify'); 6 | ``` 7 | 8 | The following metadata is provided by the target identity provider. 9 | 10 | ```xml 11 | 12 | 13 | 14 | 15 | 16 | MIIEF... 17 | 18 | 19 | 20 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 21 | 22 | 23 | 24 | 25 | 26 | Support 27 | support@onelogin.com 28 | 29 | 30 | ``` 31 | 32 | Import the above metadata and get the identity provider ready. Previously, we only allow user to enter path to file and the module will read for users. Starting from v2, we have relaxed the configuration to accept string, it allows user importing their metadata, key and certificate files from different sources. For examples, read from database, file systems, online resources (public url for metadata) and even in-memory storage. 33 | 34 | !> **API is changed since v2** 35 | 36 | ```javascript 37 | // after v2 38 | const idp = saml.IdentityProvider({ 39 | metadata: fs.readFileSync('./metadata/onelogin_metadata_486670.xml') 40 | }); 41 | // before v2 (deprecated) 42 | // const idp = saml.IdentityProvider('./metadata/onelogin_metadata_486670.xml'); 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | samlify - High-level API for Single Sign On (SAML 2.0) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/key-generation.md: -------------------------------------------------------------------------------- 1 | # Key generation 2 | 3 | We use openssl to generate the keys and certificate for testing purpose. It is optional to use password protection for private key. The following is the commands to generate private key and self-signed certificate. 4 | 5 | ```console 6 | > openssl genrsa -passout pass:foobar -out encryptKey.pem 4096 7 | > openssl req -new -x509 -key encryptKey.pem -out encryptionCert.cer -days 3650 8 | ``` -------------------------------------------------------------------------------- /docs/metadata-distribution.md: -------------------------------------------------------------------------------- 1 | # Metadata distribution 2 | 3 | ?> Metadata is used to exchange information between Identity Provider and Service Provider. Simply there are two major ways to exchange Metadata. 4 | 5 | **Release in public ** 6 | 7 | Display the Metadata in a specific URL. Everyone has the URL can watch the Metadata. Therefore, the Metadata is distributed publicly. We provide an API to do it once you've configure your SP. 8 | 9 | ```javascript 10 | const saml = require('samlify'); 11 | const sp = saml.ServiceProvider({ 12 | metadata: fs.readFileSync('./metadata_sp.xml') 13 | }); 14 | router.get('/metadata', (req, res) => { 15 | res.header('Content-Type', 'text/xml').send(sp.getMetadata()); 16 | }); 17 | ``` 18 | 19 | If you use our IdP solution, you can also release the Metadata same as above. 20 | 21 | ```javascript 22 | const idp = saml.IdentityProvider({ 23 | metadata: fs.readFileSync('./metadata_idp.xml') 24 | }); 25 | router.get('/metadata', (req, res) => { 26 | res.header('Content-Type', 'text/xml').send(idp.getMetadata()); 27 | }); 28 | ``` 29 | 30 | **Export and distribute it privately** 31 | 32 | Some properties may not want their metadata to release publicly. If IdP or SP is configured explicitly, a helper method is provided to export the auto-generated metadata. 33 | 34 | ```javascript 35 | // Configure the entities without metadata 36 | const sp = saml.ServiceProvider(spSetting); 37 | const idp = saml.IdentityProvider(idpSetting); 38 | // Export the auto-generated Metadata to a specific file 39 | sp.exportMetadata('./distributed_sp_md.xml'); 40 | idp.exportMetadata('./distributed_idp_md.xml'); 41 | ``` 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/multi-entities.md: -------------------------------------------------------------------------------- 1 | # Multiple entities 2 | 3 | For those applications with many clients, each client may have its own Identity Provider. Developers just need to configure multiple IdPs. Different configuration of SP is required for different IdP, therefore multiple SPs are allowed. 4 | 5 | **Multiple IdPs - Single SP** 6 | 7 | ```javascript 8 | // define SP 9 | const sp = saml.ServiceProvider({ 10 | metadata: fs.readFileSync('./metadata_sp.xml') 11 | }); 12 | // define multiple IdPs 13 | const defaultIdP = saml.IdentityProvider({ 14 | metadata: fs.readFileSync('./metadata_idp_default.xml') 15 | }); 16 | const oneloginIdP = saml.IdentityProvider({ 17 | metadata: fs.readFileSync('./metadata_onelogin.xml') 18 | }); 19 | // URL routing for SP-initiated SSO 20 | router.get('/spinitsso-post/:idp', (req, res) => { 21 | let targetIdP = undefined; 22 | switch(req.params.idp) { 23 | case 'onelogin': { 24 | targetIdP = oneloginIdP; 25 | break; 26 | } 27 | default: { 28 | targetIdP = idp; 29 | break; 30 | } 31 | } 32 | return sp.createLoginRequest(targetIdP, 'post', (req, res) => res.render('actions', req)); 33 | }); 34 | ``` 35 | 36 | Using the same SP configuration, it can apply to different IdPs. We've played a trick here, the initiated URL for SP-inititated SSO is controlled by a parameter. When user accesses `/spinitsso-post/onelogin`, the OneLogin IdP is used. When user accesses `/spinitsso-post/default`, the default IdP is then used for authentication. 37 | 38 | **Multiple IdPs - Mutiple SPs** 39 | 40 | Different IdPs may have different preference, so single SP configuration may not be suitable. For example, OneLogin IdP requires a request with signature but our default IdP does not. Here we come up with another solution which is very similar to the previous one. 41 | 42 | ```javascript 43 | // define a default SP 44 | const defaultSP = saml.ServiceProvider({ 45 | metadata: fs.readFileSync('./metadata_sp.xml') 46 | }); 47 | // define SP for OneLogin with different metadta 48 | const oneloginSP = saml.ServiceProvider({ 49 | metadata: fs.readFileSync('./metadata_sp_for_oneLogin.xml') 50 | }); 51 | // define a default IdP 52 | const defaultIdP = saml.IdentityProvider({ 53 | metadata: fs.readFileSync('./metadata_idp_default.xml') 54 | }); 55 | // define OneLogin IdP 56 | const oneloginIdP = saml.IdentityProvider({ 57 | metadata: fs.readFileSync('./metadata_idp_onelogin.xml') 58 | }); 59 | // URL routing for SP-initiated SSO 60 | router.get('/spinitsso-post/:idp', function(req, res) { 61 | let targetIdP = undefined; 62 | let sourceSP = undefined; 63 | switch(req.params.idp || '') { 64 | case 'onelogin': { 65 | targetIdP = oneloginIdP; 66 | sourceSP = oneloginSP; 67 | break; 68 | } 69 | default: { 70 | targetIdP = idp; 71 | sourceSP = defaultSP; 72 | break; 73 | } 74 | } 75 | return sourceSP.createLoginRequest(targetIdP, 'post', (req, res) => res.render('actions', request)); 76 | }); 77 | ``` 78 | -------------------------------------------------------------------------------- /docs/okta-inbound.md: -------------------------------------------------------------------------------- 1 | In progress ... -------------------------------------------------------------------------------- /docs/okta.md: -------------------------------------------------------------------------------- 1 | ## Work with Okta (Credit to [@fas3r](https://github.com/fas3r)) 2 | 3 | ?> In this chapter, we will make an sample application that implements SP-initiated SSO. 4 | 5 | ### Pre-requirement: 6 | 7 | samlify, express (or other), body-parser. 8 | 9 | ### Step-by-step tutorial: 10 | 11 | 1. Create a new web app with SAML2.0 in okta : 12 | 13 | ![](https://user-images.githubusercontent.com/11342586/54870114-a3396880-4da2-11e9-9e79-3debd7f6c93f.png) 14 | 15 | 16 | 2. Configure SAML_integration: 17 | 18 | - General setting: 19 | 20 | ![](https://user-images.githubusercontent.com/11342586/54870126-b8ae9280-4da2-11e9-9154-39a697e0a69a.png) 21 | 22 | - Configure SAML : 23 | 24 | !> Never upload your private key online 25 | 26 | ![](https://user-images.githubusercontent.com/11342586/54870230-f7911800-4da3-11e9-920e-66c22fca8b14.png) 27 | 28 | * "Single Sign on URL": the uri where to "POST" the auth request 29 | * "Audience URI": The uri where the metadata are accessible. This is not mandatory if you don't want to share the metadata file. See [here](https://samlify.js.org/#/metadata-distribution) 30 | * "Assertion Encryption": We set to "Encrypted". Indicates whether the SAML assertion is encrypted. 31 | * "Encryption Certificate" : Upload the path to the certificate `*.cer` to use to encrypt the assertion. 32 | 33 | ![](https://user-images.githubusercontent.com/11342586/54870264-9289f200-4da4-11e9-8ce4-560aaa8e99d7.png) 34 | 35 | * and the attributes statement/groups to return in the assertion section 36 | 37 | - Feedback: 38 | 39 | ![](https://user-images.githubusercontent.com/11342586/54870275-b1888400-4da4-11e9-96ec-d09a61cf00a5.png) 40 | 41 | * Choose your desired one. 42 | 43 | 3. Next you will see in the "Sign On" tab the following : 44 | 45 | ![](https://user-images.githubusercontent.com/11342586/54870311-18a63880-4da5-11e9-815f-f73ab237e954.png) 46 | 47 | - Red Arrow: The SAML 2.0 Certificate 48 | - Green Arrow: Get the idp XML file of your application with all the information 49 | - Blue Arrow: Direct link to the metadata file of the application. 50 | - In the "General" tab you should see something like : 51 | 52 | ![](https://user-images.githubusercontent.com/11342586/54870350-a2ee9c80-4da5-11e9-8c32-c05eaae3d7c9.png) 53 | 54 | 55 | 4. Example code snippet 56 | 57 | ```js 58 | const express = require('express'); 59 | const fs = require('fs'); 60 | const saml = require('samlify'); 61 | const axios = require('axios'); 62 | const bodyParser = require("body-parser"); 63 | const app = express(); 64 | app.use(bodyParser.urlencoded({ extended: true })); 65 | app.use(bodyParser.json()); 66 | app.use(serveStatic(path.resolve(__dirname, 'public'))); 67 | 68 | // URL to the okta metadata 69 | const uri_okta_metadata = 'https://dev-xxxxxxx.oktapreview.com/app/APP_ID/sso/saml/metadata'; 70 | 71 | axios.get(uri_okta_metadata) 72 | .then(response => { 73 | 74 | const idp = saml.IdentityProvider({ 75 | metadata: response.data, 76 | isAssertionEncrypted: true, 77 | messageSigningOrder: 'encrypt-then-sign', 78 | wantLogoutRequestSigned: true 79 | }); 80 | 81 | const sp = saml.ServiceProvider({ 82 | entityID: 'http://localhost:8080/sp/metadata?encrypted=true', 83 | authnRequestsSigned: false, 84 | wantAssertionsSigned: true, 85 | wantMessageSigned: true, 86 | wantLogoutResponseSigned: true, 87 | wantLogoutRequestSigned: true, 88 | // the private key (.pem) use to sign the assertion; 89 | privateKey: fs.readFileSync(__dirname + '/ssl/sign/privkey.pem'), 90 | // the private key pass; 91 | privateKeyPass: 'VHOSp5RUiBcrsjrcAuXFwU1NKCkGA8px', 92 | // the private key (.pem) use to encrypt the assertion; 93 | encPrivateKey: fs.readFileSync(__dirname + '/ssl/encrypt/privkey.pem'), 94 | isAssertionEncrypted: true, 95 | assertionConsumerService: [{ 96 | Binding: saml.Constants.namespace.post, 97 | Location: 'http://localhost:8080/sp/acs?encrypted=true', 98 | }] 99 | }); 100 | 101 | app.post('/sp/acs', async (req, res) => { 102 | try { 103 | const { extract } = await sp.parseLoginResponse(idp, 'post', req); 104 | console.log(extract.attributes); 105 | /** 106 | * 107 | * Implement your logic here. 108 | * extract.attributes, should contains : firstName, lastName, email, uid, groups 109 | * 110 | **/ 111 | } catch (e) { 112 | console.error('[FATAL] when parsing login response sent from okta', e); 113 | return res.redirect('/'); 114 | } 115 | }); 116 | 117 | app.get('/login', async (req, res) => { 118 | const { id, context } = await sp.createLoginRequest(idp, 'redirect'); 119 | console.log(context); 120 | return res.redirect(context); 121 | }); 122 | 123 | app.get('/sp/metadata', (req, res) => { 124 | console.log("here"); 125 | res.header('Content-Type', 'text/xml').send(idp.getMetadata()); 126 | }); 127 | 128 | }); 129 | ``` -------------------------------------------------------------------------------- /docs/prerequistite.md: -------------------------------------------------------------------------------- 1 | # Knowledge 2 | 3 | There is no prerequisite for using this module. You can skip this chapter in case you are familiar with Single Sign On and have worked before. Otherwise, it's recommended to go through this chapter once and get some insights. 4 | 5 | ## What is Single Sign On (SSO) ? 6 | 7 | SSO is an access control strategy for multiple applications. Just imagine that you have to log-in different internal systems in a company every morning. It's really annoying when you type your account name and password. Also you imagine if you were the guy in IT department. Every time a new employee is hired, you have to create an account information for each internal systems. It turns out that really difficult to manage the credentials. 8 | 9 | By using SSO, user can memorize one set of credential to log-in an **Identity Provider** for authentication. User can access those systems because of the trust-worthy relationship among IdP and those systems. 10 | -------------------------------------------------------------------------------- /docs/saml-request.md: -------------------------------------------------------------------------------- 1 | # SAML Request 2 | 3 | When we apply SP-initiated SSO, our Service Provider have to send a SAML Request to Identity Provider. 4 | 5 | SAML Request is in XML format, asking if identity provider can authenticate this user. The following is a sample request without signature. 6 | 7 | ```xml 8 | 17 | https://sp.example.org/metadata 18 | 19 | 20 | urn:oasis:names:tc:SAML:2.0:ac:classes:Password 21 | 22 | 23 | ``` 24 | 25 | Different bindings can be used to send this request, we support Redirect-Binding and Post-Binding. 26 | 27 | **Redirect-Binding** 28 | 29 | It means that the XML is embedded as an URL parameter and redirect to the SSO endpoint of IdP. Because of different length limitation in different browsers, it's required to deflate Request. 30 | 31 | ```javascript 32 | const saml = require('samlify'); 33 | const sp = saml.ServiceProvider({ 34 | metadata: fs.readFileSync('./metadata_sp.xml') 35 | }); 36 | const idp = saml.IdentityProvider({ 37 | metadata: fs.readFileSync('./metadata_idp.xml') 38 | }); 39 | ``` 40 | 41 | The SSO endpoint of IdP is specified in their metadata. For example: 42 | 43 | ```xml 44 | 45 | 46 | ``` 47 | 48 | There may be more than one SSO endpoint, to support different bindings. By using our entity level API, you can just write your initiation point in any route you want as follow: 49 | 50 | ```javascript 51 | router.get('/spinitsso-redirect', (req, res) => { 52 | const { id, context } = sp.createLoginRequest(idp, 'redirect'); 53 | return res.redirect(context); 54 | }); 55 | ``` 56 | By applying the preference of SP and IdP, `sp.createLoginRequest`returns an URL which is in following general format: 57 | 58 | https://idp.example.org/sso/SingleSignOnService?SAMLRequest=www&SigAlg=xxx&RelayState=yyy&Signature=zzz 59 | 60 | The parameters **SigAlg** and **Signature** is optional in case IdP requests your SAML Request should be signed. **relayState** is also optional if the application needs a deep link to access. 61 | 62 | All the corresponding values are URL-encoded. **Signature** is already Base64-encoded and the deflated **SAMLRequest** should be Base64-encoded. 63 | 64 | **Post-Binding** 65 | 66 | The Request XML is sent via a form post instead of embedding in URL parameters. By using the same method as in Redirect-Binding: 67 | 68 | ```javascript 69 | router.get('/spinitsso-redirect', (req, res) => { 70 | res.render('actions', sp.createLoginRequest(idp, 'post')); 71 | }); 72 | ``` 73 | 74 | You can simply change the second argument from 'redirect' to 'post'. This time the callback function returns an object instead of a string. It is then fed to a generic form post template as follow: 75 | 76 | ```html 77 |
78 | 79 | {{#if relayState}} 80 | 81 | {{/if}} 82 |
83 | 89 | ``` 90 | 91 | Handlebar view engine is used in this example, you may choose your own and configure in your `app.js`. 92 | 93 | ```javascript 94 | app.engine('handlebars', exphbs({defaultLayout: 'main'})); 95 | app.set('view engine', 'handlebars'); 96 | ``` 97 | 98 | After those values are filled into the tags, the form will be automatically submit. 99 | 100 | ?> **What's the next ?**

101 | Identity Provider parses SP's request, then a SAML Response is sent back to SP. The response includes the authentication result. SP can then take action to create session for authenticated user if the result is successful. 102 | -------------------------------------------------------------------------------- /docs/signed-saml-request.md: -------------------------------------------------------------------------------- 1 | # Signed SAML Request 2 | 3 | We follow the preference in metadata files. If it doesn't state in the metadata, default is not to sign the SAML Request. 4 | 5 | In IdP's metadata, there is an attribute called `WantAuthnRequestsSigned`. Default value is `false`. 6 | 7 | ```xml 8 | 12 | ``` 13 | In SP's metadata, there is an attribute called `AuthnRequestsSigned`. Default value is `false`. 14 | 15 | ```xml 16 | 19 | ``` 20 | 21 | and include the X.509 certificate in SP's metadata. 22 | 23 | ```xml 24 | 28 | 29 | 30 | 31 | 32 | MIIDozCCAougAwIBAgIJAKN... 33 | 34 | 35 | 36 | ... 37 | ``` 38 | 39 | If both two attributes are not matched, an error will be thrown out during run-time. Developers can easily locate the error. 40 | 41 | If IdP doesn't provide the metadata for you, 1) you may ask them 2) import an object setting, see advanced topics [here](). 42 | 43 | Metadata stores the preferences only. To sign a XML document, we still need our **private key** and **signature algorithm**. We can configure our SP here: 44 | 45 | ```javascript 46 | const saml = require('samlify'); 47 | // Define the setting 48 | const setting = { 49 | privateKey: fs.readFileSync('./key/sp_key.pem'), 50 | privateKeyPass: 'KCkGOSjrcAuXFwU1pVH5RUiBcrsNA8px', 51 | requestSignatureAlgorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512', 52 | metadata: fs.readFileSync('./metadata_sp.xml') 53 | }; 54 | // Construct our service provider 55 | const sp = saml.ServiceProvider(setting); 56 | ``` 57 | 58 | The property `privateKeyPass` is optional in case you have set a passphrase when the private key is created. Also the default value of `requestSignatureAlgorithm` is RSA-SHA1. 59 | 60 | All support signature algorithms: 61 | ```javascript 62 | 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 63 | 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 64 | 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512' 65 | ``` 66 | Once you have configured the SP correctly, all you need to send a signed SAML Request is to do as follow: 67 | 68 | ```javascript 69 | router.get('/spinitsso-redirect', (req, res) => { 70 | const { id, context } = sp.createLoginRequest(idp, 'redirect'); 71 | return res.redirect(context); 72 | }); 73 | ``` 74 | 75 | Yes, it's the same method we used to send a SAML Request without signature. 76 | 77 | **How to generate a signature** 78 | 79 | For those who are not interested in how the signature generates, you can skip this section. The signature is generated by two different formats. 80 | 81 | In **Redirect-Binding**, the URL-encoded message should be assigned as follow: 82 | 83 | + Octet string is a concatenation of SAMLRequest, RelayState and SigAlg.`SAMLRequest=xxx&RelayState=yyy&SigAlg=zzz` 84 | + Signature MUST be encoded by base64 encoding. 85 | + RelayState is an optional parameter. If there is no RelayState value, this parameter should be ignored from computing signature. e.g. `SAMLRequest=xxx&SigAlg=zzz` 86 | 87 | 88 | In **Post-Binding**, XML digital signature is used and embedded inside the Request XML. 89 | 90 | ```xml 91 | 101 | 102 | https://sp.example.org/metadata 103 | 104 | 105 | urn:oasis:names:tc:SAML:2.0:ac:classes:Password 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | tQDisBXKTQ+9OXJO5r7KuJga+KI= 118 | 119 | 120 | oxRkvau7UvYgFEZ7YNAUNf3067V7Tn5C9XSIiet1aZw2FYevNW5bUy/0mxp3aj6AvfFjnmpzAb88BjdwAz2BErDTomRcuZB7Lb0fYTf31N2oZOX0MiPiQOH54I63qJW4Xo3VqdF7GBuFZZHyllfSBv7gfCtjJDwFSCzWK70B9r3cFMRJZLhCJ9oPen+4U9scSYO6g+szBZLl6AiJ06PHc8jzEKGwfQrcZk8kDKUlvNfJMULyq8dpx2VvUAx4p5ewfMOwB9W3Hl3PPa0dO77zZif3CglpcN06f+m6UYG/wnoTQEyKW9hOe+2vGM80W77eWu0dmiaPuqT1ok8LXPuq1A== 121 | 122 | 123 | ``` 124 | -------------------------------------------------------------------------------- /docs/signed-saml-response.md: -------------------------------------------------------------------------------- 1 | # Signed SAML Response 2 | 3 | The configuration for the use case receiving signed SAML Response is very simple. First, developers have to make sure that Identity Provider would sign the response. Second, define the property `WantAssertionsSigned` in SP's metadata inside the `SPSSODescriptor` tag. 4 | 5 | ```xml 6 | 10 | ``` 11 | Currently, we support the following algorithms: 12 | 13 | **Signature algorithms** 14 | * http://www.w3.org/2000/09/xmldsig#rsa-sha1 (Default) 15 | * http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 16 | * http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 17 | * http://www.w3.org/2000/09/xmldsig#hmac-sha1 18 | 19 | **Hashing Algorithms** 20 | * http://www.w3.org/2000/09/xmldsig#sha1 (Default) 21 | * http://www.w3.org/2001/04/xmlenc#sha256 22 | * http://www.w3.org/2001/04/xmlenc#sha512 23 | 24 | **Canonicalization and Transformation Algorithms** 25 | * http://www.w3.org/2001/10/xml-exc-c14n# 26 | * http://www.w3.org/2001/10/xml-exc-c14n#WithComments 27 | * http://www.w3.org/2000/09/xmldsig#enveloped-signature 28 | 29 | Credits to [yaronn/xml-crypto](https://github.com/yaronn/xml-crypto). 30 | 31 | !> SAML Response must be signed if you use our API for creating identity providers. 32 | 33 | We recommend user to accept signed response in their service provider. Therefore, our identity provider is RECOMMENDED to sign the response in order to maintain the confidentiality and message integrity [Section 4.1.3.5](http://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf). 34 | 35 | There are different examples of signing scheme supported in samlify. 36 | 37 | + **Unsigned message, Signed assertion (wo/ encryption)** 38 | 39 | To guarantee the setting in between idp-sp pair is synchronized, determination of assertion signature depends on the sp setting. Set `WantAssertionsSigned` to true in corresponding sp's metadata or `wantAssertionsSigned` in constructor if metadata is not set. 40 | 41 | ```javascript 42 | const sp = ServiceProvider({ 43 | // ... 44 | metadata: readFileSync('./sp-metadata.xml'), 45 | // must have if assertion signature fails validation 46 | // transformationAlgorithms: [ 47 | // 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 48 | // 'http://www.w3.org/2001/10/xml-exc-c14n#', 49 | // ], 50 | }); 51 | 52 | const idp = IdentityProvider({ 53 | // ... 54 | metadata: readFileSync('./idp-metatadata.xml'), 55 | privateKey: readFileSync('./mysecret.pem'), 56 | privateKeyPass: 'zzz', // if has 57 | // must have if metadata is not provided 58 | // signingCert: readFileSync('./signing.cer') 59 | }); 60 | ``` 61 | 62 | The certificate of identity provider will be included in its metadata, or specify in constructor as `signingCert`. 63 | 64 | + **Unsigned message, Signed & Encrypted assertion** 65 | 66 | SP's preparation is same as the first case. For encrpytion part, identity provider encrypts the assertion with sp's certificate (public key) and sp can decrypt the response using sp's private key. 67 | 68 | IdP controls whether the response is encrypted or not. 69 | 70 | ```javascript 71 | // create in sp side, private key for decryption is owned by sp only 72 | 73 | const sp = ServiceProvider({ 74 | // ... 75 | metadata: readFileSync('./sp-metadata.xml'), 76 | encPrivateKey: fs.readFileSync('./encryptKey.pem'), 77 | encPrivateKeyPass: 'yyy', 78 | // must have if metadata is not provided 79 | // signingCert: readFileSync('./signing.cer') 80 | // encryptCert: readFileSync('./encrypt.cer') 81 | }); 82 | ``` 83 | 84 | ```javascript 85 | // create in idp side 86 | 87 | const sp = ServiceProvider({ 88 | // ... 89 | metadata: readFileSync('./sp-metadata.xml'), 90 | }); 91 | 92 | const idp = IdentityProvider({ 93 | // ... 94 | isAssertionEncrypted: true, 95 | metadata: readFileSync('./idp-metatadata.xml'), 96 | privateKey: readFileSync('./mysecret.pem'), 97 | privateKeyPass: 'xxx', // if has 98 | // must have if metadata is not provided 99 | // signingCert: readFileSync('./signing.cer') 100 | }); 101 | ``` 102 | 103 | + **Signed message, Unsigned assertion (w/wo encryption)** 104 | 105 | There are two new properties added into the constructor method for idp starting from v2. `wantMessageSigned` and `signatureConfig` are used to enrich our signature scheme whereas `signatureConfig` is same as the configuration in [xml-crypto](https:// 106 | github.com/yaronn/xml-crypto#examples). 107 | 108 | ```javascript 109 | const idp = IdentityProvider({ 110 | // ... 111 | wantMessageSigned: true, 112 | signatureConfig: { 113 | prefix: 'ds', 114 | location: { 115 | reference: '/samlp:Response/saml:Issuer', 116 | action: 'after' 117 | } 118 | } 119 | }); 120 | ``` 121 | 122 | + **Signed message, Signed assertion (wo/ encryption)** 123 | 124 | See above signed message and signed assertion setting. 125 | 126 | + **Signed message, Signed & Encrypted assertion** 127 | 128 | The most complex case, see above all. -------------------------------------------------------------------------------- /docs/sp-configuration.md: -------------------------------------------------------------------------------- 1 | # SP Configuration 2 | 3 | #### Required Parameters 4 | 5 | ?> You can either choose to import from metadata plus optional paramters, or defined properties plus optional parameters. 6 | 7 | - **metadata: String**
8 | SP issued metadata to declare the structure and scope of the entity, as a common contract on how sso/slo should be proceeded. 9 | 10 | ```js 11 | const sp = new ServiceProvider({ 12 | // required 13 | metadata: readFileSync('./test/misc/spmeta.xml'), 14 | // optional 15 | privateKey: readFileSync('./test/key/sp/privkey.pem'), 16 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 17 | encPrivateKey: readFileSync('./test/key/sp/encryptKey.pem'), 18 | encPrivateKeyPass: 'g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN' 19 | }); 20 | ``` 21 | 22 | OR 23 | 24 | - **entityID: String**
Entity identifier. It is used to identify your entity, and match the equivalence in each saml request/response. 25 | 26 | - **authnRequestsSigned: Boolean**
27 | _Optional_: Declare if sp signs the authn request, reflects to the `AuthnRequestsSigned` in sp metadata, default to `false`. 28 | 29 | - **wantAssertionsSigned: Boolean**
30 | _Optional_: Declare if sp wants the signed assertion, reflects to the `WantAssertionsSigned` in sp metadata, default to `false`. 31 | 32 | - **wantMessageSigned: Boolean**
33 | _Optional_: Declare if sp wants the signed message, default to `false`. 34 | 35 | - **signingCert: String**
36 | _Optional_: Specify the certificate used for signing purpose if you construct the sp without a metadata. 37 | 38 | - **encryptCert: String**
39 | _Optional_: Specify the certificate used for encryption purpose if you construct the sp without a metadata. 40 | 41 | - **elementsOrder: String[]**
42 | _Optional_: Define the DOM structure of xml document, default to `['KeyDescriptor', 'NameIDFormat', 'SingleLogoutService', 'AssertionConsumerService']`. (See more [#89](https://github.com/tngan/samlify/issues/89)) 43 | 44 | - **nameIDFormat: NameIDFormat[]**
45 | _Optional_: Declare the name id format that would respond if you construct the sp without a metadata. The request will always pick the first one if multiple formats are specified. 46 | 47 | - **singleLogoutService: Service[]**
48 | _Optional_: Declare the single logout service if you construct the sp without a metadata. 49 | 50 | - **assertionConsumerService: Service[]**
51 | _Optional_: Declare the asssertion consumer service where the saml response redirects to if you construct the sp without a metadata. 52 | 53 | - **signatureConfig: SignatureConfig**
54 | _Optional_: Configure how the signature is being constructed. (See [more](/signed-saml-response)) 55 | 56 | ```js 57 | const sp = new ServiceProvider({ 58 | // required 59 | entityID: 'http://hello-saml-sp.com/metadata', 60 | // optional parameters listed below 61 | }); 62 | ``` 63 | 64 | #### Optional Parameters 65 | 66 | - **loginRequestTemplate: {context: String, attributes: Attributes}**
67 | Customize the login request template, and user can reuse it in the callback function to do runtime interpolation. (See [more](/template)) 68 | 69 | - **wantLogoutRequestSigned: Boolean**
70 | Declare if sp guarantees the logout request from idp is signed. 71 | 72 | - **relayState: String**
73 | Specify the relayState of the request. 74 | 75 | !> It will be deprecated soon and put into request level instead g of entity level. 76 | 77 | - **generateID: (): String**
78 | A function to generate the document identifier in root node. Default to `_${UUID_V4}`. 79 | 80 | - **clockDrifts: [Number, Number]**
81 | A time range allowing for drifting the range that specified in the SAML document. The first one is for the `notBefore` time and the second one is for `notOnOrAfter`. Default value of both drift value is `0`. The unit is in `ms`. 82 | 83 | For example, if you set `[-5000, 3000]`. The value can be either positive or negative in order to take care of the flexibility. 84 | 85 | ```console 86 | # tolerated timeline 87 | notBefore - 5s >>>>>>> notBefore >>>>>>> notAfter ---- notAfter + 3s 88 | 89 | # new valid time 90 | notBefore - 5s >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> notAfter + 3s 91 | ``` 92 | 93 | Another example, if you don't set, the default drift tolerance is `[0, 0]`. The valid range is trivial. 94 | 95 | ```console 96 | # valid time 97 | notBefore >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> notAfter 98 | ``` 99 | 100 | ?> The flow will skip the validation when there is no `notBefore` and `notOnOrAfter` at the same time. 101 | 102 | ?> See [SAML Core P.19](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) for more detail. 103 | -------------------------------------------------------------------------------- /docs/sp.md: -------------------------------------------------------------------------------- 1 | # Service Provider 2 | 3 | Let's get started to get the entry point. 4 | 5 | ```javascript 6 | const saml = require('samlify'); 7 | ``` 8 | 9 | You should have prepared the metadata of service provider. 10 | 11 | ```xml 12 | 17 | 18 | 19 | 20 | 21 | MIID... 22 | 23 | 24 | 25 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 26 | 27 | 28 | 29 | ``` 30 | 31 | Import the above metadata and get the service provider ready. Previously, we only allow user to enter path to file and the module will read for users. Starting from v2, we have relaxed the configuration to accept string, it allows user importing their metadata, key and certificate files from different sources. For examples, read from database, file systems, online resources (public url for metadata) and even in-memory storage. 32 | 33 | !> **API is changed since v2** 34 | 35 | ```javascript 36 | // after v2 37 | const sp = saml.ServiceProvider({ 38 | metadata: fs.readFileSync('./metadata/sp.xml') 39 | }); 40 | // before v2 (deprecated) 41 | // const sp = saml.ServiceProvider('./metadata/sp.xml'); 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/template.md: -------------------------------------------------------------------------------- 1 | # Attributes in response 2 | 3 | ?> **Starting from v2, we provide a shortcut for user to construct the attributes section efficiently instead of hard code the attribute information in template string.** 4 | 5 | ```javascript 6 | const idp = require('samlify').IdentityProvider({ 7 | // ... 8 | loginResponseTemplate: { 9 | context: ', 10 | attributes: [ 11 | { name: "mail", valueTag: "user.email", nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", valueXsiType: "xs:string" }, 12 | { name: "name", valueTag: "user.name", nameFormat: "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", valueXsiType: "xs:string" } 13 | ] 14 | } 15 | }); 16 | ``` 17 | 18 | then the attributes part will be included in the template string: 19 | 20 | ```xml 21 | 22 | 25 | 26 | {attrUserEmail} 27 | 28 | 29 | 32 | 33 | {attrUserName} 34 | 35 | 36 | 37 | ``` 38 | 39 | the tag name is auto-generated with prefix `attr` and the suffix is formatted as camel case of `valueTag` specified in the config. 40 | 41 | # Custom templates 42 | 43 | Developer can design their own request and response template for log-in and log-out respectively. There are optional parameters in setting object. 44 | 45 | ```javascript 46 | const saml = require('samlify'); 47 | 48 | // load the template every time before each request/response is sent 49 | const sp = saml.ServiceProvider({ 50 | //... 51 | loginRequestTemplate: { 52 | context: readFileSync('./loginResponseTemplate.xml'), 53 | } 54 | }); 55 | ``` 56 | 57 | In SP configuration, `loginRequestTemplate` is the template of SAML Request, it can be either file name or XML string. This is the default template we've used in our module. 58 | 59 | ```xml 60 | 69 | 70 | {Issuer} 71 | 74 | 75 | 76 | ``` 77 | 78 | When you apply your own template, remember to do custom tag replacement when you send out the request. `replaceTagFromTemplate` is just the name here to illustrate but it's not fixed. 79 | 80 | ```javascript 81 | router.get('/spinitsso-redirect', (req, res) => { 82 | 83 | const { id, context } = sp.createLoginRequest(idp, 'redirect', loginRequestTemplate => { 84 | // Here is the callback function for custom template 85 | // the input parameter is the value of loginRequestTemplate 86 | // The following is the input parameter of rcallback in different actions 87 | // sp.createLoginRequest -> loginRequestTemplate 88 | // sp.createLogoutResponse -> logoutResponseTemplate 89 | // idp.createLoginResponse -> loginResponseTemplate 90 | // idp.createLogoutRequest -> logoutRequestTemplate 91 | // replaceTagFromTemplate is a function to do dynamically substitution of tags 92 | return replaceTagFromTemplate(loginRequestTemplate); 93 | }); 94 | 95 | return res.redirect(context); 96 | 97 | }); 98 | ``` 99 | 100 | !> `replaceTagFromTemplate` must return the object containing `id` (response id) and `context` (string) 101 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | // version <= 1.25 2 | import IdentityProvider, { IdentityProvider as IdentityProviderInstance } from './src/entity-idp'; 3 | import ServiceProvider, { ServiceProvider as ServiceProviderInstance } from './src/entity-sp'; 4 | 5 | export { default as IdPMetadata } from './src/metadata-idp'; 6 | export { default as SPMetadata } from './src/metadata-sp'; 7 | export { default as Utility } from './src/utility'; 8 | export { default as SamlLib } from './src/libsaml'; 9 | // roadmap 10 | // new name convention in version >= 3.0 11 | import * as Constants from './src/urn'; 12 | import * as Extractor from './src/extractor'; 13 | 14 | // exposed methods for customising samlify 15 | import { setSchemaValidator } from './src/api'; 16 | 17 | export { 18 | Constants, 19 | Extractor, 20 | // temp: resolve the conflict after version >= 3.0 21 | IdentityProvider, 22 | IdentityProviderInstance, 23 | ServiceProvider, 24 | ServiceProviderInstance, 25 | // set context 26 | setSchemaValidator 27 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samlify", 3 | "version": "2.7.4", 4 | "description": "High-level API for Single Sign On (SAML 2.0)", 5 | "main": "build/index.js", 6 | "keywords": [ 7 | "nodejs", 8 | "saml2", 9 | "sso", 10 | "slo", 11 | "metadata" 12 | ], 13 | "typings": "types/index.d.ts", 14 | "scripts": { 15 | "build": "yarn audit;make rebuild", 16 | "docs": "docsify serve -o docs", 17 | "lint": "tslint -p .", 18 | "lint:fix": "tslint -p . --fix", 19 | "pretest": "make pretest", 20 | "test": "NODE_ENV=test nyc ava", 21 | "coverage": "nyc report --reporter=text-lcov | coveralls", 22 | "hooks:postinstall": "ln -sf $PWD/.pre-commit.sh $PWD/.git/hooks/pre-commit" 23 | }, 24 | "contributors": [ 25 | "Tony Ngan " 26 | ], 27 | "author": "tngan", 28 | "repository": { 29 | "url": "https://github.com/tngan/samlify", 30 | "type": "git" 31 | }, 32 | "license": "MIT", 33 | "dependencies": { 34 | "camelcase": "^5.3.1", 35 | "node-forge": "^0.8.5", 36 | "node-rsa": "^1.0.5", 37 | "pako": "^1.0.10", 38 | "uuid": "^3.3.2", 39 | "xml": "^1.0.1", 40 | "xml-crypto": "^1.5.3", 41 | "xml-encryption": "^1.1.1", 42 | "xmldom": "^0.1.27", 43 | "xpath": "^0.0.27" 44 | }, 45 | "devDependencies": { 46 | "@ava/typescript": "^1.1.1", 47 | "@types/node": "^11.11.3", 48 | "@types/node-forge": "^0.7.4", 49 | "@types/pako": "^1.0.1", 50 | "@types/uuid": "3.0.0", 51 | "@types/xmldom": "^0.1.28", 52 | "ava": "^3.8.2", 53 | "coveralls": "^3.1.0", 54 | "nyc": "^15.0.1", 55 | "timekeeper": "^2.2.0", 56 | "ts-node": "^8.3.0", 57 | "tslint": "^6.1.2", 58 | "typescript": "^3.8.3" 59 | }, 60 | "ava": { 61 | "extensions": [ 62 | "ts" 63 | ], 64 | "require": [ 65 | "ts-node/register" 66 | ], 67 | "files": [ 68 | "!**/*.d.ts" 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/api.ts: -------------------------------------------------------------------------------- 1 | // global module configuration 2 | interface Context extends ValidatorContext {} 3 | 4 | interface ValidatorContext { 5 | validate?: (xml: string) => Promise; 6 | } 7 | 8 | const context: Context = { 9 | validate: undefined 10 | }; 11 | 12 | export function getContext() { 13 | return context; 14 | } 15 | 16 | export function setSchemaValidator(params: ValidatorContext) { 17 | 18 | if (typeof params.validate !== 'function') { 19 | throw new Error('validate must be a callback function having one arguemnt as xml input'); 20 | } 21 | 22 | // assign the validate function to the context 23 | context.validate = params.validate; 24 | 25 | } -------------------------------------------------------------------------------- /src/entity-idp.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file entity-idp.ts 3 | * @author tngan 4 | * @desc Declares the actions taken by identity provider 5 | */ 6 | import Entity, { ESamlHttpRequest } from './entity'; 7 | import { 8 | ServiceProviderConstructor as ServiceProvider, 9 | ServiceProviderMetadata, 10 | IdentityProviderMetadata, 11 | IdentityProviderSettings, 12 | } from './types'; 13 | import libsaml from './libsaml'; 14 | import { namespace } from './urn'; 15 | import postBinding from './binding-post'; 16 | import { flow, FlowResult } from './flow'; 17 | import { isString } from './utility'; 18 | import { BindingContext } from './entity'; 19 | 20 | /** 21 | * Identity prvider can be configured using either metadata importing or idpSetting 22 | */ 23 | export default function(props: IdentityProviderSettings) { 24 | return new IdentityProvider(props); 25 | } 26 | 27 | /** 28 | * Identity prvider can be configured using either metadata importing or idpSetting 29 | */ 30 | export class IdentityProvider extends Entity { 31 | 32 | entityMeta: IdentityProviderMetadata; 33 | 34 | constructor(idpSetting: IdentityProviderSettings) { 35 | const defaultIdpEntitySetting = { 36 | wantAuthnRequestsSigned: false, 37 | tagPrefix: { 38 | encryptedAssertion: 'saml', 39 | }, 40 | }; 41 | const entitySetting = Object.assign(defaultIdpEntitySetting, idpSetting); 42 | // build attribute part 43 | if (idpSetting.loginResponseTemplate) { 44 | if (isString(idpSetting.loginResponseTemplate.context) && Array.isArray(idpSetting.loginResponseTemplate.attributes)) { 45 | const replacement = { 46 | AttributeStatement: libsaml.attributeStatementBuilder(idpSetting.loginResponseTemplate.attributes), 47 | }; 48 | entitySetting.loginResponseTemplate = { 49 | ...entitySetting.loginResponseTemplate, 50 | context: libsaml.replaceTagsByValue(entitySetting.loginResponseTemplate!.context, replacement), 51 | }; 52 | } else { 53 | console.warn('Invalid login response template'); 54 | } 55 | } 56 | super(entitySetting, 'idp'); 57 | } 58 | 59 | /** 60 | * @desc Generates the login response for developers to design their own method 61 | * @param sp object of service provider 62 | * @param requestInfo corresponding request, used to obtain the id 63 | * @param binding protocol binding 64 | * @param user current logged user (e.g. req.user) 65 | * @param customTagReplacement used when developers have their own login response template 66 | * @param encryptThenSign whether or not to encrypt then sign first (if signing) 67 | */ 68 | public async createLoginResponse( 69 | sp: ServiceProvider, 70 | requestInfo: { [key: string]: any }, 71 | binding: string, 72 | user: { [key: string]: any }, 73 | customTagReplacement?: (template: string) => BindingContext, 74 | encryptThenSign?: boolean, 75 | ) { 76 | const protocol = namespace.binding[binding]; 77 | // can only support post binding for login response 78 | if (protocol === namespace.binding.post) { 79 | const context = await postBinding.base64LoginResponse(requestInfo, { 80 | idp: this, 81 | sp, 82 | }, user, customTagReplacement, encryptThenSign); 83 | return { 84 | ...context, 85 | entityEndpoint: (sp.entityMeta as ServiceProviderMetadata).getAssertionConsumerService(binding), 86 | type: 'SAMLResponse' 87 | }; 88 | } 89 | throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING'); 90 | } 91 | 92 | /** 93 | * Validation of the parsed URL parameters 94 | * @param sp ServiceProvider instance 95 | * @param binding Protocol binding 96 | * @param req RequesmessageSigningOrderst 97 | */ 98 | parseLoginRequest(sp: ServiceProvider, binding: string, req: ESamlHttpRequest) { 99 | const self = this; 100 | return flow({ 101 | from: sp, 102 | self: self, 103 | checkSignature: self.entityMeta.isWantAuthnRequestsSigned(), 104 | parserType: 'SAMLRequest', 105 | type: 'login', 106 | binding: binding, 107 | request: req 108 | }); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/entity-sp.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file entity-sp.ts 3 | * @author tngan 4 | * @desc Declares the actions taken by service provider 5 | */ 6 | import Entity, { 7 | BindingContext, 8 | PostBindingContext, 9 | ESamlHttpRequest, 10 | } from './entity'; 11 | import { 12 | IdentityProviderConstructor as IdentityProvider, 13 | ServiceProviderMetadata, 14 | ServiceProviderSettings, 15 | } from './types'; 16 | import { namespace } from './urn'; 17 | import redirectBinding from './binding-redirect'; 18 | import postBinding from './binding-post'; 19 | import { flow, FlowResult } from './flow'; 20 | 21 | /* 22 | * @desc interface function 23 | */ 24 | export default function(props: ServiceProviderSettings) { 25 | return new ServiceProvider(props); 26 | } 27 | 28 | /** 29 | * @desc Service provider can be configured using either metadata importing or spSetting 30 | * @param {object} spSettingimport { FlowResult } from '../types/src/flow.d'; 31 | 32 | */ 33 | export class ServiceProvider extends Entity { 34 | entityMeta: ServiceProviderMetadata; 35 | 36 | /** 37 | * @desc Inherited from Entity 38 | * @param {object} spSetting setting of service provider 39 | */ 40 | constructor(spSetting: ServiceProviderSettings) { 41 | const entitySetting = Object.assign({ 42 | authnRequestsSigned: false, 43 | wantAssertionsSigned: false, 44 | wantMessageSigned: false, 45 | }, spSetting); 46 | super(entitySetting, 'sp'); 47 | } 48 | 49 | /** 50 | * @desc Generates the login request for developers to design their own method 51 | * @param {IdentityProvider} idp object of identity provider 52 | * @param {string} binding protocol binding 53 | * @param {function} customTagReplacement used when developers have their own login response template 54 | */ 55 | public createLoginRequest( 56 | idp: IdentityProvider, 57 | binding = 'redirect', 58 | customTagReplacement?: (template: string) => BindingContext, 59 | ): BindingContext | PostBindingContext { 60 | const nsBinding = namespace.binding; 61 | const protocol = nsBinding[binding]; 62 | if (this.entityMeta.isAuthnRequestSigned() !== idp.entityMeta.isWantAuthnRequestsSigned()) { 63 | throw new Error('ERR_METADATA_CONFLICT_REQUEST_SIGNED_FLAG'); 64 | } 65 | 66 | if (protocol === nsBinding.redirect) { 67 | return redirectBinding.loginRequestRedirectURL({ idp, sp: this }, customTagReplacement); 68 | } 69 | 70 | if (protocol === nsBinding.post) { 71 | const context = postBinding.base64LoginRequest("/*[local-name(.)='AuthnRequest']", { idp, sp: this }, customTagReplacement); 72 | return { 73 | ...context, 74 | relayState: this.entitySetting.relayState, 75 | entityEndpoint: idp.entityMeta.getSingleSignOnService(binding) as string, 76 | type: 'SAMLRequest', 77 | }; 78 | } 79 | // Will support artifact in the next release 80 | throw new Error('ERR_SP_LOGIN_REQUEST_UNDEFINED_BINDING'); 81 | } 82 | 83 | /** 84 | * @desc Validation of the parsed the URL parameters 85 | * @param {IdentityProvider} idp object of identity provider 86 | * @param {string} binding protocol binding 87 | * @param {request} req request 88 | */ 89 | public parseLoginResponse(idp, binding, request: ESamlHttpRequest) { 90 | const self = this; 91 | return flow({ 92 | from: idp, 93 | self: self, 94 | checkSignature: true, // saml response must have signature 95 | parserType: 'SAMLResponse', 96 | type: 'login', 97 | binding: binding, 98 | request: request 99 | }); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/metadata-idp.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file metadata-idp.ts 3 | * @author tngan 4 | * @desc Metadata of identity provider 5 | */ 6 | import Metadata, { MetadataInterface } from './metadata'; 7 | import { MetadataIdpOptions, MetadataIdpConstructor } from './types'; 8 | import { namespace } from './urn'; 9 | import libsaml from './libsaml'; 10 | import { isNonEmptyArray, isString } from './utility'; 11 | import * as xml from 'xml'; 12 | 13 | export interface IdpMetadataInterface extends MetadataInterface { 14 | 15 | } 16 | 17 | /* 18 | * @desc interface function 19 | */ 20 | export default function(meta: MetadataIdpConstructor) { 21 | return new IdpMetadata(meta); 22 | } 23 | 24 | export class IdpMetadata extends Metadata { 25 | 26 | constructor(meta: MetadataIdpConstructor) { 27 | 28 | const isFile = isString(meta) || meta instanceof Buffer; 29 | 30 | if (!isFile) { 31 | 32 | const { 33 | entityID, 34 | signingCert, 35 | encryptCert, 36 | wantAuthnRequestsSigned = false, 37 | nameIDFormat = [], 38 | singleSignOnService = [], 39 | singleLogoutService = [], 40 | } = meta as MetadataIdpOptions; 41 | 42 | const IDPSSODescriptor: any[] = [{ 43 | _attr: { 44 | WantAuthnRequestsSigned: String(wantAuthnRequestsSigned), 45 | protocolSupportEnumeration: namespace.names.protocol, 46 | }, 47 | }]; 48 | 49 | if (signingCert) { 50 | IDPSSODescriptor.push(libsaml.createKeySection('signing', signingCert)); 51 | } else { 52 | //console.warn('Construct identity provider - missing signing certificate'); 53 | } 54 | 55 | if (encryptCert) { 56 | IDPSSODescriptor.push(libsaml.createKeySection('encryption', encryptCert)); 57 | } else { 58 | //console.warn('Construct identity provider - missing encrypt certificate'); 59 | } 60 | 61 | if (isNonEmptyArray(nameIDFormat)) { 62 | nameIDFormat.forEach(f => IDPSSODescriptor.push({ NameIDFormat: f })); 63 | } 64 | 65 | if (isNonEmptyArray(singleSignOnService)) { 66 | singleSignOnService.forEach((a, indexCount) => { 67 | const attr: any = { 68 | Binding: a.Binding, 69 | Location: a.Location, 70 | }; 71 | if (a.isDefault) { 72 | attr.isDefault = true; 73 | } 74 | IDPSSODescriptor.push({ SingleSignOnService: [{ _attr: attr }] }); 75 | }); 76 | } else { 77 | throw new Error('ERR_IDP_METADATA_MISSING_SINGLE_SIGN_ON_SERVICE'); 78 | } 79 | 80 | if (isNonEmptyArray(singleLogoutService)) { 81 | singleLogoutService.forEach((a, indexCount) => { 82 | const attr: any = {}; 83 | if (a.isDefault) { 84 | attr.isDefault = true; 85 | } 86 | attr.Binding = a.Binding; 87 | attr.Location = a.Location; 88 | IDPSSODescriptor.push({ SingleLogoutService: [{ _attr: attr }] }); 89 | }); 90 | } else { 91 | console.warn('Construct identity provider - missing endpoint of SingleLogoutService'); 92 | } 93 | // Create a new metadata by setting 94 | meta = xml([{ 95 | EntityDescriptor: [{ 96 | _attr: { 97 | 'xmlns': namespace.names.metadata, 98 | 'xmlns:assertion': namespace.names.assertion, 99 | 'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#', 100 | entityID, 101 | }, 102 | }, { IDPSSODescriptor }], 103 | }]); 104 | } 105 | 106 | super(meta as string | Buffer, [ 107 | { 108 | key: 'wantAuthnRequestsSigned', 109 | localPath: ['EntityDescriptor', 'IDPSSODescriptor'], 110 | attributes: ['WantAuthnRequestsSigned'], 111 | }, 112 | { 113 | key: 'singleSignOnService', 114 | localPath: ['EntityDescriptor', 'IDPSSODescriptor', 'SingleSignOnService'], 115 | index: ['Binding'], 116 | attributePath: [], 117 | attributes: ['Location'] 118 | }, 119 | ]); 120 | 121 | } 122 | 123 | /** 124 | * @desc Get the preference whether it wants a signed request 125 | * @return {boolean} WantAuthnRequestsSigned 126 | */ 127 | isWantAuthnRequestsSigned(): boolean { 128 | const was = this.meta.wantAuthnRequestsSigned; 129 | if (was === undefined) { 130 | return false; 131 | } 132 | return String(was) === 'true'; 133 | } 134 | 135 | /** 136 | * @desc Get the entity endpoint for single sign on service 137 | * @param {string} binding protocol binding (e.g. redirect, post) 138 | * @return {string/object} location 139 | */ 140 | getSingleSignOnService(binding: string): string | object { 141 | if (isString(binding)) { 142 | const bindName = namespace.binding[binding]; 143 | const service = this.meta.singleSignOnService[bindName]; 144 | if (service) { 145 | return service; 146 | } 147 | } 148 | return this.meta.singleSignOnService; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/metadata.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file metadata.ts 3 | * @author tngan 4 | * @desc An abstraction for metadata of identity provider and service provider 5 | */ 6 | import * as fs from 'fs'; 7 | import { namespace } from './urn'; 8 | import { extract } from './extractor'; 9 | import { isString } from './utility'; 10 | 11 | export interface MetadataInterface { 12 | xmlString: string; 13 | getMetadata: () => string; 14 | exportMetadata: (exportFile: string) => void; 15 | getEntityID: () => string; 16 | getX509Certificate: (certType: string) => string | string[]; 17 | getNameIDFormat: () => any[]; 18 | getSingleLogoutService: (binding: string | undefined) => string | object; 19 | getSupportBindings: (services: string[]) => string[]; 20 | } 21 | 22 | export default class Metadata implements MetadataInterface { 23 | 24 | xmlString: string; 25 | meta: any; 26 | 27 | /** 28 | * @param {string | Buffer} metadata xml 29 | * @param {object} extraParse for custom metadata extractor 30 | */ 31 | constructor(xml: string | Buffer, extraParse: any = []) { 32 | this.xmlString = xml.toString(); 33 | this.meta = extract(this.xmlString, extraParse.concat([ 34 | { 35 | key: 'entityDescriptor', 36 | localPath: ['EntityDescriptor'], 37 | attributes: [], 38 | context: true 39 | }, 40 | { 41 | key: 'entityID', 42 | localPath: ['EntityDescriptor'], 43 | attributes: ['entityID'] 44 | }, 45 | { 46 | // shared certificate for both encryption and signing 47 | key: 'sharedCertificate', 48 | localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor', 'KeyInfo', 'X509Data', 'X509Certificate'], 49 | attributes: [] 50 | }, 51 | { 52 | // explicit certificate declaration for encryption and signing 53 | key: 'certificate', 54 | localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor'], 55 | index: ['use'], 56 | attributePath: ['KeyInfo', 'X509Data', 'X509Certificate'], 57 | attributes: [] 58 | }, 59 | { 60 | key: 'singleLogoutService', 61 | localPath: ['EntityDescriptor', '~SSODescriptor', 'SingleLogoutService'], 62 | attributes: ['Binding', 'Location'] 63 | }, 64 | { 65 | key: 'nameIDFormat', 66 | localPath: ['EntityDescriptor', '~SSODescriptor', 'NameIDFormat'], 67 | attributes: [], 68 | } 69 | ])); 70 | 71 | // get shared certificate 72 | const sharedCertificate = this.meta.sharedCertificate; 73 | if (typeof sharedCertificate === 'string') { 74 | this.meta.certificate = { 75 | signing: sharedCertificate, 76 | encryption: sharedCertificate 77 | }; 78 | delete this.meta.sharedCertificate; 79 | } 80 | 81 | if ( 82 | Array.isArray(this.meta.entityDescriptor) && 83 | this.meta.entityDescriptor.length > 1 84 | ) { 85 | throw new Error('ERR_MULTIPLE_METADATA_ENTITYDESCRIPTOR'); 86 | } 87 | 88 | } 89 | 90 | /** 91 | * @desc Get the metadata in xml format 92 | * @return {string} metadata in xml format 93 | */ 94 | public getMetadata(): string { 95 | return this.xmlString; 96 | } 97 | 98 | /** 99 | * @desc Export the metadata to specific file 100 | * @param {string} exportFile is the output file path 101 | */ 102 | public exportMetadata(exportFile: string): void { 103 | fs.writeFileSync(exportFile, this.xmlString); 104 | } 105 | 106 | /** 107 | * @desc Get the entityID in metadata 108 | * @return {string} entityID 109 | */ 110 | public getEntityID(): string { 111 | return this.meta.entityID; 112 | } 113 | 114 | /** 115 | * @desc Get the x509 certificate declared in entity metadata 116 | * @param {string} use declares the type of certificate 117 | * @return {string} certificate in string format 118 | */ 119 | public getX509Certificate(use: string): string | string[] { 120 | return this.meta.certificate[use] || null; 121 | } 122 | 123 | /** 124 | * @desc Get the support NameID format declared in entity metadata 125 | * @return {array} support NameID format 126 | */ 127 | public getNameIDFormat(): any { 128 | return this.meta.nameIDFormat; 129 | } 130 | 131 | /** 132 | * @desc Get the entity endpoint for single logout service 133 | * @param {string} binding e.g. redirect, post 134 | * @return {string/object} location 135 | */ 136 | public getSingleLogoutService(binding: string | undefined): string | object { 137 | if (binding && isString(binding)) { 138 | const bindType = namespace.binding[binding]; 139 | let singleLogoutService = this.meta.singleLogoutService; 140 | if (!(singleLogoutService instanceof Array)) { 141 | singleLogoutService = [singleLogoutService]; 142 | } 143 | const service = singleLogoutService.find(obj => obj.binding === bindType); 144 | if (service) { 145 | return service.location; 146 | } 147 | } 148 | return this.meta.singleLogoutService; 149 | } 150 | 151 | /** 152 | * @desc Get the support bindings 153 | * @param {[string]} services 154 | * @return {[string]} support bindings 155 | */ 156 | public getSupportBindings(services: string[]): string[] { 157 | let supportBindings = []; 158 | if (services) { 159 | supportBindings = services.reduce((acc: any, service) => { 160 | const supportBinding = Object.keys(service)[0]; 161 | return acc.push(supportBinding); 162 | }, []); 163 | } 164 | return supportBindings; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { LoginResponseTemplate } from './libsaml'; 2 | 3 | export { IdentityProvider as IdentityProviderConstructor } from './entity-idp'; 4 | export { IdpMetadata as IdentityProviderMetadata } from './metadata-idp'; 5 | 6 | export { ServiceProvider as ServiceProviderConstructor } from './entity-sp'; 7 | export { SpMetadata as ServiceProviderMetadata } from './metadata-sp'; 8 | 9 | export type MetadataFile = string | Buffer; 10 | 11 | type SSOService = { 12 | isDefault?: boolean; 13 | Binding: string; 14 | Location: string; 15 | }; 16 | 17 | export interface MetadataIdpOptions { 18 | entityID?: string; 19 | signingCert?: string | Buffer; 20 | encryptCert?: string | Buffer; 21 | wantAuthnRequestsSigned?: boolean; 22 | nameIDFormat?: string[]; 23 | singleSignOnService?: SSOService[]; 24 | singleLogoutService?: SSOService[]; 25 | requestSignatureAlgorithm?: string; 26 | } 27 | 28 | export type MetadataIdpConstructor = 29 | | MetadataIdpOptions 30 | | MetadataFile; 31 | 32 | export interface MetadataSpOptions { 33 | entityID?: string; 34 | signingCert?: string | Buffer; 35 | encryptCert?: string | Buffer; 36 | authnRequestsSigned?: boolean; 37 | wantAssertionsSigned?: boolean; 38 | wantMessageSigned?: boolean; 39 | signatureConfig?: { [key: string]: any }; 40 | nameIDFormat?: string[]; 41 | singleSignOnService?: SSOService[]; 42 | singleLogoutService?: SSOService[]; 43 | assertionConsumerService?: SSOService[]; 44 | elementsOrder?: string[]; 45 | } 46 | 47 | export type MetadataSpConstructor = 48 | | MetadataSpOptions 49 | | MetadataFile; 50 | 51 | export type EntitySetting = ServiceProviderSettings & IdentityProviderSettings; 52 | 53 | export interface SignatureConfig { 54 | prefix?: string; 55 | location?: { 56 | reference?: string; 57 | action?: 'append' | 'prepend' | 'before' | 'after'; 58 | }; 59 | } 60 | 61 | export interface SAMLDocumentTemplate { 62 | context?: string; 63 | } 64 | 65 | export type ServiceProviderSettings = { 66 | metadata?: string | Buffer; 67 | entityID?: string; 68 | authnRequestsSigned?: boolean; 69 | wantAssertionsSigned?: boolean; 70 | wantMessageSigned?: boolean; 71 | wantLogoutResponseSigned?: boolean; 72 | wantLogoutRequestSigned?: boolean; 73 | privateKey?: string | Buffer; 74 | privateKeyPass?: string; 75 | isAssertionEncrypted?: boolean; 76 | requestSignatureAlgorithm?: string; 77 | encPrivateKey?: string | Buffer; 78 | encPrivateKeyPass?: string | Buffer; 79 | assertionConsumerService?: SSOService[]; 80 | singleLogoutService?: SSOService[]; 81 | signatureConfig?: SignatureConfig; 82 | loginRequestTemplate?: SAMLDocumentTemplate; 83 | logoutRequestTemplate?: SAMLDocumentTemplate; 84 | signingCert?: string | Buffer; 85 | encryptCert?: string | Buffer; 86 | transformationAlgorithms?: string[]; 87 | nameIDFormat?: string[]; 88 | allowCreate?: boolean; 89 | // will be deprecated soon 90 | relayState?: string; 91 | // https://github.com/tngan/samlify/issues/337 92 | clockDrifts?: [number, number]; 93 | }; 94 | 95 | export type IdentityProviderSettings = { 96 | metadata?: string | Buffer; 97 | 98 | /** signature algorithm */ 99 | requestSignatureAlgorithm?: string; 100 | 101 | /** template of login response */ 102 | loginResponseTemplate?: LoginResponseTemplate; 103 | 104 | /** template of logout request */ 105 | logoutRequestTemplate?: SAMLDocumentTemplate; 106 | 107 | /** customized function used for generating request ID */ 108 | generateID?: () => string; 109 | 110 | entityID?: string; 111 | privateKey?: string | Buffer; 112 | privateKeyPass?: string; 113 | signingCert?: string | Buffer; 114 | encryptCert?: string | Buffer; /** todo */ 115 | nameIDFormat?: string[]; 116 | singleSignOnService?: SSOService[]; 117 | singleLogoutService?: SSOService[]; 118 | isAssertionEncrypted?: boolean; 119 | encPrivateKey?: string | Buffer; 120 | encPrivateKeyPass?: string; 121 | messageSigningOrder?: string; 122 | wantLogoutRequestSigned?: boolean; 123 | wantLogoutResponseSigned?: boolean; 124 | wantAuthnRequestsSigned?: boolean; 125 | wantLogoutRequestSignedResponseSigned?: boolean; 126 | tagPrefix?: { [key: string]: string }; 127 | }; 128 | -------------------------------------------------------------------------------- /src/validator.ts: -------------------------------------------------------------------------------- 1 | // unit is ms 2 | type DriftTolerance = [number, number]; 3 | 4 | function verifyTime( 5 | utcNotBefore: string | undefined, 6 | utcNotOnOrAfter: string | undefined, 7 | drift: DriftTolerance = [0, 0] 8 | ): boolean { 9 | 10 | const now = new Date(); 11 | 12 | if (!utcNotBefore && !utcNotOnOrAfter) { 13 | // show warning because user intends to have time check but the document doesn't include corresponding information 14 | console.warn('You intend to have time validation however the document doesn\'t include the valid range.'); 15 | return true; 16 | } 17 | 18 | let notBeforeLocal: Date | null = null; 19 | let notOnOrAfterLocal: Date | null = null; 20 | 21 | const [notBeforeDrift, notOnOrAfterDrift] = drift; 22 | 23 | if (utcNotBefore && !utcNotOnOrAfter) { 24 | notBeforeLocal = new Date(utcNotBefore); 25 | return +notBeforeLocal + notBeforeDrift <= +now; 26 | } 27 | if (!utcNotBefore && utcNotOnOrAfter) { 28 | notOnOrAfterLocal = new Date(utcNotOnOrAfter); 29 | return +now < +notOnOrAfterLocal + notOnOrAfterDrift; 30 | } 31 | 32 | notBeforeLocal = new Date(utcNotBefore!); 33 | notOnOrAfterLocal = new Date(utcNotOnOrAfter!); 34 | 35 | return ( 36 | +notBeforeLocal + notBeforeDrift <= +now && 37 | +now < +notOnOrAfterLocal + notOnOrAfterDrift 38 | ); 39 | 40 | } 41 | 42 | export { 43 | verifyTime 44 | }; -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | ## Standalone code for running directly with Node.js REPL 2 | 3 | ```javascript 4 | // playground setup for extractor 5 | var samlify = require('./build/index'); 6 | var fs = require('fs'); 7 | var idpconfig = { 8 | privateKey: fs.readFileSync('./test/key/idp/privkey.pem'), 9 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 10 | isAssertionEncrypted: false, 11 | metadata: fs.readFileSync('./test/misc/idpmeta_rollingcert.xml') 12 | }; 13 | var idp = samlify.IdentityProvider(idpconfig); 14 | 15 | samlify.Extractor.extract(idp.entityMeta.xmlString, [ 16 | { 17 | key: 'certificate', 18 | localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor'], 19 | index: ['use'], 20 | attributePath: ['KeyInfo', 'X509Data', 'X509Certificate'], 21 | attributes: [] 22 | } 23 | ]) 24 | 25 | // construct response signature 26 | const { 27 | IdPMetadata: idpMetadata, 28 | Utility: utility, 29 | SamlLib: libsaml, 30 | } = require('./'); 31 | const fs = require('fs'); 32 | const metadata = idpMetadata(fs.readFileSync('./test/misc/idpmeta_rollingcert.xml')); 33 | const _idpKeyFolder = './test/key/idp/'; 34 | const _idpPrivPem1 = String(fs.readFileSync(_idpKeyFolder + 'privkey.pem')); 35 | const _idpPrivPem2 = String(fs.readFileSync(_idpKeyFolder + 'privkey2.pem')); 36 | function writer(str) { 37 | fs.writeFileSync('nogit.xml', str); 38 | } 39 | writer(utility.base64Decode(libsaml.constructSAMLSignature({ 40 | rawSamlMessage: String(fs.readFileSync('./test/misc/response.xml')), 41 | referenceTagXPath: libsaml.createXPath('Issuer'), 42 | signingCert: metadata.getX509Certificate('signing')[0], 43 | privateKey: _idpPrivPem1, 44 | privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW', 45 | signatureAlgorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 46 | signatureConfig: { 47 | prefix: 'ds', 48 | location: { reference: "/*[local-name(.)='Response']/*[local-name(.)='Issuer']", action: 'after' }, 49 | }, 50 | }))); 51 | ``` -------------------------------------------------------------------------------- /test/extractor.ts: -------------------------------------------------------------------------------- 1 | // This test file includes all the units related to the extractor 2 | import test from 'ava'; 3 | import { readFileSync } from 'fs'; 4 | import { extract } from '../src/extractor'; 5 | 6 | const _decodedResponse: string = String(readFileSync('./test/misc/response_signed.xml')); 7 | const _spmeta: string = String(readFileSync('./test/misc/spmeta.xml')); 8 | 9 | (() => { 10 | 11 | test('fetch multiple attributes', t => { 12 | const result = extract(_decodedResponse, [ 13 | { 14 | key: 'response', 15 | localPath: ['Response'], 16 | attributes: ['ID', 'Destination'] 17 | } 18 | ]); 19 | t.is(result.response.id, '_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6'); 20 | t.is(result.response.destination, 'http://sp.example.com/demo1/index.php?acs'); 21 | }); 22 | 23 | test('fetch single attributes', t => { 24 | const result = extract(_decodedResponse, [ 25 | { 26 | key: 'statusCode', 27 | localPath: ['Response', 'Status', 'StatusCode'], 28 | attributes: ['Value'], 29 | } 30 | ]); 31 | t.is(result.statusCode, 'urn:oasis:names:tc:SAML:2.0:status:Success'); 32 | }); 33 | 34 | test('fetch the inner context of leaf node', t => { 35 | const result = extract(_decodedResponse, [ 36 | { 37 | key: 'audience', 38 | localPath: ['Response', 'Assertion', 'Conditions', 'AudienceRestriction', 'Audience'], 39 | attributes: [] 40 | } 41 | ]); 42 | t.is(result.audience, 'https://sp.example.com/metadata'); 43 | }); 44 | 45 | test('fetch the entire context of a non-existing node ', t => { 46 | const result = extract(_decodedResponse, [ 47 | { 48 | key: 'assertionSignature', 49 | localPath: ['Response', 'Assertion', 'Signature'], 50 | attributes: [], 51 | context: true 52 | } 53 | ]); 54 | t.is(result.assertionSignature, null); 55 | }); 56 | 57 | test('fetch the entire context of an existed node', t => { 58 | const result = extract(_decodedResponse, [ 59 | { 60 | key: 'messageSignature', 61 | localPath: ['Response', 'Signature'], 62 | attributes: [], 63 | context: true 64 | } 65 | ]); 66 | t.not(result.messageSignature, null); 67 | }); 68 | 69 | test('fetch the unique inner context of multiple nodes', t => { 70 | const result = extract(_decodedResponse, [ 71 | { 72 | key: 'issuer', 73 | localPath: [ 74 | ['Response', 'Issuer'], 75 | ['Response', 'Assertion', 'Issuer'] 76 | ], 77 | attributes: [] 78 | } 79 | ]); 80 | t.is(result.issuer.length, 1); 81 | t.is(result.issuer.every(i => i === 'https://idp.example.com/metadata'), true); 82 | }); 83 | 84 | test('fetch the attribute with wildcard local path', t => { 85 | const result = extract(_spmeta, [ 86 | { 87 | key: 'certificate', 88 | localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor'], 89 | index: ['use'], 90 | attributePath: ['KeyInfo', 'X509Data', 'X509Certificate'], 91 | attributes: [] 92 | } 93 | ]); 94 | t.not(result.certificate.signing, null); 95 | t.not(result.certificate.encryption, null); 96 | }); 97 | 98 | test('fetch the attribute with non-wildcard local path', t => { 99 | const result = extract(_decodedResponse, [ 100 | { 101 | key: 'attributes', 102 | localPath: ['Response', 'Assertion', 'AttributeStatement', 'Attribute'], 103 | index: ['Name'], 104 | attributePath: ['AttributeValue'], 105 | attributes: [] 106 | } 107 | ]); 108 | t.is(result.attributes.uid, 'test'); 109 | t.is(result.attributes.mail, 'test@example.com'); 110 | t.is(result.attributes.eduPersonAffiliation.length, 2); 111 | }); 112 | 113 | test('fetch with one attribute as key, another as value', t => { 114 | const result = extract(_spmeta, [ 115 | { 116 | key: 'singleSignOnService', 117 | localPath: ['EntityDescriptor', '~SSODescriptor', 'AssertionConsumerService'], 118 | index: ['Binding'], 119 | attributePath: [], 120 | attributes: ['Location'] 121 | } 122 | ]); 123 | const postEndpoint = result.singleSignOnService['urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST']; 124 | const artifactEndpoint = result.singleSignOnService['urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact']; 125 | 126 | t.is(postEndpoint, 'https://sp.example.org/sp/sso'); 127 | t.is(artifactEndpoint, 'https://sp.example.org/sp/sso'); 128 | }); 129 | 130 | })(); 131 | -------------------------------------------------------------------------------- /test/key/idp/README.md: -------------------------------------------------------------------------------- 1 | ## Support the use case of rolling certificate 2 | 3 | * `privkey1.pem` - password protected `q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW`, it generates `cert.cer` 4 | * `privkey2.pem` - no password protected, it generates `cert2.cer` -------------------------------------------------------------------------------- /test/key/idp/cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV 3 | BAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQ 4 | cm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0x 5 | NTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYD 6 | VQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIG 7 | A1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEB 8 | BQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG 9 | 3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZU 10 | tWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3 11 | pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRA 12 | vr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsb 13 | VUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0O 14 | BBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwd 15 | wK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPN 16 | mHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUw 17 | i1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef 18 | 2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0a 19 | zkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWW 20 | k1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4 21 | yyoWAJDUHiAmvFA= 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /test/key/idp/cert2.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFLjCCAxYCCQCqGHhTssya9jANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJI 3 | SzESMBAGA1UECAwJSG9uZyBLb25nMRIwEAYDVQQHDAlIb25nIEtvbmcxEDAOBgNV 4 | BAoMB3NhbWxpZnkxEDAOBgNVBAMMB3NhbWxpZnkwHhcNMjAwNTEwMTUyNjIzWhcN 5 | MzAwNTA4MTUyNjIzWjBZMQswCQYDVQQGEwJISzESMBAGA1UECAwJSG9uZyBLb25n 6 | MRIwEAYDVQQHDAlIb25nIEtvbmcxEDAOBgNVBAoMB3NhbWxpZnkxEDAOBgNVBAMM 7 | B3NhbWxpZnkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQG+abAeeW 8 | jwsOZt5SkcNcw/XSJcjSyJykEbEU2iguErRuOIyBfgj0p1UVBv33uL2igeYJT3OS 9 | XmSjvMO8KvqtYN2tJAjoFjghGr8NbIEZjYS4ukMZUbwxd2bRycD9OMI9g44AUB1s 10 | fQ0UyFwzEOseW3lcW1FnhcizA8TgI0GN4NpdVruNlpgoWdP3w+Syhtq0rWebY8g/ 11 | HGFruEKn8VwbUblOZdP7jNVXsd1aUMScpuMa0khzzXPDN+Q0rwl79fO4ychSeKAA 12 | ERdPXA1UfDfbh9W7pcYBP0ABXd91Bf9akplmbbVOIsNbuRIcVS7WvLwCr613JuJ+ 13 | EtGDcUkrSpbuRvDW85DQRHBGuoKlcSG+imHQtHqRwMwMc8P54hIEBvaFW0RfwPfz 14 | dFNe8wARtmvIeX84iwq5Yey15Ly1rdopi7t2g7qyF7C/B9gZ3tJ/gPKp2NrdCGFB 15 | cahl93Lj56WWmI0jNHn7+7Y3x6isJ3KTRXIliSrAwiK7/7UezOlWzs1k8mGQWZTD 16 | 3AGGKu1cBVwuC+rh4wkLsDeHfzxavbXxVEok9p/1P28M4GiHfS0POE3Hl4RT3Q6A 17 | iYWnmFYyZ+smY97SgPwB4tTNYFjC6+9d/BllNoQb8wsPjqp6ZDn1OeY668hp+ZAc 18 | E13AFdiTBMVrcdEECCPLxg1kFk5wZdHrGwIDAQABMA0GCSqGSIb3DQEBCwUAA4IC 19 | AQCyA/14hKTqfdeOVl+MQ2SLPWi7pC/t/Zv4kc361xP26FAVSSrxgXq9kVLZeJIA 20 | qCwjGHkl/DTUlA8hfLfuZx5z+NI/qIodsXAjCzsCe7paEbjvR6OQjYkR0UY4u/AO 21 | O7x2op2KDFKNuWT9KZNm8bh1mxwNKep1fJP2O5M0nMYAGYbPsLAOn7mzZyufQl8h 22 | sJwIV2s8sbft7s8vmEYZbuueQDOJCMTt+eC08LONrovYChyYmj3i5RIk8kcaodeS 23 | Do811F1B1gDvO/dmVxgrHEgoai7X6LUoiAiLkigP7udNEZxbXsRlOhBRv9w+rRXF 24 | urVFlUPkQ9UF+QB0BoyIcUxo+fZ8vCA4xEVBenVBadpFbwum6+XeTkvDoRc4sSCp 25 | m8v2qtprc8aU/0F82EzxSybYvstc5lDv7wuwCwNwfoAQ+/16kTpJvoYbOXUPv5yC 26 | A3mIuqYeA1woaWPXsE4jNOzTqv1qOZQTvXProEgK5B0FR5ILc4mfNrD2p9VGbiYf 27 | 2GjCfeEzDFg174dvSn2MMp1yK5pvZEp7yFE8z1eduYN6W/7qdtss9BGpnyS5X7Lu 28 | YfDvd1dHP6/JuqJDbfSVG9prYWcaMRd3FzSC7jBeetJgMyj4dunfqw8R16aONhwv 29 | ICtzdFa93hYrDvTyo3ae80KFi0WGgApKeoqO5t3l1PAcaA== 30 | -----END CERTIFICATE----- 31 | -------------------------------------------------------------------------------- /test/key/idp/encryptKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: DES-EDE3-CBC,FACBF89A697AB50A 4 | 5 | i0RiFM9TTHzN/atuOBWhAfoty7rMEgNVVsyeoAPqQZoGwBTmOSbMZ+3vLR3jc7Xi 6 | GJ4NtXOux2IcNy5rcYnL3SgZIANVakfEUwF6qwBLCGYbOaqWqEv4eHvz9JHIH9iC 7 | 0w4PPMzA2Q4daWiRw1UGr4Kik2iqfkDGv4JPdUDY7/KNlD4hpthRk6axUg+XbJat 8 | swCijv0NGrU//MRGCpqnt4q5ApoZ5Yg4jIbc9JG95ZoZ9+eVZJa1l9ZyYyw6bJ6+ 9 | 0iinwWC59qX4soWzvBPvXMzJpgSPAtDrhNKMU4mLPD6+1fLVsc5POzjAuGqDRNcV 10 | bJb/nftu3/MNasXI0PI37RM5krOitBfona8YD4T3B5fIa80XBUrPfSpFXqOqCHZQ 11 | H4rHbnletX8mnAAlzBIEzELO5Dspwnd9OvEkHsKdN5BSZ8cKJh6/qIHwejn4DP21 12 | hvFAkUYrZWpNZsCi7CKZTJBYkwogW7u0u7ki3XiyPxeDJaYSyTxcdiZD2eVmsWdh 13 | wOWU7mfprfcYIJJnslyJ104z5C0Ioj2xp7VHcX4It8DrwzizfPHkvasv9JarILIX 14 | yeST80i7mcxFyAwmuKIVdD+vvNhZeu0OYs15uhcoKH/oIz2dBLk5U+d/hVwV6TlX 15 | v41nDLuXfvqjAh83rz+a+QkjEdtaMDXKkM3ob6u13F+7JZPQ/32VMeiu0hMWwFff 16 | nijXoWZ+gv3hxbI2oy3Gc2Kjj4H8sYBx/Jd+LTtEZzH01wq0oR/2BR2r74ErB2lF 17 | ByD9d9/SJ/+WrIuseJTcLIWARP5t0QDe8NAWEY5KPk6YjvB84jHIAHf+K+fQMKJL 18 | n6ehvRlVZo4a4cP9PPGMEupfSHCNjioRzT92/AAc3+vplZghMd8lNOpCKSs2NlYX 19 | rf1gKanBPwjcH034SbiP3gN8r4j0Pep6RIWBra2FGZtZcNUhLSXZG87Lmf4RGnsJ 20 | TRwbCUPAx21vhkoQPg5/sLh9IQ+7nzCZfs82ke/yXVNNW7KIxchQ8mz54Ji/k2ix 21 | l0q3jRgH3u8LGPOyLwl1h2fusfZjKYZQnjTZw69Xv8kz1dt5iigNlSspwoMm9NI1 22 | Hj2TEXQJuBi2/Z+J+aDnY8HLPTM1VtXpuJiPmbxcS0kAJIveg9HQDAei26i+l5OM 23 | b4tXGjGCH/HYJxNIFWtAkrRJZjwrKmVF/GWESGvOtpEsm5YiuC5pUt7+fs6eZ+F+ 24 | nzUV2d/2EkA3FKEjAvoQb6QICCFE0SRUGutYYuUZm4AYG3JEeI4JGYpE1h9pGXMz 25 | m1hlV8N9EIJiFdEtGifjAcfHSVHm7m4us5qOG0TiVfSDC3RZCJSxm8pAUJXLaemp 26 | BvoHL8MuJX8bNMMB3JpWW3e3HxrmR8nLk+xZiviggfWBVRxM9YAyb6NPezVFAV0H 27 | YTULqiXGZbpe+Bm6MmJ6LryicIf8E3pyGbQEYtO9iLYfXnJDHud4dKZnXqjo68oc 28 | 80EeEm149eVGtYFRiWhjnRGyb6Hdql4u5iLZdaBRIm3Jm0qsHioYBi6SH5ucPM+q 29 | 8hSEfoIZiRlSsrjzvko+19lM4/JnHpk/7cihRNpgXBQysGLwSSA626cvgjwEJSJB 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /test/key/idp/encryptionCert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID6TCCAtGgAwIBAgIJAPQQPsolUypeMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV 3 | BAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2Ft 4 | bDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDAeFw0xNTEwMDMwMzU3MzRa 5 | Fw0xODEwMDIwMzU3MzRaMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv 6 | bmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQD 7 | EwVlc2FtbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7dF1gUNu8e 8 | n0fHMSbzf192uB8m2CTeHeEeYrmq5rau6t1WzaHwbSStd9tJ/11Arm8f8zfefFqE 9 | BA0EYbp/DMqHb9ZiLGgIff08679NOYeK/d9EAs5DzvTMTR6QqG7a4vH3jKOksIbj 10 | M35h5RVitVDxo+xWDKyvOpuNE64bJlWHOEiNxvwmcHfJ2hAd1EozaRLcJOojFHg5 11 | 1alUqiNIZ+vpkMAM8s3lUlcYETKqTpcnsE7c1QX60cCrFN4m3SNS98HGBEdotch8 12 | +2Myzz957cBiwg9CR05PtEfjH0gGXJbL56JmpPyY+TkEiNMtMqJ7RNkK92gZfoY2 13 | i3RdjLKOHDUCAwEAAaOBuTCBtjAdBgNVHQ4EFgQUm4zK2qBtDMICekupt3LnRBdb 14 | P9UwgYYGA1UdIwR/MH2AFJuMytqgbQzCAnpLqbdy50QXWz/VoVqkWDBWMQswCQYD 15 | VQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRUwEwYDVQQKEwxleHByZXNzLXNh 16 | bWwxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWyCCQD0ED7KJVMqXjAMBgNV 17 | HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9t7VMtX93yIYIGFC20GCsMYZe 18 | ZpTedxpxpjqom2dOuOUaDQgrZcGF3FVbFqTEpPtOnsKXYaCg7FJvUjxv7FIuix5H 19 | 7JO6DALoJ792pfG2wwS2PvDiGFxMfGnNvb3aLnB/s6wTyWBpDYRdwlB5nj37KPk6 20 | kpFJj3N9x5BD1oTdmQqeVuacjoiemIulkc33P28tGl6Datth4WpE0LwmrwREQ1NW 21 | ixi2j1Ti3mjYkyqGVY8XphWKEIIWmheqLnYCXRXhbxZ4E+FGg81ZYG8TKYC/IjzV 22 | 8p0rLnAI1qS7wdwv5UJ9vQJt6KcxdHHZsUlpIfaJC6N5DvAL/qUY8DoIymgz 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /test/key/idp/nocrypt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA4NmxaEJ77IbQ9qVA9NSgPvKSjkxNYwJHEnyFKbaTuYbcSD9j 3 | a/QQF0KZPDuIMJ69GpSZuYWersxE7JXh6uInOHQppsB1l/v+TqSiCGy3dlS1Y7DO 4 | yHLGQG1YPAaYGlAZMawrEnwzWOzdpKo1FcFPg4FYz3DYaW3X7y3LfRGFi/elIX78 5 | ccsfsBz68tIgCWiRoVbfhFZNwn/ysAO5FaVeKHgZ+ci7Rb+dybmdNJomJEC+vd0Y 6 | NE7+SGJegl1ts6Pt0c9QvFUZsf0hs8rvpMLAtsXuKQgyw+i9VtOunIvq+xtVQp4S 7 | X/kYqmlPCn0MsA56hJikJiSQORgq71NFCMXTYwIDAQABAoIBADOGbzr/ETrQYg5D 8 | LDFukBIcsCzfm1Q272ZzFmjKp+t51fzQWc4hLZbG8ip1Ue4iUh9HMjrrPcO8l4bH 9 | ie+zR12OcQT/UXM0kcAfxem8UAZTvwVLPPd+JaQZ6oBG2pAdDsjtNSmVQIb+MIRN 10 | ZMDJfZkbCOjwaQcv3q22hszwOPQrq5nW82ScuZ8k9oAyz5igomGX0jQBkQM8KMzm 11 | cXTJXBVCc/wEjHEjV8Gx1hBaDuIqY0rt6/5R4zLtwgSvT5LvUOIlzFMKACs7RFA2 12 | pkhfUx786IRbDXnGRPIqlJgYglcQjEh/815jTdsjJ6VDBBtYcEiF4vn0eWl9tp4S 13 | NxzwWoECgYEA/BG+bAMnMuvjtlOnrZF7l7mCMmKvQzhPr8+8zPtuiQKgn0vHtw4z 14 | 7u0TcaP35sa7WwZjcwUtSX4Vs1VrlBfNaHUAEgJ6PAxVPMIB537ttxbPER1l4vE8 15 | ZvGRGYsps+VNfu7XJnaFtq81mbpGsr1qRmaN+OjDs51UbkKd5esPDCECgYEA5FtK 16 | ps3kfe8rkaacFKfbD3tyj9CeZf8A1ovgiWJFi7PCY46Yg+66Vx/aKkzj2rh993Nn 17 | 74BgPWszDJHwG15sHyDlxaZHxUAAeWRJClirsS8MuaLOooReA9D3U82w/s5MDviT 18 | aP3CIc/RtpoLk31arCyqF/aT6K2B79EjmzOKzwMCgYEAjpY68T6XXeax2OFZaIVz 19 | NFBrpbTND2k7KmiIlCtmS3qBAZsMTjBqkCzrYs0t3g1szgC/IME87OW1wMwBHrSY 20 | LQ6CC637Fxyi2suj6B+UuIzedP/8MnPjhxf+zEQ8QtbjD3prmgZRfRV/bIZCl7kt 21 | 9MTuam7AxUmqCPUF/JkK2gECgYEA4Y8DF+w7i+EYag/mD8kVah+Hs2Jfc2QEkecs 22 | bMdy5mEy21/Yakj+Kly+BBZa4oplcmy99yYY6dHfZMUqI/6KUd0O2MI8Fiv3y/Aw 23 | 7VVUkfllWl/kN0cEDkT0aAS+lZF0Mz15bbVpcjhybymN0at6SqL7iBv5UVVBCX7M 24 | 6tpoe70CgYEA5TAEHT77eF8falYD7nYKnPUinfx2p6a3J0UAWI33W3CE6K4MTMSN 25 | Q2AxLj1ImFrmDMiPIFa9GeP9DrE/6eeKVI4q0u7kF58XkCammgIJ9GzyCBWfNpVR 26 | rR2ZD+OyCGiqsrL4PqtHxTwRiYymLOuVKvXxZYlDDPN/RlkBINUX0qk= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/key/idp/privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: DES-EDE3-CBC,116B0EBB2F2F0A9D 4 | 5 | HMmUsJPVPTsq1e06yrrskfinY21OOHosfRzibLueBg9ByFFZ7+/oW/DKy1GcDeBc 6 | ycL+3gylIoGUYuZ+DPC11ArjdxFqLFnHJb96rwy5h4sTP0lE+qHy+06AwsowUgp3 7 | pdD2unPFeydpu5h/dqgoDzkGSucz0Ty/spHXNBvns0vJO18B7XlzXUtfH5aHco22 8 | DyVY6FrJwMts9E4Rzs9JsxJJ7mi/6+Qsc0rOr8/6KKsRo1sKD6cvQIQ05dEvGrE9 9 | /2fubHkRTl+zBqOVyQvC6iUtocwxlMP4KfmyYrD1wlQAnP/+smq2G+xf7uGc4X4P 10 | 8q0jEy2P9n5ASlwZ3XCS9hZgp8VRAcXWOYjzzNouQp3NEP9d5D3wN4aFKa/JW6pk 11 | a6VwraEweuyJqvZ7nnam1emW0ge0z7hJabR0+j0PnUxFIwkI5jO3HI5UiuUzuQFe 12 | 2bTLA3XnJ7QD08ZKom0rmApbFrmm9BWBRTmt46NlQDy49VODPY4gFuQ/mpaFjaBy 13 | fSNJaOSS/MDuAdPabNEh3l+yCGKtHIbPVIms76PxYf6o0VVxW96/Q25hrvyOJCxn 14 | dVQyyJbQ1jGenu4ViDNrW9ZQfw4aJCPpY7lUQd09BGz2NMKgkrSl8bKSan4lvlF3 15 | ok8BjfIw+pIrTyesPU5tF0YudDxwi8fbIG70iwrpsSt2wVIMa+Nz2lwFT1dV8be7 16 | NARkkkhLWJYAsxsyVfdl+ucNSqhvo8xLITuG8CZnzKf0T2HMKnMNegFx/ipfM7ff 17 | Mx5CjayN5Oy99MWsagYEutUGzCGPAuVpqYpJuuYa3lWbFk2XWihWkAiUwgRqIluE 18 | M6LpO8l3LVXVjN1+6bK1GZpbfLay+E6vy4W38XMuXZSNpyhy6e+XggTPH2xbbwoi 19 | OcAzcojhMaxVGpxm/aXyRxg9zBdrQjtqM/aCN91ri55bvOKxELVi+D/VcZKpd2CR 20 | X/vWcqoGaK/6+vlPWMZSHCJkPa4KBT0aUcnEdeFWx2nmrwdrHvETzCYLAzVBSECV 21 | ZoYH0xTkFr/RI2AOAzx701LSuYbnPoCq+w7TXtjPaooZdYVVgrYuI+j4JOlseFS7 22 | 1c9iRiJVPBfnpUNIZdHLw19+k81IJ/FmumiuDhfLS5pwQmtuXkO3DWZDa3UPlV8e 23 | 6dmZeP1XGwRLL9VpOKx7NCqZM+CdEt87CXpFFWXdw8tL+3K/2r8w4lHIzBKaVPSS 24 | 5uFqXc1vzfP6Qeov31IjeLPE1pWTHNqRPdmvt9Scq9tKS3o18wmLBxOVinOE0cxQ 25 | oddzPd0z5NxNYVayqZORwDdVv6CVXKnrvBSnOFFslZqv1G8/diE5BXxeaAPEMcZE 26 | 3lD7MzdoEHK5oL2MXofLWZbNtMkOZLaLqY80zKT1UG3Gs8U44d44aLXO1dBL0HGX 27 | dNfNUaH+IGZf2ccS6OR1RhwIazDZ8qk0XeUwQV588adwC3FUvscVA3eHZa95z4kX 28 | xvHg+ylzRtKRfpSPzB2IVwgV9/rsOg0OmvwhV8+5IQpdcFr+hf2Bn6AVn6H9aX8A 29 | JjycN6KMcHaFa0EUqagGm9tsQLmf/MGCj8sy9am1IbRmFCz5lB5A7P/YLPM2Csjg 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /test/key/idp/privkey2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKQIBAAKCAgEA0BvmmwHnlo8LDmbeUpHDXMP10iXI0sicpBGxFNooLhK0bjiM 3 | gX4I9KdVFQb997i9ooHmCU9zkl5ko7zDvCr6rWDdrSQI6BY4IRq/DWyBGY2EuLpD 4 | GVG8MXdm0cnA/TjCPYOOAFAdbH0NFMhcMxDrHlt5XFtRZ4XIswPE4CNBjeDaXVa7 5 | jZaYKFnT98PksobatK1nm2PIPxxha7hCp/FcG1G5TmXT+4zVV7HdWlDEnKbjGtJI 6 | c81zwzfkNK8Je/XzuMnIUnigABEXT1wNVHw324fVu6XGAT9AAV3fdQX/WpKZZm21 7 | TiLDW7kSHFUu1ry8Aq+tdybifhLRg3FJK0qW7kbw1vOQ0ERwRrqCpXEhvoph0LR6 8 | kcDMDHPD+eISBAb2hVtEX8D383RTXvMAEbZryHl/OIsKuWHsteS8ta3aKYu7doO6 9 | shewvwfYGd7Sf4Dyqdja3QhhQXGoZfdy4+ellpiNIzR5+/u2N8eorCdyk0VyJYkq 10 | wMIiu/+1HszpVs7NZPJhkFmUw9wBhirtXAVcLgvq4eMJC7A3h388Wr218VRKJPaf 11 | 9T9vDOBoh30tDzhNx5eEU90OgImFp5hWMmfrJmPe0oD8AeLUzWBYwuvvXfwZZTaE 12 | G/MLD46qemQ59TnmOuvIafmQHBNdwBXYkwTFa3HRBAgjy8YNZBZOcGXR6xsCAwEA 13 | AQKCAgBLkOYCgQWLuPMlzpqJ1t3ecFVxckDisO+X78iiLrkKScZ0g1oZpx8vXxdY 14 | 5EoRymYpfQt/c/cePeJDRka4q86MaDD2LrCBPZgyBRk8kZqrIaUAwrmclv5D4/xU 15 | zvKhwBtf5MYKPQ0CGMJIOpyn+ku1oTeHHq2Hbp+6yPKTBJpIH06LN/QwbG9hr4R1 16 | Yg9H+AmwM4r8dJYAvJhvWd/yRYTRcrJb0kPQAopxJmee5NcPntW2JocibYbMax4V 17 | Nz21YlCWV8bCk4RdodcZ/O3mMJjDwSYN1hr41vOxy1lZj8zyIWtMMyfzcFIJm0EF 18 | QrUYSj3mp83QBzGU39Zt6RPNgW8d/CMrBRoGK4PnBqOaL8vxlc3zFh9imveXEhk+ 19 | bYhvC15w3+i94IX/7zEv8Bkx7iPUTvKh1RjEEDqYikuLmW9KEmF01u26BSg1Y2uM 20 | 6ZLlzhw9cKf8xok63jdE0o8XT+VRd8UzcdCnQ7k5NUkm4dLYhpNxMTCsSptBwpTV 21 | c7XwHOdMFopkQi8XMkZlJqNsXQy57BcDgEEfLPRsfd93jGOn5zIKwj5zC1DXDrDX 22 | uker1yDxkLxeQdFPQwvE3m1Xpb2lvR1a29474qE6bxsrp0ADajLaebnB+QprWRX3 23 | iBLMJau1YcI0HHpncGtTTzmmkuTNbwd7CgLODMQ35V2kkIbPGQKCAQEA/B+1oPhb 24 | bh0jZGTL3MoHQTjJNwmd2frv4ijxB683VJbhw0kbHbitnYsv/cCdgCTsHcxOGYQu 25 | D6feVTPtNoJxYZziXwFI0xvrgAMQHWPHDfESs3vCZtJfyWSVqNf7FGfbasxxe0D1 26 | 3qbKLVJSctdMezc1+o7grJmfd+mBNU3p9iGUmWNc/qBClsB4tlrsNfoyRiJwcOsY 27 | HZKXNeudawIBlq+Lysf1r7waLtjMg9flshzrkvOlls6xfV0z9MT6XvSnqKqUNiMI 28 | sgJGnc2SWbuYa/pVWNMyFdt40aq7i+ybkm+ddFJFEYD7X37yI9gZZQLsltik8D1/ 29 | fICX37mGrbk5vwKCAQEA007192RB31QA6rSTzQ48rvcKIreBH9dRf/LrQtrkUp1M 30 | oAAGeiH5iypCdWREL6yXVCXMmAgTUdpgP6hj5J7B7N7TkQP5HBvL+NIN/iaY2pob 31 | SI4hwf4OuiHD6oRMWuuzOlT8enNk4mo+ue29uv/g3gvR2S6zkOCDc2G3gycSfpfF 32 | vgjU0lF9dVhhn3emcXInDXkDU9aXXjy+8tXDo6xvbMV9Vo9nCrFMT1hYbrdIETxl 33 | GyrvVbDvel6xV765FT60v37Q0e4zbyPoS8iN0yDXg+XS8GrqrEnCDc6hUJG5OFwb 34 | kBnbCX0Eo0YXd85YuKYfwmwRwFK8Ct98FXl+EL8NpQKCAQA4o9sG7aSEqVEhJa/S 35 | yyQ0F9DEZ4mpxcEMWsxDQK66dycC2zKXS7zdLr66UAJSHnlY/GPzQYmjhL/i/kZl 36 | P4q/NiJ4224D1zrhyE5fe+HlFOpxnfT/anWQZeNlShgi7m4RoRpBaUeTHH9BDURu 37 | fkW1TKL4xg5dWCnGI5QeaIGOBN9AUl066r/q5BR6SxTTz4Bp1yTRiU8inaMQvvzf 38 | ZFT9CDTsel2MfEKZkaToXaFBkVOu8MObjJW9Jyob7ACfQnFD6AZh3x799prsqpkd 39 | RZKpd1SjHtcap/KNj8CQX7hXfnGuBylzFDnkqz00pkCWO8Dw5nyvZ/FzA+SaozBJ 40 | aNo7AoIBAQCGlyGlzK8EX44h8Ji/oFTYoLNM/5L4Q/4+P+zHbYLGeDiJJNr7Sc6X 41 | bHheK1oe/5B34YeaQnKDzVNG2Kufv9sHU7pwAJbX54CY4LpW6iCsBEJiiV1JIdgh 42 | iEYwhsnXk49aFS2nlP5qFIAVjy8s/7Qr2l10NwHawpYXlOL9X5KxHVyvORLNT2hY 43 | qM2tc9mJIstrEmwjJ2jMdmatZ6iwBLIIFxZJXxejwOA5Ha1d/9GgYNaJYmSFMSin 44 | yc6tc+aReJpJ6q15OX57SOS5+GkVVDLRaT5dMcx9ppE6mCU5m0fddRV9SGqydXXR 45 | xWBHSCBMpEtQW+NGm6v4RPbU+shoRDidAoIBAQCfNnCjLvLNTfeJ4blQOdGMOiDr 46 | TEyxtF9tAgkzbQefBr6HBVwzfPdywUtf3ZxVxKIsnpYmbGJIKp525/Wtvme7qjp4 47 | CsdyFO6ZFLEeI8KGKiewGEv5YzvQIpVqoMZ6ucY/WiSvwHSvZuyLZVLHOLGcZRLJ 48 | 49jbfhsvrJqWVDC2CmX2oAuH3GF+LUFhkM36zD1d0FrpaZwL2acWErk/N0CNhnNp 49 | H/08579O5MmSjlWh8Eco2wVD1z/A+LSC0YN+04ZrurB7wAebGCsOoEO7M53aan77 50 | gP2nLQ/cnYHiPrmUlL5s7EDhKnvpNY1W2ViEydwywvg9m4mxOA1sjrYpoNRg 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /test/key/keypass.txt: -------------------------------------------------------------------------------- 1 | Private Key Phrase (SP) - signature 2 | VHOSp5RUiBcrsjrcAuXFwU1NKCkGA8px 3 | 4 | Private Key Phrase (SP) - encryption 5 | BXFNKpxrsjrCkGA8cAu5wUVHOSpci1RU 6 | 7 | Private Key Phrase (IDP) - signature 8 | q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW 9 | 10 | Private Key Phrase (IDP) - encryption 11 | g7hGcRmp8PxT5QeP2q9Ehf1bWe9zTALN 12 | -------------------------------------------------------------------------------- /test/key/sp/cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV 3 | BAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQK 4 | DApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNv 5 | bTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhL 6 | MRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2Rl 7 | LXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIw 8 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZq 9 | ClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPs 10 | tBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15 11 | qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QB 12 | o7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZ 13 | ApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEA 14 | AaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaA 15 | FEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL 16 | BQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+ 17 | uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1i 18 | JmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq 19 | 2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uL 20 | EpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNr 21 | vk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /test/key/sp/encryptKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: DES-EDE3-CBC,860FDB9F3BE14699 4 | 5 | bMpTdWaAEqNciUFQhHYNv1F9N12aqOQd6cFbMozfRnNR19HW6QIPDmEOPSSCaaRy 6 | QCnJhbpcSnaz9pvI7EzeJzdykDmR8Boos+0NSK9qIX0buBO55mfPr7hjx7bLFEVl 7 | kkHk+k9F1rLyjyAGJrVoTNoWjyuMOFUCWR7ZxoYticwM/sL+Rbhn1FsfdkdfhFW0 8 | 08OHTouRK33Aifx0A3MWxR0ILvw49E6urtbbIrskEzKzfWQug8gY1TJhI3sbsMsI 9 | 1bS5Vg88TvilFFBGn0Yv6GEJjgOrsrKDGKtYGhuBfK4fd4rwnQKKvC6gTKeNXIfV 10 | 7Qm1R20LUJXC8zv35pdKoVk+NdS/MGNXJRFgO3Kkp01aVf3n1oo2+AllS02AYyWt 11 | 1svHecsRwbibXip8gSQsOtDdpqQrEDyqZlFHXEw/IcJE9vQWEJmpHD5GFhbKtttp 12 | E0B3ZtNl6YcyUz0rSf9zjuMx/wReWdRb6H2WoIqoRS7vAUONDRPt7wvfjtLlDRVi 13 | bc2RTN8yce/57lGnA1n8bxPV5+9VxCJOEipV3io/nrj+uNO8i/0rUpkKdZy8wy2C 14 | Rksoxq4TxwegONz1HQcJVpJu0iBdu7B+BXVjxQQScvMQlOTbua8k+YdaCeZAb83j 15 | JVX89/PFy+Xj7eGyzzBTqz7dV0Xkxq9mpiMYUCoyNL5Iq1jD9Xb5TzVW1Gbh8zCZ 16 | YXjcZEQKeartaBC4/fRWyxqK3gJRX4SJkl4gYMQrPS2pbTzVCO+WLxSwIh3dOZpo 17 | eErXLSrylIv9cE2Xrs0McXAR+hfGrqgtILBWwgbh2NhmUiFfLwUTUxU51eu7QZ2T 18 | V1VFBX0QTmn2kM0JLSSC96mDUzbs6qfURUaXbuffF5cqdUjXgtzZj5SFEbIv4UFS 19 | 0DAS+6i/jTGSz7aAp/uofOxhYkCqK/s2Cex2jQbDpcKXKiWzPdULOCjAh3fdCAp0 20 | 3ua3fdAI7H8PslSDiPFrcY78OxZaWXzazEiun77WKbzrMloLMP5dpCPlUCOqxbZ0 21 | ykSuo0M7p/UPY34yi3AMHS9grvQQ1DykMPoqKKEheI6nUGcQ1AFcdr307ILWRsPO 22 | T6gHOLXZaR4+UEeYfkTKsjrMUhozx7JIyuLgTXA9TWC+tZ9WZpbJ7i3bpQ+RNwX2 23 | AxQSwc9ZOcNxg8YCbGlJgJHnRVhA202kNT5ORplcRKqaOaO9LK7491gaaShjaspg 24 | 4THDnH+HHFORmbgwyO9P74wuw+n6tI40Ia3qzRLVz6sJBQMtLEN+cvNoNi3KYkNj 25 | GJM1iWfSz6PjrEGxbzQZKoFPPiZrVRnVfPhBNyT2OZj+TJii9CaukhmkkA2/AJmS 26 | 5XoO3GNIaqOGYV9HLyh1++cn3NhjgFYe/Q3ORCTIg2Ltd8Qr6mYe0LcONQFgiv4c 27 | AUOZtOq05fJDXE74R1JjYHPaQF6uZEbTF98jN9QZIfCEvDdv1nC83MvSwATi0j5S 28 | LvdU/MSPaZ0VKzPc4JPwv72dveEPME6QyswKx9izioJVrQJr36YtmrhDlKR1WBny 29 | ISbutnQPUN5fsaIsgKDIV3T7n6519t6brobcW5bdigmf5ebFeZJ16/lYy6V77UM5 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /test/key/sp/encryptionCert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID7TCCAtWgAwIBAgIJANSq1uUtXl4DMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNV 3 | BAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFjAUBgNVBAoTDWV4cHJlc3Mtc2Ft 4 | bDIxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWwwHhcNMTUxMDAzMDM0ODA2 5 | WhcNMTgxMDAyMDM0ODA2WjBXMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBL 6 | b25nMRYwFAYDVQQKEw1leHByZXNzLXNhbWwyMQwwCgYDVQQLEwNkZXYxDjAMBgNV 7 | BAMTBWVzYW1sMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyx/yIgvJ 8 | wfOCwMTNjL4Fslr21ky4O/uzxp0Y8wpHk9jk8Afcj3plQCr5X8dPKG2Rz4EIh//n 9 | QQL9tq2InaUdRwJkS9SeuuAcJG7DN/KDUtfrh4+cO2lZ4h7cQIdjpbBgpGEMhGy1 10 | wwpwHJsadoBuX0PKyT4O4oHkj1gwWO14qYnK4biviNBqmjGjmN+py+lUcACsQt22 11 | abA4s8Xjm/tlvnkgNRE3H44ICvSr8m5MVhyYGoAUe7Qprn2BcsMXd9mrlZ5hEdal 12 | NUDRbKb+W7mrKEkKFCbE3wi/Ns2bc4fbNXvwcZoF3/TPzl936u2eivTQESjCLsym 13 | IqdYHwRiVLifWQIDAQABo4G7MIG4MB0GA1UdDgQWBBSdBiMAVhKrjzd72sncR13i 14 | mevq/DCBiAYDVR0jBIGAMH6AFJ0GIwBWEquPN3vaydxHXeKZ6+r8oVukWTBXMQsw 15 | CQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRYwFAYDVQQKEw1leHByZXNz 16 | LXNhbWwyMQwwCgYDVQQLEwNkZXYxDjAMBgNVBAMTBWVzYW1sggkA1KrW5S1eXgMw 17 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEARi25PJOR+x0ytYCmfXwG 18 | 5LSXKNHx5BD6G+nBgXm1/DMMJ9ZY34FYMF3gDUu+NmQoVegqARTxetQcCICpAPdK 19 | nK0yQb6MXdj3VfQnEA+4hVGFmqnHTK90g0BudEmp1fWKBjJYpLd0oncVwJQJDK5O 20 | fS7fMUftN6/Kg6/fDuJMCNIECfKRE8tiXz2Ht924MjedKlH0+qoV1F2Fy5as+QRb 21 | j/QfrPTrZrfqhP04mavTPL2bdW6+ykeQWN3zMQtJA8kt2LI0y0CIGhFjLbqAceq+ 22 | gDkp4drj7/Yw8qaqmxl6GP8w3GbfLu6mXCjCLCGgsATktvWq9dRfBuapaIpNDrv0 23 | NA== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /test/key/sp/knownGoodCert.cer: -------------------------------------------------------------------------------- 1 | MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 2 | -------------------------------------------------------------------------------- /test/key/sp/knownGoodEncryptKey.pem: -------------------------------------------------------------------------------- 1 | Proc-Type:4,ENCRYPTEDDEK-Info:DES-EDE3-CBC,860FDB9F3BE14699bMpTdWaAEqNciUFQhHYNv1F9N12aqOQd6cFbMozfRnNR19HW6QIPDmEOPSSCaaRyQCnJhbpcSnaz9pvI7EzeJzdykDmR8Boos+0NSK9qIX0buBO55mfPr7hjx7bLFEVlkkHk+k9F1rLyjyAGJrVoTNoWjyuMOFUCWR7ZxoYticwM/sL+Rbhn1FsfdkdfhFW008OHTouRK33Aifx0A3MWxR0ILvw49E6urtbbIrskEzKzfWQug8gY1TJhI3sbsMsI1bS5Vg88TvilFFBGn0Yv6GEJjgOrsrKDGKtYGhuBfK4fd4rwnQKKvC6gTKeNXIfV7Qm1R20LUJXC8zv35pdKoVk+NdS/MGNXJRFgO3Kkp01aVf3n1oo2+AllS02AYyWt1svHecsRwbibXip8gSQsOtDdpqQrEDyqZlFHXEw/IcJE9vQWEJmpHD5GFhbKtttpE0B3ZtNl6YcyUz0rSf9zjuMx/wReWdRb6H2WoIqoRS7vAUONDRPt7wvfjtLlDRVibc2RTN8yce/57lGnA1n8bxPV5+9VxCJOEipV3io/nrj+uNO8i/0rUpkKdZy8wy2CRksoxq4TxwegONz1HQcJVpJu0iBdu7B+BXVjxQQScvMQlOTbua8k+YdaCeZAb83jJVX89/PFy+Xj7eGyzzBTqz7dV0Xkxq9mpiMYUCoyNL5Iq1jD9Xb5TzVW1Gbh8zCZYXjcZEQKeartaBC4/fRWyxqK3gJRX4SJkl4gYMQrPS2pbTzVCO+WLxSwIh3dOZpoeErXLSrylIv9cE2Xrs0McXAR+hfGrqgtILBWwgbh2NhmUiFfLwUTUxU51eu7QZ2TV1VFBX0QTmn2kM0JLSSC96mDUzbs6qfURUaXbuffF5cqdUjXgtzZj5SFEbIv4UFS0DAS+6i/jTGSz7aAp/uofOxhYkCqK/s2Cex2jQbDpcKXKiWzPdULOCjAh3fdCAp03ua3fdAI7H8PslSDiPFrcY78OxZaWXzazEiun77WKbzrMloLMP5dpCPlUCOqxbZ0ykSuo0M7p/UPY34yi3AMHS9grvQQ1DykMPoqKKEheI6nUGcQ1AFcdr307ILWRsPOT6gHOLXZaR4+UEeYfkTKsjrMUhozx7JIyuLgTXA9TWC+tZ9WZpbJ7i3bpQ+RNwX2AxQSwc9ZOcNxg8YCbGlJgJHnRVhA202kNT5ORplcRKqaOaO9LK7491gaaShjaspg4THDnH+HHFORmbgwyO9P74wuw+n6tI40Ia3qzRLVz6sJBQMtLEN+cvNoNi3KYkNjGJM1iWfSz6PjrEGxbzQZKoFPPiZrVRnVfPhBNyT2OZj+TJii9CaukhmkkA2/AJmS5XoO3GNIaqOGYV9HLyh1++cn3NhjgFYe/Q3ORCTIg2Ltd8Qr6mYe0LcONQFgiv4cAUOZtOq05fJDXE74R1JjYHPaQF6uZEbTF98jN9QZIfCEvDdv1nC83MvSwATi0j5SLvdU/MSPaZ0VKzPc4JPwv72dveEPME6QyswKx9izioJVrQJr36YtmrhDlKR1WBnyISbutnQPUN5fsaIsgKDIV3T7n6519t6brobcW5bdigmf5ebFeZJ16/lYy6V77UM5 2 | -------------------------------------------------------------------------------- /test/key/sp/privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: DES-EDE3-CBC,9C86371F0420A091 4 | 5 | 77TqgiK/IYRgO5w3ZMyV81/gk0zN5wPTGWxoztNFjQKXCySFnrL30kUqlGituBxX 6 | VgxwXbkoYMrd5MoDZKL5EJuf0H59hq92O0+3uwJA8QyZjOm4brQcjXKmIrkvihgs 7 | FvpaJiGzp6kS/O7vFBDNTQWr9yY9Y3FBPcmOUWufpRp4Q5nhpSlqnMmIqZyWQUL/ 8 | YJSJETtzJVsk38lCqIxxDT3LtbGySahj0jRuRqspAZQeLTpnJqzNMC4vnJew9luC 9 | R+UffrX7gVsnwOhNtyRzYaMsLnbRfXT8Jqx2gRHg36GxkOVgyU7e62nk9CzeC0WA 10 | kHHCNVqqivRx9/EC0mQkkRgRzo3BZWp0o671sUsGTy57JhktiGfTnWMrl7ZfhAza 11 | SZnjyTwuI1bTQipIkNI3aJBTP/o/gNUE1sj5D5FZlFdpq5ks2Vxww3GNx1FRrvWd 12 | 98z5CNt78ZR0ihLmdz/EakEBKBUteQu/5zPLUlwmGuou4wPuEHG2BsjGzb/d5Zfc 13 | ElIjUV+yrMmGHvBfPyPnDUrCUyLn18S1NZiCMCdN5PqCybjhk8oMPYZhWBqp8Ymr 14 | yHIC7BCnTJhIvgQZR6M68NwVv0aBBgH/I/DB0jADo6/B5Eajwus9i6zSv8QIbqhw 15 | fusKtI04vxc91aP0GWRr0J/O4mkxXYNPfa3a/I7sGTXGl0k0CygckE3fLXRy/WEk 16 | ikZt4UHqg5ZQ8vc5NSAM5f5Yx/72CU1I6ehFtxHsyE5yndpZXWp2X2S4l31e8fLs 17 | ddOoybroJgbyLrh7JT3Yac3XOEsKATWIvqU+hNYq6KwqLWev9jInHVgjzfyOKbmF 18 | hkrzDDHaKULYZuTsUq5mLc1SzSu98lXYfXp1WE4XsH0X0VicPzf8ZH4Kutuig0VG 19 | 5Kg9HB/Cin65VMm0ffEiTraO6johIlwFGRrtAs38ONKgsPCQUv7ee9SEGOHViNZq 20 | NpWPr1KOzbI4wEB1ueKoZuEQ0a+tzfJgszJrM48bM82J6iEjN/PSOTsdTKJq9e47 21 | dlUp+tqQsvGkbBOIOt5OOpkr8Z+8qbEd21ojF9Q0p0T4WMThRP6YBRKvt8mmFwRs 22 | DjEhMiPa4L70Eqldfu2lWdI6ietfHrK97WXwQO1gF73LOnA+EdMXNxr1iLd0Tdke 23 | z6fUSw3hKZL+I7nX6O40+KgkhXVSZOsRz5CEvo2iChIUrYGEGDl94K/ofqGu71Y+ 24 | G8KBvbha6EC7xcUrTYP5Gek5wsrw7cGgDZJjMsyXYFBZjQO1N6g9fncLmc5pB5Ix 25 | W3gLfQS/My4daWNTvrYOgfA08J4M4ZWd0v5TglxOSV78psG4J4slppDySNFB2d/3 26 | 7JiwWVm5SMk0StLWwb2azmTvBoinnrZJzPnPlOytxvE5uGJ/i0WAik7C99YgVJkS 27 | 9hO3FJGasrOnHeiOvMZEdRuIVspKz9iMFx7hWHpVHTTyjwceEpaiEkhmqLM9QkKh 28 | kCZqeWyVsKBIc0sse+CKNK8ik9eTeUlCklGMV1Q4kKjR6uuHUOLyjk/xhqslV4TS 29 | jnnjCjsK5YzTa4hmbHhPZIW262KoFV9TqxYKkhP5ab7AXRSakrdrY2cwACWN4AMT 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /test/misc/attack_response_signed.xml: -------------------------------------------------------------------------------- 1 | evil@evil.comhttps://idp.example.com/metadatahttps://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1sZOR3aMpVBn1CoSmP674OQfCcyg=h7Dk6GTh4MrNNx8b8Or12SeGsAGBM/ILd7Jgz/RuqR6ixMHrmkRAotou8LvKOzH9I9BfLthqgwcNJGm4hMPHcxoiyVlkqWqnpIMxlWc/vb1E/lXjwo86mZ/hBUJdRhgIfrgIDKCMBf98ftWtUF8I1Hd5qBvY7pTMk3ErQYOtqBfvCCFGwejAfOUKwtY4itQ7AILi4Er2IgALH0zJO7alPugTOwmICd998rafB2wAHWREJkaOfCgCasRkB8tqcWjpLx2oMqiYSTVq2d6PBgAFSmoN9ltO2neTz9pqd0BA1BKIi7PjQYN+F7dB/ffG7V8VjNoPMROrHzq6sY3Ondtv7w==MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 2 | -------------------------------------------------------------------------------- /test/misc/dumpes_issuer_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | http://www.okta.com/dummyIssuer 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Spr+5HzbZxSt8I3vCY4rTBu+glE= 19 | 20 | 21 | 22 | signatureValue 23 | 24 | 25 | 26 | stuff 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | http://www.okta.com/dummyIssuer 37 | 38 | email@email.com 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | api.com 48 | 49 | 50 | 51 | 52 | urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient 53 | 54 | 55 | 56 | 57 | 58 | 60 | email@email.com 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /test/misc/failed_response.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadata -------------------------------------------------------------------------------- /test/misc/false_signed_request_sha1.xml: -------------------------------------------------------------------------------- 1 | https://sp.example.org/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordtQDisBXKTQ+9OXJO5r7KuJga+KI=oxRkvau7UvYgFEZ7YNAUNf3067V7Tn5C9XSIiet1aZw2FYevNW5bUy/0mxp3aj6AvfFjnmpzAb88BjdwAz2BErDTomRcuZB7Lb0fYTf31N2oZOX0MiPiQOH54I63qJW4Xo3VqdF7GBuFZZHyllfSBv7gfCtjJDwFSCzWK70B9r3cFMRJZLhCJ9oPen+4U9scSYO6g+szBZLl6AiJ06PHc8jzEKGwfQrcZk8kDKUlvNfJMULyq8dpx2VvUAx4p5ewfMOwB9W3Hl3PPa0dO77zZif3CglpcN06f+m6UYG/wnoTQEyKW9hOe+2vGM80W77eWu0dmiaPuqTok8LXPuq1A==MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 2 | -------------------------------------------------------------------------------- /test/misc/false_signed_request_sha256.xml: -------------------------------------------------------------------------------- 1 | http://localhost:4002/sso/metadata9Ftynct5x7o+SdQM9iie2Z8VzZW95OTtXh4BD4O/HP8=EjY0qRy8tJeSANz3uINpdyFmCISiid4vl3KtszPa1mLvx1wGO2RJiFW8Sa18JOS0l8rYP2gwoUYmxU5WS/Cl1QEMlDj46fPpOjEBELGXdKW69zpAHa5jM/FtS8RCixhiMI1dmbL3+zgziEVdx5xrkaakqvpdDD601Eyn0gy1oO+VUmCMPFE6YjsPeFDhw5ZXf7MmJ/fXLeqWmH5Pn+mkyTCZWxi/L+2nG9iayZ41Z3wBl67XTdBL6rwHMcEY7oxwFSZtKTbtTOV6aW11KdAd9peLIsHeqoaMCY/VypS2bTr9FubQCbHhho2vbhX8cuUfpE21OefA7o1rA==MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 2 | -------------------------------------------------------------------------------- /test/misc/false_signed_request_sha512.xml: -------------------------------------------------------------------------------- 1 | http://localhost:4002/sso/metadata9Ftynct5x7o+SdQM9iie2Z8VzZW95OTtXh4BD4O/HP8=dk+CI6UvXgsM0cHAGAz/Y3gbvehbab92i1jEmDH0QB7d6/3l7j7TuOEvUFnmtwa0kwpigwpySwXybfiuvgdSBmhejwng5m28bYqaIA8FgCWe/BkBVL5BYeQH03gPbnqhBpC5EXUe52FtOlGAoTGNqaD0pyrshoGiOj/OzqVZC7RSBvvYt5iwpLyqj4KIFFao4yNAfIs2n7RwfcbGg3I2m2b5nuhVppRdzzukdQiLdDCuATPDxKJ3KdETbHb3yss+8L2iDPcAoqsZ+UTZ8VI5DhrQBcarcIe8Xp2FUKQnC4n0AEqCpb87l6txPz7GYDaw9yMqe2xD5LPWQ6/2guvqw==MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 2 | -------------------------------------------------------------------------------- /test/misc/idpmeta.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 9 | 10 | MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 11 | 12 | 13 | 14 | 15 | 16 | 17 | MIID6TCCAtGgAwIBAgIJAPQQPsolUypeMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDAeFw0xNTEwMDMwMzU3MzRaFw0xODEwMDIwMzU3MzRaMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7dF1gUNu8en0fHMSbzf192uB8m2CTeHeEeYrmq5rau6t1WzaHwbSStd9tJ/11Arm8f8zfefFqEBA0EYbp/DMqHb9ZiLGgIff08679NOYeK/d9EAs5DzvTMTR6QqG7a4vH3jKOksIbjM35h5RVitVDxo+xWDKyvOpuNE64bJlWHOEiNxvwmcHfJ2hAd1EozaRLcJOojFHg51alUqiNIZ+vpkMAM8s3lUlcYETKqTpcnsE7c1QX60cCrFN4m3SNS98HGBEdotch8+2Myzz957cBiwg9CR05PtEfjH0gGXJbL56JmpPyY+TkEiNMtMqJ7RNkK92gZfoY2i3RdjLKOHDUCAwEAAaOBuTCBtjAdBgNVHQ4EFgQUm4zK2qBtDMICekupt3LnRBdbP9UwgYYGA1UdIwR/MH2AFJuMytqgbQzCAnpLqbdy50QXWz/VoVqkWDBWMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRUwEwYDVQQKEwxleHByZXNzLXNhbWwxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWyCCQD0ED7KJVMqXjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9t7VMtX93yIYIGFC20GCsMYZeZpTedxpxpjqom2dOuOUaDQgrZcGF3FVbFqTEpPtOnsKXYaCg7FJvUjxv7FIuix5H7JO6DALoJ792pfG2wwS2PvDiGFxMfGnNvb3aLnB/s6wTyWBpDYRdwlB5nj37KPk6kpFJj3N9x5BD1oTdmQqeVuacjoiemIulkc33P28tGl6Datth4WpE0LwmrwREQ1NWixi2j1Ti3mjYkyqGVY8XphWKEIIWmheqLnYCXRXhbxZ4E+FGg81ZYG8TKYC/IjzV8p0rLnAI1qS7wdwv5UJ9vQJt6KcxdHHZsUlpIfaJC6N5DvAL/qUY8DoIymgz 18 | 19 | 20 | 21 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 22 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 23 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 24 | urn:oasis:names:tc:SAML:2.0:nameid-format:entity 25 | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified 26 | urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos 27 | urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName 28 | urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/misc/idpmeta_nosign.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 9 | 10 | MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 11 | 12 | 13 | 14 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 15 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 16 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 17 | urn:oasis:names:tc:SAML:2.0:nameid-format:entity 18 | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified 19 | urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos 20 | urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName 21 | urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/misc/idpmeta_onelogoutservice.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 9 | 10 | MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 11 | 12 | 13 | 14 | 15 | 16 | 17 | MIID6TCCAtGgAwIBAgIJAPQQPsolUypeMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDAeFw0xNTEwMDMwMzU3MzRaFw0xODEwMDIwMzU3MzRaMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7dF1gUNu8en0fHMSbzf192uB8m2CTeHeEeYrmq5rau6t1WzaHwbSStd9tJ/11Arm8f8zfefFqEBA0EYbp/DMqHb9ZiLGgIff08679NOYeK/d9EAs5DzvTMTR6QqG7a4vH3jKOksIbjM35h5RVitVDxo+xWDKyvOpuNE64bJlWHOEiNxvwmcHfJ2hAd1EozaRLcJOojFHg51alUqiNIZ+vpkMAM8s3lUlcYETKqTpcnsE7c1QX60cCrFN4m3SNS98HGBEdotch8+2Myzz957cBiwg9CR05PtEfjH0gGXJbL56JmpPyY+TkEiNMtMqJ7RNkK92gZfoY2i3RdjLKOHDUCAwEAAaOBuTCBtjAdBgNVHQ4EFgQUm4zK2qBtDMICekupt3LnRBdbP9UwgYYGA1UdIwR/MH2AFJuMytqgbQzCAnpLqbdy50QXWz/VoVqkWDBWMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRUwEwYDVQQKEwxleHByZXNzLXNhbWwxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWyCCQD0ED7KJVMqXjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9t7VMtX93yIYIGFC20GCsMYZeZpTedxpxpjqom2dOuOUaDQgrZcGF3FVbFqTEpPtOnsKXYaCg7FJvUjxv7FIuix5H7JO6DALoJ792pfG2wwS2PvDiGFxMfGnNvb3aLnB/s6wTyWBpDYRdwlB5nj37KPk6kpFJj3N9x5BD1oTdmQqeVuacjoiemIulkc33P28tGl6Datth4WpE0LwmrwREQ1NWixi2j1Ti3mjYkyqGVY8XphWKEIIWmheqLnYCXRXhbxZ4E+FGg81ZYG8TKYC/IjzV8p0rLnAI1qS7wdwv5UJ9vQJt6KcxdHHZsUlpIfaJC6N5DvAL/qUY8DoIymgz 18 | 19 | 20 | 21 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 22 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 23 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 24 | urn:oasis:names:tc:SAML:2.0:nameid-format:entity 25 | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified 26 | urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos 27 | urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName 28 | urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/misc/idpmeta_share_cert.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 9 | 10 | MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 11 | 12 | 13 | 14 | urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 15 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 16 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 17 | urn:oasis:names:tc:SAML:2.0:nameid-format:entity 18 | urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified 19 | urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos 20 | urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName 21 | urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/misc/invalid_response.xml: -------------------------------------------------------------------------------- 1 | 2 | https://idp.example.com/metadata 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/misc/logout_request.xml: -------------------------------------------------------------------------------- 1 | 2 | http://sp.example.com/metadata 3 | f92cc1834efc0f73e9c09f482fce80037a6251e7 4 | 5 | -------------------------------------------------------------------------------- /test/misc/multiple_entitydescriptor.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 9 | 10 | MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 11 | 12 | 13 | 14 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 30 | 31 | 32 | 33 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/misc/request.xml: -------------------------------------------------------------------------------- 1 | https://sp.example.org/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Password 2 | -------------------------------------------------------------------------------- /test/misc/response.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadatahttps://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1 2 | -------------------------------------------------------------------------------- /test/misc/response_signed.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadatahttps://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1sZOR3aMpVBn1CoSmP674OQfCcyg=h7Dk6GTh4MrNNx8b8Or12SeGsAGBM/ILd7Jgz/RuqR6ixMHrmkRAotou8LvKOzH9I9BfLthqgwcNJGm4hMPHcxoiyVlkqWqnpIMxlWc/vb1E/lXjwo86mZ/hBUJdRhgIfrgIDKCMBf98ftWtUF8I1Hd5qBvY7pTMk3ErQYOtqBfvCCFGwejAfOUKwtY4itQ7AILi4Er2IgALH0zJO7alPugTOwmICd998rafB2wAHWREJkaOfCgCasRkB8tqcWjpLx2oMqiYSTVq2d6PBgAFSmoN9ltO2neTz9pqd0BA1BKIi7PjQYN+F7dB/ffG7V8VjNoPMROrHzq6sY3Ondtv7w==MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA= 2 | -------------------------------------------------------------------------------- /test/misc/response_signed_cert1.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadataiPlh1ZRFuCBV07ayPRWVk7xU9SB5JN8mu6xAab3lEo0=ECKTz4y6czJx+KGlZNb8E6mBnFrMQC8hL7YDlAi8dko=GZSDF9T0TMTe5nkZspOBlc6+j+lon0eHjViy765ty0tM7F47qgDVWTiC2x326Iz8One12XKKbUHxMvqABnI77aNSJ0/BADFJLoH+mgPuSsgcZygTAWmKdn1bR/3zydMtkMIbP9JXB2VEF7a7KnnnjGcM2OXmdxanhe5J2vtrBWCrxt0QZOLaEsxQmCHosKizVhOnO5JehNqqkf9M4yp7acIsIVhCg21YYqnuAWMsve8qReryF31189TdsV9KO8uB0rufBsxl/dzNnMG74Rgq4mS3QjPI7N/WpXzZZk8vPe38FYEsFA5lmeIsdMxnlbbUEPJFwzWM72xEmMgo12+y4A==MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA=https://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1 -------------------------------------------------------------------------------- /test/misc/response_signed_cert2.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadataiPlh1ZRFuCBV07ayPRWVk7xU9SB5JN8mu6xAab3lEo0=ECKTz4y6czJx+KGlZNb8E6mBnFrMQC8hL7YDlAi8dko=JgrKOwRaj4swHYgLra3MOG92BeekCyRgbDfxAk5KLmzeRk1u0w6AmB/qW32mrlM4bn8LtwTq33PiHk6NMbkOfg5X2jQ8vjRyog+tgxDmwdiVkMMHfTWHcOqI5Gou572GayDLC0M9rOv4iHXUoDaul4ozhkeRolS9peLxydulSLzyXJiMGQ9ChnmxsR1P7y1rU/DOJ4O/zWzY2M9GoKBXWwG5C9RuoiO7FfOQn4za7InoQ+pBAtGWeh3mXwKLYpd+dhWL73vLa2sr5OmOQUlnFDSuFoAzhnT9eJEJCcedfmtjTUi724iAcYtFeXYahcCe/n4H2JjQYhE0ovG4JpEaThRA/sM3C6h3j7t9b+fX86VhH71+0f79VuX9TNeQkSiuYxqbUYvJjNgx3z8W7ixv5WGpHCjq6zd5KKbIwGk2+bWp7xs6ZD8sh9uyqWHNX/7YE096Ovxn4ki9O370MnK/3henA3m/+lwwWaL3Bn6+TmYC5DOWM7WVhy+dokSW6/2ZhgzoehpbDVZfYkKP+SH1w2PEqwtyB60fJpcTHZFANbCzfLJuyuRjiaWl9lzc3sKsRlK8W76ro/lXeIX2Jal1pQpkctZRUc0RyL+l9EnqzRnPc1K9nGUI+a8PNS54clILe0silqt339ZaE+wkslvhZ1M8oLzsWcXFWD+x2JZkvbo=MIIFLjCCAxYCCQCqGHhTssya9jANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJISzESMBAGA1UECAwJSG9uZyBLb25nMRIwEAYDVQQHDAlIb25nIEtvbmcxEDAOBgNVBAoMB3NhbWxpZnkxEDAOBgNVBAMMB3NhbWxpZnkwHhcNMjAwNTEwMTUyNjIzWhcNMzAwNTA4MTUyNjIzWjBZMQswCQYDVQQGEwJISzESMBAGA1UECAwJSG9uZyBLb25nMRIwEAYDVQQHDAlIb25nIEtvbmcxEDAOBgNVBAoMB3NhbWxpZnkxEDAOBgNVBAMMB3NhbWxpZnkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQG+abAeeWjwsOZt5SkcNcw/XSJcjSyJykEbEU2iguErRuOIyBfgj0p1UVBv33uL2igeYJT3OSXmSjvMO8KvqtYN2tJAjoFjghGr8NbIEZjYS4ukMZUbwxd2bRycD9OMI9g44AUB1sfQ0UyFwzEOseW3lcW1FnhcizA8TgI0GN4NpdVruNlpgoWdP3w+Syhtq0rWebY8g/HGFruEKn8VwbUblOZdP7jNVXsd1aUMScpuMa0khzzXPDN+Q0rwl79fO4ychSeKAAERdPXA1UfDfbh9W7pcYBP0ABXd91Bf9akplmbbVOIsNbuRIcVS7WvLwCr613JuJ+EtGDcUkrSpbuRvDW85DQRHBGuoKlcSG+imHQtHqRwMwMc8P54hIEBvaFW0RfwPfzdFNe8wARtmvIeX84iwq5Yey15Ly1rdopi7t2g7qyF7C/B9gZ3tJ/gPKp2NrdCGFBcahl93Lj56WWmI0jNHn7+7Y3x6isJ3KTRXIliSrAwiK7/7UezOlWzs1k8mGQWZTD3AGGKu1cBVwuC+rh4wkLsDeHfzxavbXxVEok9p/1P28M4GiHfS0POE3Hl4RT3Q6AiYWnmFYyZ+smY97SgPwB4tTNYFjC6+9d/BllNoQb8wsPjqp6ZDn1OeY668hp+ZAcE13AFdiTBMVrcdEECCPLxg1kFk5wZdHrGwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCyA/14hKTqfdeOVl+MQ2SLPWi7pC/t/Zv4kc361xP26FAVSSrxgXq9kVLZeJIAqCwjGHkl/DTUlA8hfLfuZx5z+NI/qIodsXAjCzsCe7paEbjvR6OQjYkR0UY4u/AOO7x2op2KDFKNuWT9KZNm8bh1mxwNKep1fJP2O5M0nMYAGYbPsLAOn7mzZyufQl8hsJwIV2s8sbft7s8vmEYZbuueQDOJCMTt+eC08LONrovYChyYmj3i5RIk8kcaodeSDo811F1B1gDvO/dmVxgrHEgoai7X6LUoiAiLkigP7udNEZxbXsRlOhBRv9w+rRXFurVFlUPkQ9UF+QB0BoyIcUxo+fZ8vCA4xEVBenVBadpFbwum6+XeTkvDoRc4sSCpm8v2qtprc8aU/0F82EzxSybYvstc5lDv7wuwCwNwfoAQ+/16kTpJvoYbOXUPv5yCA3mIuqYeA1woaWPXsE4jNOzTqv1qOZQTvXProEgK5B0FR5ILc4mfNrD2p9VGbiYf2GjCfeEzDFg174dvSn2MMp1yK5pvZEp7yFE8z1eduYN6W/7qdtss9BGpnyS5X7LuYfDvd1dHP6/JuqJDbfSVG9prYWcaMRd3FzSC7jBeetJgMyj4dunfqw8R16aONhwvICtzdFa93hYrDvTyo3ae80KFi0WGgApKeoqO5t3l1PAcaA==https://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1 -------------------------------------------------------------------------------- /test/misc/signed_request_sha1.xml: -------------------------------------------------------------------------------- 1 | https://sp.example.org/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordtQDisBXKTQ+9OXJO5r7KuJga+KI=oxRkvau7UvYgFEZ7YNAUNf3067V7Tn5C9XSIiet1aZw2FYevNW5bUy/0mxp3aj6AvfFjnmpzAb88BjdwAz2BErDTomRcuZB7Lb0fYTf31N2oZOX0MiPiQOH54I63qJW4Xo3VqdF7GBuFZZHyllfSBv7gfCtjJDwFSCzWK70B9r3cFMRJZLhCJ9oPen+4U9scSYO6g+szBZLl6AiJ06PHc8jzEKGwfQrcZk8kDKUlvNfJMULyq8dpx2VvUAx4p5ewfMOwB9W3Hl3PPa0dO77zZif3CglpcN06f+m6UYG/wnoTQEyKW9hOe+2vGM80W77eWu0dmiaPuqT1ok8LXPuq1A== 2 | -------------------------------------------------------------------------------- /test/misc/signed_request_sha256.xml: -------------------------------------------------------------------------------- 1 | http://localhost:4002/sso/metadata9Ftynct5x7o+SdQM9iie2Z8VzZW95OTtXh4BD4O/HP8=EjCY0hdmiULo0qRy8tJeSANz3uINpdyFmCISiid4vl3KtszPa1mLvx1wGO2RJiFW8Sa18JOS0l8rYP2gwoUYmxU5WS/Cl1QEMlDj46fPpOjEBELGXdKW69zpAHa5jM/FtS8RCixhiMI1dmbL3+zgziEVdx5xrkaakqvpdDD601Eyn0gy1oO+VUmCMPFE6YjsPeFDhw5ZXf7MmJ/fXLeqWmH5Pn+mkyTCZWxi/L+2nG9iayZ41Z3wBl67XTdBL6rwHMcEY7oxwFSZtKTbtTOV6aW11KdAd9peLIsHeqoaMCY/VypS2bTr9FubQCbHhho2vbhX8cuUfpE21OefA7o1rA==MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 2 | -------------------------------------------------------------------------------- /test/misc/signed_request_sha512.xml: -------------------------------------------------------------------------------- 1 | http://localhost:4002/sso/metadata9Ftynct5x7o+SdQM9iie2Z8VzZW95OTtXh4BD4O/HP8=dk+CI6UvXgsM0cHAGAz/Y3gbvehbab92i1jEUmDH0QB7d6/3l7j7TuOEvUFnmtwa0kwpigwpySwXybfiuvgdSBmhejwng5m28bYqaIA8FgCWe/BkBVL5BYeQH03gPbnqhBpC5EXUe52FtOlGAoTGNqaD0pyrshoGiOj/OzqVZC7RSBvvYt5iwpLyqj4KIFFao4yNAfIs2n7RwfcbGg3I2m2b5nuhVppRdzzukdQiLdDCuATPDxKJ3KdETbHb3yss+8L2iDPcAoqsZ+UTZ8VI5DhrQBcarcIe8Xp2FUKQnC4n0AEqCpb87l6txPz7GYDaw9yMqe2xD5LPWQ6/2guvqw==MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 2 | -------------------------------------------------------------------------------- /test/misc/signed_response_sha1.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadataCocGj4j5psQ0OfZ1mOlAdQkfwjTqCb95tNqpiFtt6qhTlnn+1IIp9pDpMLubomf9LWwX176PPLWFYxsRmqyEBYlhT53hgAF+z2fEgJdlxXF7FYKsnsn+ujC0ZJP3QkUlWGT9eo74i67JrkAwmiOXPHBJAAN040L/uqmYgjqdnGIFZAyTk4SwplECf1yzVxh4wkETpkf1na1VgTpFC3QDHpXVmCdTbq4FgtgNyfcZmr10d81rmSLjwfHJswV8Qg+cuxXODcn0rxDA5ZA3abpIxGwHUMtKP8ak4amY1urWQTXkhaFjZIChA6E4p870MzfmzVExG6p8/svKf2vDHTAH0w==MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA=https://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1 -------------------------------------------------------------------------------- /test/misc/signed_response_sha256.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadata0TJreH5fvSPwTL8cMGtvYkc8mDQDirHL/0KAU0PPjWXKUqyWSVi7FtDhnAuUakJpfPaYowrHBaUkX+SoJC9uQjXNCgvx5Z7DJfNq+h/vFxoSoxMT/1qeKMKWoNQFVmUErIPMCl0Wou/MfDR8qd+0ofUyLF4pEglczqNBVGi23RirDMZGSgS9M6QDlgpTx/CDnWRL6+0T1lNrTLuX6n0VaEziUeHOHY0lK5T0hmT/tVlufZ7LRO10FN7MUrxzIZvIIWVNuPVOmn0hm/4Z33JEK7rT35+MZLq8f7fbA3SS4+4InJOvZZgBRR9BcPjeEXG1n1el7uyf2AfE9+gr3vu6eg==MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA=https://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1 -------------------------------------------------------------------------------- /test/misc/signed_response_sha512.xml: -------------------------------------------------------------------------------- 1 | https://idp.example.com/metadataRkgzPlU7snHmrHTA6tCt0DRqQFyQeNypGIFzaY+2/6OLsNNH0B4gdBWYUWrwMpOGNqHr9Wo+th248ABVoUBtbdQ2pT8M49D0JDGwvl6L8CscTK0xzLGaqaAhHwszmk61WGVOxrbkiZQqOQA8VDiua5bDoXOqiCqEIB6TlSuJ+HH4Lc6u10WSXChI5iC9YwsHoWS8tqFLw6rsx4qPx4hFkZfBUh6JFZNT8hsWiSr4y6d359SIkRgkPUd85+I/3Od//al4HLnIjXaDsahO/YZ9AlvOnBxjUEuk/7kuxZ91LDeI6I8ekno83+ndhk34tnaBc3l1uGeHNhJhpY3eK+LiCw==MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA=https://idp.example.com/metadata_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7https://sp.example.com/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtesttest@example.comusersexamplerole1 -------------------------------------------------------------------------------- /test/misc/sp_metadata_98.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | urn:oasis:names:tc:SAML:2.0:nameid-format:transient 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/misc/spmeta.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 11 | 12 | 13 | 14 | 15 | 16 | 17 | MIID7TCCAtWgAwIBAgIJANSq1uUtXl4DMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFjAUBgNVBAoTDWV4cHJlc3Mtc2FtbDIxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWwwHhcNMTUxMDAzMDM0ODA2WhcNMTgxMDAyMDM0ODA2WjBXMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRYwFAYDVQQKEw1leHByZXNzLXNhbWwyMQwwCgYDVQQLEwNkZXYxDjAMBgNVBAMTBWVzYW1sMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyx/yIgvJwfOCwMTNjL4Fslr21ky4O/uzxp0Y8wpHk9jk8Afcj3plQCr5X8dPKG2Rz4EIh//nQQL9tq2InaUdRwJkS9SeuuAcJG7DN/KDUtfrh4+cO2lZ4h7cQIdjpbBgpGEMhGy1wwpwHJsadoBuX0PKyT4O4oHkj1gwWO14qYnK4biviNBqmjGjmN+py+lUcACsQt22abA4s8Xjm/tlvnkgNRE3H44ICvSr8m5MVhyYGoAUe7Qprn2BcsMXd9mrlZ5hEdalNUDRbKb+W7mrKEkKFCbE3wi/Ns2bc4fbNXvwcZoF3/TPzl936u2eivTQESjCLsymIqdYHwRiVLifWQIDAQABo4G7MIG4MB0GA1UdDgQWBBSdBiMAVhKrjzd72sncR13imevq/DCBiAYDVR0jBIGAMH6AFJ0GIwBWEquPN3vaydxHXeKZ6+r8oVukWTBXMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRYwFAYDVQQKEw1leHByZXNzLXNhbWwyMQwwCgYDVQQLEwNkZXYxDjAMBgNVBAMTBWVzYW1sggkA1KrW5S1eXgMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEARi25PJOR+x0ytYCmfXwG5LSXKNHx5BD6G+nBgXm1/DMMJ9ZY34FYMF3gDUu+NmQoVegqARTxetQcCICpAPdKnK0yQb6MXdj3VfQnEA+4hVGFmqnHTK90g0BudEmp1fWKBjJYpLd0oncVwJQJDK5OfS7fMUftN6/Kg6/fDuJMCNIECfKRE8tiXz2Ht924MjedKlH0+qoV1F2Fy5as+QRbj/QfrPTrZrfqhP04mavTPL2bdW6+ykeQWN3zMQtJA8kt2LI0y0CIGhFjLbqAceq+gDkp4drj7/Yw8qaqmxl6GP8w3GbfLu6mXCjCLCGgsATktvWq9dRfBuapaIpNDrv0NA== 18 | 19 | 20 | 21 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/misc/spmeta_noassertsign.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | 12 | 13 | MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 14 | 15 | 16 | 17 | 18 | 19 | 20 | MIID7TCCAtWgAwIBAgIJANSq1uUtXl4DMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFjAUBgNVBAoTDWV4cHJlc3Mtc2FtbDIxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWwwHhcNMTUxMDAzMDM0ODA2WhcNMTgxMDAyMDM0ODA2WjBXMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRYwFAYDVQQKEw1leHByZXNzLXNhbWwyMQwwCgYDVQQLEwNkZXYxDjAMBgNVBAMTBWVzYW1sMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyx/yIgvJwfOCwMTNjL4Fslr21ky4O/uzxp0Y8wpHk9jk8Afcj3plQCr5X8dPKG2Rz4EIh//nQQL9tq2InaUdRwJkS9SeuuAcJG7DN/KDUtfrh4+cO2lZ4h7cQIdjpbBgpGEMhGy1wwpwHJsadoBuX0PKyT4O4oHkj1gwWO14qYnK4biviNBqmjGjmN+py+lUcACsQt22abA4s8Xjm/tlvnkgNRE3H44ICvSr8m5MVhyYGoAUe7Qprn2BcsMXd9mrlZ5hEdalNUDRbKb+W7mrKEkKFCbE3wi/Ns2bc4fbNXvwcZoF3/TPzl936u2eivTQESjCLsymIqdYHwRiVLifWQIDAQABo4G7MIG4MB0GA1UdDgQWBBSdBiMAVhKrjzd72sncR13imevq/DCBiAYDVR0jBIGAMH6AFJ0GIwBWEquPN3vaydxHXeKZ6+r8oVukWTBXMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRYwFAYDVQQKEw1leHByZXNzLXNhbWwyMQwwCgYDVQQLEwNkZXYxDjAMBgNVBAMTBWVzYW1sggkA1KrW5S1eXgMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEARi25PJOR+x0ytYCmfXwG5LSXKNHx5BD6G+nBgXm1/DMMJ9ZY34FYMF3gDUu+NmQoVegqARTxetQcCICpAPdKnK0yQb6MXdj3VfQnEA+4hVGFmqnHTK90g0BudEmp1fWKBjJYpLd0oncVwJQJDK5OfS7fMUftN6/Kg6/fDuJMCNIECfKRE8tiXz2Ht924MjedKlH0+qoV1F2Fy5as+QRbj/QfrPTrZrfqhP04mavTPL2bdW6+ykeQWN3zMQtJA8kt2LI0y0CIGhFjLbqAceq+gDkp4drj7/Yw8qaqmxl6GP8w3GbfLu6mXCjCLCGgsATktvWq9dRfBuapaIpNDrv0NA== 21 | 22 | 23 | 24 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 25 | 28 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/misc/spmeta_noauthnsign.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | 12 | 13 | MIIDozCCAougAwIBAgIJAKNsmL8QbfpwMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTAeFw0xNTA3MDUxNzU2NDdaFw0xODA3MDQxNzU2NDdaMGgxCzAJBgNVBAYTAkhLMRIwEAYDVQQIDAlIb25nIEtvbmcxCzAJBgNVBAcMAkhLMRMwEQYDVQQKDApub2RlLXNhbWwyMSMwIQYJKoZIhvcNAQkBFhRub2RlLnNhbWwyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQJAB8JrsLQbUuJa8akzLqO1EZqClS0tQp+w+5wgufp07WwGn/shma8dcQNj1dbjszI5HBeVFjOKIxlfjmNB9ovhQPstBjP/UPQYp1Ip2IoHCYX9HDgMz3xyXKbHthUzZaECz+p+7WtgwhczRkBLDOm2k15qhPYGPw0vH2zbVRGWUBS9dy2Mp3tqlVbP0xZ9CDNkhCJkV9SMNfoCVW/VYPqK2QBo7ki4obm5x5ixFQSSHsKbVARVzyQH5iNjFe1TdAp3rDwrE5Lc1NQlQaxR5Gnb2NZApDORRZIVlNv2WUdi9QvM0yCzjQ90jP0OAogHhRYaxg0/vgNEye46h+PiY0CAwEAAaNQME4wHQYDVR0OBBYEFEVkjcLAITndky090Ay74QqCmQKIMB8GA1UdIwQYMBaAFEVkjcLAITndky090Ay74QqCmQKIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG4lYX3KQXenez4LpDnZhcFBEZi9YstUKPF5EKd+WplpVbcTQc1A3/Z+uHRmyV8h+pQzeF6Liob37G87YpacPplJI66cf2Rj7j8hSBNbdr+66E2qpcEhAF1iJmzBNyhb/ydlEuVpn8/EsoP+HvBeiDl5gon3562MzZIgV/pLdTfxHyW6hzAQhjGq2UhcvR+gXNVJvHP2eS4jlHnJkB9bfo0kvf87Q+D6XKX3q5c3mO8tqW6UpqHSC+uLEpzZiNLeuFa4TUIhgBgjDjlRrNDKu8ndancSn3yBHYnqJ2t9cR+coFnnjYABQpNrvk4mtmXY8SXoBzYG9Y+lqeAun6+0YyE= 14 | 15 | 16 | 17 | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 18 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "declarationDir": "types", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "downlevelIteration": true, 11 | "sourceMap": true, 12 | "outDir": "./build", 13 | "baseUrl": "./", 14 | "removeComments": false, 15 | "strictNullChecks": true, 16 | "paths": {}, 17 | "lib": [ 18 | "dom", 19 | "es2015.core", 20 | "es2015.promise", 21 | "es2015.iterable", 22 | "es5" 23 | ] 24 | }, 25 | "atom": { "rewriteTsconfig": false }, 26 | "exclude": [ 27 | "node_modules", 28 | "types/**/*.ts", 29 | "test/**/*.ts" 30 | ], 31 | "compileOnSave": false, 32 | "buildOnSave": false 33 | } 34 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [], 4 | "linterOptions": { 5 | "exclude": [ 6 | "node_modules/**" 7 | ] 8 | }, 9 | "rules": { 10 | "arrow-parens": [true, "ban-single-arg-parens"], 11 | "comment-format": false, 12 | "interface-name": [true, "never-prefix"], 13 | "jsdoc-format": false, 14 | "max-line-length": false, 15 | "member-access": false, 16 | "no-console": [false], 17 | "no-consecutive-blank-lines": [true, 3], 18 | "no-empty-interface": false, 19 | "no-string-literal": false, 20 | "object-literal-sort-keys": false, 21 | "object-literal-key-quotes": false, 22 | "object-literal-shorthand": false, 23 | "trailing-comma": false, 24 | "eofline": false, 25 | "no-empty": false, 26 | "align": false, 27 | "no-trailing-whitespace": false, 28 | "ordered-imports": false, 29 | "quotemark": [true, "single", "avoid-escape", "avoid-template"], 30 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], 31 | "interface-over-type-literal": false, 32 | "no-var-requires": false 33 | }, 34 | "jsRules": {} 35 | } 36 | -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | export * from './index' 2 | export * from './src/types' --------------------------------------------------------------------------------