diff --git a/.github/workflows/build-ssp-debug-sp.yml b/.github/workflows/build-ssp-debug-sp.yml new file mode 100644 index 0000000..8ee97b2 --- /dev/null +++ b/.github/workflows/build-ssp-debug-sp.yml @@ -0,0 +1,29 @@ +name: Build docker SSP debug SP container + +on: + pull_request: + workflow_dispatch: + +jobs: + build-ssp-debug-sp: + + runs-on: ubuntu-latest + + steps: + + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log into GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build the SSP Debug SP container and push to GitHub Packages + uses: docker/build-push-action@v2 + with: + tags: ghcr.io/openconext/openconext-containers/openconext-ssp-debug-sp:latest + context: docker/ssp-debug-sp/ + push: true diff --git a/README.md b/README.md index dfdbf3f..1c6098f 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ # OpenConext-containers + +## SSP Debug SP +The SSP debug SP container is specifically targeted for use with StepUp projects. The container is configured with +a SP / IdP setup that tailors to use with StepUp authentication in mind. The debug SP (sp.php) can be used to fire +SSO and SFO authentications to the Gateway. + +In order to work with this container, you will need to do some small additional setting up in your own Dockerfile/Docker +Compose. + +1. Make sure you deploy a sp.key, idp.key, sp.crt and idp.crt to the `/var/cert` folder. They should match the SP + certificate of the SP's defined in your Gateway SAML entity setup. E.g the entities projected in + gateway.saml_entities`. diff --git a/docker/ssp-debug-sp/Dockerfile b/docker/ssp-debug-sp/Dockerfile new file mode 100644 index 0000000..1376504 --- /dev/null +++ b/docker/ssp-debug-sp/Dockerfile @@ -0,0 +1,40 @@ +FROM webdevops/php-nginx:7.2 AS ssp-debug-sp +MAINTAINER Michiel Kodde (michiel@ibuildings.nl) + +# Install required applications & binaries to install SimpleSAMLphp +RUN apt-get update && apt-get install -y git python zip libpng-dev nodejs +RUN docker-php-ext-install pdo_mysql exif gd + +# Install Composer +COPY --from=composer:1 /usr/bin/composer /usr/local/bin/composer +# Install SSP: Clone and install rev adf1eb8 of SSP +WORKDIR /app/ +RUN git clone https://github.com/simplesamlphp/simplesamlphp.git /app +RUN git reset --hard adf1eb8 + +# Install SSP: Copy files +COPY conf/config.php /app/config/config.php +COPY conf/authsources.php /app/config/authsources.php +COPY conf/accountgen.inc /app/config/accountgen.inc +COPY certificates/* /app/cert/ +COPY conf/saml20-idp-hosted.php /app/metadata/saml20-idp-hosted.php +COPY conf/saml20-idp-remote.php /app/metadata/saml20-idp-remote.php +COPY conf/saml20-sp-remote.php /app/metadata/saml20-sp-remote.php +COPY conf/SURFconext_short_to_urn.php /attributemap/SURFconext_short_to_urn.php + +# Install SSP: Install dependencies and build +RUN composer require simplesamlphp/simplesamlphp-module-saml2debug +RUN composer install --prefer-dist -n -o + +# Install SSP: Copy DebugSP files +COPY conf/DebugSP /app/modules/DebugSP +COPY conf/sp.php /app/www/sp.php +COPY conf/sp-config.inc /app/www/sp-config.inc +COPY conf/sp-utils.inc /app/www/sp-utils.inc + +# Enable the SSP IdP +RUN touch modules/exampleauth/enable + +# Configure the webserver: deploy the nginx vhost config & set php-fpm pool config +COPY conf/nginx.conf /opt/docker/etc/nginx/vhost.conf +RUN echo '' > /opt/docker/etc/nginx/vhost.common.d/10-php.conf diff --git a/docker/ssp-debug-sp/certificates/idp.crt b/docker/ssp-debug-sp/certificates/idp.crt new file mode 100644 index 0000000..2b45bfe --- /dev/null +++ b/docker/ssp-debug-sp/certificates/idp.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAlUCFA/gdInhlGAC81SV1MS4HTXKLa2PMA0GCSqGSIb3DQEBCwUAMDMx +GDAWBgNVBAMMD0RlbW8gR1NTUCAyIElkUDEXMBUGA1UECgwORGV2ZWxvcG1lbnQg +Vk0wHhcNMjEwNDIwMDcwMjI2WhcNMjYwNDE5MDcwMjI2WjAzMRgwFgYDVQQDDA9E +ZW1vIEdTU1AgMiBJZFAxFzAVBgNVBAoMDkRldmVsb3BtZW50IFZNMIIBojANBgkq +hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxJFJZyGp5Epp/y0rqRL63Q30S/97zlst +5Be/vtSwJL/M1yINk38mFGcjVEbuAxyDXHoHhgbwothfikI/1GLygPF4BGjse6fC +0JSOAyT8YrGvGm4NlKCrDnTcnryWkUZZFZWxzw5F6MdJ1N4+fa2b3KxSRokwrI8h +soxZxYmzaN01CBrNH4lv2RZ8dFttujUkUjWedOsMcjosg6bSHuSwHvbh1cNCj0Xq +bJyuEPdFlfi2WL4B8sQIUXPn3ms64K72+ZLPE/HhZ2Ush/mGA0b2Z0pCDX0728WF +og3ShTz6lXL0XL1Q1sl4ThIZxNraGJ5WxGqsWu5Kykk35gxQI0w9rTWosOCSRZcL +gVWE1GumlYv3x9XsXpj9+FG75E8Sre2uL0KlGqvcevKhc7h5hg5L059uFX6YnCDr ++F+03Iw5P1cDXaZ84Fua7MTCmldFcyIZxuib7vclhZCZGKgRxhmxZnSBDPT+D/zo +eq6WW5AJZEo3Ud4ZyRrolLueU66v/+VZAgMBAAEwDQYJKoZIhvcNAQELBQADggGB +AFd1oxY5qWs7x+keY8jf3AAV3ao3UIKuHpVm6YnkIoTLe+ova5IjY0blj9IYfDTE +UCoQkwekijJleNadrTQvBvh5ZAj+ghQOJhz2GoVA7CMA+QRIwU51tL7Umss4IQ8S +NEoz7JrZXfRqM34VAVhZb+9jImUJdpyeiOFLvdVyYkGrJ77+tEmxLpXHXCmPkayp +O7G0AGbkJHEzhsFSUfdd5O9zh1wX2xW1bXGFIBtBi3g6SsxfPtG69RIuC4E7mvWi +C9+139Ht9cM90tFRqO6C/ZonZPSR4G95oNI8jKnPS5oToDDzxK+qqCyRRlEts+pV +SIZiD2Equc+ejSkCiW1zNsKyimRv0arXZCm+GP7qh3bDEWXaGeG91beTRipTvphr +2+RGr9XDY1mEGqISIogNOQp+TQa5vj18pYRdiNtRcqwxoj/DtMfDpnzuyKD2g4Z8 +Z0+zTe9v0wzDa7Snk0nGWtF2mmW7cClyCpJm1vYE9Z2EWBth7ykndxGD3SpD62fW +Jw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/docker/ssp-debug-sp/certificates/idp.key b/docker/ssp-debug-sp/certificates/idp.key new file mode 100644 index 0000000..a8dc04a --- /dev/null +++ b/docker/ssp-debug-sp/certificates/idp.key @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4wIBAAKCAYEAxJFJZyGp5Epp/y0rqRL63Q30S/97zlst5Be/vtSwJL/M1yIN +k38mFGcjVEbuAxyDXHoHhgbwothfikI/1GLygPF4BGjse6fC0JSOAyT8YrGvGm4N +lKCrDnTcnryWkUZZFZWxzw5F6MdJ1N4+fa2b3KxSRokwrI8hsoxZxYmzaN01CBrN +H4lv2RZ8dFttujUkUjWedOsMcjosg6bSHuSwHvbh1cNCj0XqbJyuEPdFlfi2WL4B +8sQIUXPn3ms64K72+ZLPE/HhZ2Ush/mGA0b2Z0pCDX0728WFog3ShTz6lXL0XL1Q +1sl4ThIZxNraGJ5WxGqsWu5Kykk35gxQI0w9rTWosOCSRZcLgVWE1GumlYv3x9Xs +Xpj9+FG75E8Sre2uL0KlGqvcevKhc7h5hg5L059uFX6YnCDr+F+03Iw5P1cDXaZ8 +4Fua7MTCmldFcyIZxuib7vclhZCZGKgRxhmxZnSBDPT+D/zoeq6WW5AJZEo3Ud4Z +yRrolLueU66v/+VZAgMBAAECggGAA+SkwYgnJ0BaDRXF8ZlQoqQuHHs45oNjy0q1 +H4By5Kdv1Sr1feBczrakOn0VJbag22oHUB4/EdqbOc/KF9jF2MvvhpbVaDWQZDUt +At7uqL3ALBPV7QWpnaWu4O33RXVROl42oVU1CUE5MyAbuL2BgsNe9cqtzh0fm7uv +43uws/j9neV5/o/oSTJq0Jsm9zMqPv6U3tfw7So9y3W4X6hD3LkjC+rMHK5T0Ebi +I6/iDvBYHDXXMAm16HcVNpCFIAIXFT5WNdc21I89l4gbEMjoh+bkLhPHqFmTVVON +Qhn58UleXWSk1qJCWRYkNcwY2HPehA4aW8moACcS8XH6GeY20HP2fMPGULyNp3Kj +0pfq66R827ZViF3B4hTQpfFERLYJ/VkMhgRP1TDyvVwAdEM9kcUJS4u8uMGXxpgF +f1CWlmBARgvqdgkXhzfJDEsB/sOJhob9BDvberQyAESCWn3EJLROLTStvWeuCjWZ +s/BDz8DcFcIEdE8iuv7TYWJS6RgBAoHBAPAHNL5YzyRXyTn/PDzWmHKssvPGhP9D +eV5Ao+qOcnuo09oNkbYscWmhGD8LrbLy5XkgwlSXfZCHtrY1JjQyUA6ZpGfXszV7 +rwXa6BVs9aVQ78DYvAzsQEXPHoKMiWwXqzZ1BQFmfYCqMunYNgLqMdNfjR5ApLX7 ++IvejYe0I9azU4XEBamloh6x/lLXpi9vGCC0ppbW/qt3xMYXgpFaqrDQ6Ae3gOHu +ZmftPRdHtnhqHatF/lOY+WHV/YU4zqP4gQKBwQDRpb6Wy9LMs9E0ZdsnFccdW6tP +XgPBDCs/rrGhida+BJMlZYszuaDbqrwcbgLfBS/Ub7M3pIz3q5f2dpy+hXkf1jXX +xmPki7QM+WAmyYkvdbTCHnjCoNu1IjlvlSHqNO/Dvd9lPFQH70yOEZtsUq4dtssn +81ktFXZYbWm6/ZNxi+Q/MaaOwxMsFqim8fTn4kijVyeX2sjchyMfL2bGRpfGgxQv +rCTOUayyL2sbqQOh+vRzS4qhX2l0EbuWgafiQNkCgcEAsRHv0/g6H6pvNUzYSF1b +K0XB4lpyJMnHEEQJaHDbfeRHHRZjhwv0QqNn+qKH6nqL1LbZBYSYSfYEURiWbW0s +aAjqIv0aJHtw25XpHl06PlGd/RsmZzYmGBm6fT5l5orzcIIVRjownalxU9d/yNiy +FyfnOAkiOWp/qddte03mHm4+UHESaFtbZN+UKdMSsu121DHQr3g9eYsqa6ROWyKS +x0vl0EOMXZ/8hfCa38C0mNJXvtEs1MkGOCmgFBabQpWBAoHAUwFowJPa1qmrfy+E +4ajBuWH+JeJ3YgvLY99q/SZyG7H8AKZ/wu8QPWkQKcF06ZBIK7g+IR3JopYSCMdV +sClwl6Zckx49ltOpaimiZDkPU/cqpmEiNw0xcDoou4E0eGKVO88FkDOeobWhfe6C +txTVU3Z4YUz8VdlVjhVj82FK634T1OF3rLaX9LDT/aV27git8d4kEv/Q31+yDDrc +WkzA8xwa9fUWbYnw8mvL4Ju+kHeoKa4TKWl5ezc6KpETQ4WhAoHALvByZ0ch2G2V +NomRIiCXftGns+mFcTYv/JadMvKQvpwrDPdixqL5rDsPeE/woNmegTsOI3cCZrzr +zo+W1gUktCcHd9HE4b+8yuAFg2i/FJu9qBqSl2+32a6jt95tr4YySaycWW0NBbjv +sDsp5eXrq2Tv/6/s2KNdWvpptwhT1/hekll3Mv9vr9ETLG79Wcg5bBrbTwyYfj7O +qu4tIssiOAqNIH0AGg9alGEIsh/F0wXnAn7QRNvuVmyFZBZ9qAIs +-----END RSA PRIVATE KEY----- diff --git a/docker/ssp-debug-sp/certificates/sp.crt b/docker/ssp-debug-sp/certificates/sp.crt new file mode 100644 index 0000000..1201546 --- /dev/null +++ b/docker/ssp-debug-sp/certificates/sp.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID4zCCAksCFE/RXnB+y6e2zlC0Zpi7Pl6GbyuAMA0GCSqGSIb3DQEBCwUAMC4x +EzARBgNVBAMMClJBIFNBTUwgU1AxFzAVBgNVBAoMDkRldmVsb3BtZW50IFZNMB4X +DTIxMDQyMDA3MDIyM1oXDTI2MDQxOTA3MDIyM1owLjETMBEGA1UEAwwKUkEgU0FN +TCBTUDEXMBUGA1UECgwORGV2ZWxvcG1lbnQgVk0wggGiMA0GCSqGSIb3DQEBAQUA +A4IBjwAwggGKAoIBgQCyMqGyevrF/Ms8fsGQdz6fqzCA8T/QKC9Jb3m7EpQOp/OM +q/qBv4gjtFf0/bAun2N/u6zZOlPk61iVWRbxIet/O9BAoqRhtT6PHQVcReXR1F3+ +Dk2vH8+QyZwnWGENwh16BYuirIeWQuEgfVDUpSg2MBjkHjZmpF8Dxn6d485qwrdb +FZN+z3QPtxNaNu1FBktsgPNjlpE7HNB9xcGy4DlgTIP+80nKgM+Kdopw9FVk71bf +KKHp1m9qSSbFI+drtbtFJ7OPqFYDs9gJEY8ivALID1ERNQkAPImr/EIPiazHc4nk +Qfi4Kt5ohsvGufdCxYtOUGxjcrkq9oJX5YiiC9xfekPeU05F2FsYWxYK0nmnEP0t +ydgDFeKl2FI2vUhr2oOaiTs5VlNhMz43diX9AJzjmO4nrePsuA/T3wj8rSzhS9kD +9IF6GkZ+y+1Yyzf8NWxPfFCL0K4B5/+pGDY5BETX+BHq4kKCGjWVWz9Whd9MeaJb +4buycT9RyKZrmSEe/fkCAwEAATANBgkqhkiG9w0BAQsFAAOCAYEAjuAYYpA337xi +Uem4MTmCB68VVEPxVeiR3geTqZdk42ep6ATfalbAIAsqzTsh5QPU5FZByrZauOWA +6m5HLmlEY3UQmI6l1P9KcOAIVfHQ0uVIpREuEaiFJlA2pif/Epk+Go/jp+yKPHms +/IT/ZhZTzUCM3xbcan9rDA779pgi/NqYSHJ1EljiD+Wt8jDk67hZAjHum9b79UNs +bJqB4wHrNkoyOZZnmW88nDeJGvBpoeo/zsy4xi20E23oBP7ti7QVEvsvaZtJ5L7S +mysHP03fIkfquXswZ8Xl5wS3Vjr82wx9LOGunzZzFF4awRrsIuovvxrTBTD/NNHA +v0Mm7UC0I8A27mlpufneN4TFcXmYW0KZxkiLbcrXtOicqgRyfEB1UC2C8RAPmeX3 +VGM+odFNhJjkCecms4/xpSqj13CE6S6ci2+osfiMWm5uBw6wAfPt/5rPrvy50dWx +J13vign9EqLAy7aVRzK8ghu1bOLlXV5Hp6kwwMYYqZBV5A0xOuSj +-----END CERTIFICATE----- \ No newline at end of file diff --git a/docker/ssp-debug-sp/certificates/sp.key b/docker/ssp-debug-sp/certificates/sp.key new file mode 100644 index 0000000..b400366 --- /dev/null +++ b/docker/ssp-debug-sp/certificates/sp.key @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/docker/ssp-debug-sp/certificates/ssp.crt b/docker/ssp-debug-sp/certificates/ssp.crt new file mode 100644 index 0000000..1201546 --- /dev/null +++ b/docker/ssp-debug-sp/certificates/ssp.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID4zCCAksCFE/RXnB+y6e2zlC0Zpi7Pl6GbyuAMA0GCSqGSIb3DQEBCwUAMC4x +EzARBgNVBAMMClJBIFNBTUwgU1AxFzAVBgNVBAoMDkRldmVsb3BtZW50IFZNMB4X +DTIxMDQyMDA3MDIyM1oXDTI2MDQxOTA3MDIyM1owLjETMBEGA1UEAwwKUkEgU0FN +TCBTUDEXMBUGA1UECgwORGV2ZWxvcG1lbnQgVk0wggGiMA0GCSqGSIb3DQEBAQUA +A4IBjwAwggGKAoIBgQCyMqGyevrF/Ms8fsGQdz6fqzCA8T/QKC9Jb3m7EpQOp/OM +q/qBv4gjtFf0/bAun2N/u6zZOlPk61iVWRbxIet/O9BAoqRhtT6PHQVcReXR1F3+ +Dk2vH8+QyZwnWGENwh16BYuirIeWQuEgfVDUpSg2MBjkHjZmpF8Dxn6d485qwrdb +FZN+z3QPtxNaNu1FBktsgPNjlpE7HNB9xcGy4DlgTIP+80nKgM+Kdopw9FVk71bf +KKHp1m9qSSbFI+drtbtFJ7OPqFYDs9gJEY8ivALID1ERNQkAPImr/EIPiazHc4nk +Qfi4Kt5ohsvGufdCxYtOUGxjcrkq9oJX5YiiC9xfekPeU05F2FsYWxYK0nmnEP0t +ydgDFeKl2FI2vUhr2oOaiTs5VlNhMz43diX9AJzjmO4nrePsuA/T3wj8rSzhS9kD +9IF6GkZ+y+1Yyzf8NWxPfFCL0K4B5/+pGDY5BETX+BHq4kKCGjWVWz9Whd9MeaJb +4buycT9RyKZrmSEe/fkCAwEAATANBgkqhkiG9w0BAQsFAAOCAYEAjuAYYpA337xi +Uem4MTmCB68VVEPxVeiR3geTqZdk42ep6ATfalbAIAsqzTsh5QPU5FZByrZauOWA +6m5HLmlEY3UQmI6l1P9KcOAIVfHQ0uVIpREuEaiFJlA2pif/Epk+Go/jp+yKPHms +/IT/ZhZTzUCM3xbcan9rDA779pgi/NqYSHJ1EljiD+Wt8jDk67hZAjHum9b79UNs +bJqB4wHrNkoyOZZnmW88nDeJGvBpoeo/zsy4xi20E23oBP7ti7QVEvsvaZtJ5L7S +mysHP03fIkfquXswZ8Xl5wS3Vjr82wx9LOGunzZzFF4awRrsIuovvxrTBTD/NNHA +v0Mm7UC0I8A27mlpufneN4TFcXmYW0KZxkiLbcrXtOicqgRyfEB1UC2C8RAPmeX3 +VGM+odFNhJjkCecms4/xpSqj13CE6S6ci2+osfiMWm5uBw6wAfPt/5rPrvy50dWx +J13vign9EqLAy7aVRzK8ghu1bOLlXV5Hp6kwwMYYqZBV5A0xOuSj +-----END CERTIFICATE----- \ No newline at end of file diff --git a/docker/ssp-debug-sp/certificates/ssp.key b/docker/ssp-debug-sp/certificates/ssp.key new file mode 100644 index 0000000..b400366 --- /dev/null +++ b/docker/ssp-debug-sp/certificates/ssp.key @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/docker/ssp-debug-sp/conf/DebugSP/default-enable b/docker/ssp-debug-sp/conf/DebugSP/default-enable new file mode 100644 index 0000000..e69de29 diff --git a/docker/ssp-debug-sp/conf/DebugSP/lib/Auth/Source/SP.php b/docker/ssp-debug-sp/conf/DebugSP/lib/Auth/Source/SP.php new file mode 100644 index 0000000..6dbdc6d --- /dev/null +++ b/docker/ssp-debug-sp/conf/DebugSP/lib/Auth/Source/SP.php @@ -0,0 +1,83 @@ + 'https://...', + 'DebugSP:extraPOSTvars' => array( + 'SomePOSTvariable' => 'SomeValue', + 'AnotherPOSTvariable' => 'AnotherValue' + ), + ); + $as->login($params); +*/ + +// Extend from the SimpleSAMLphp SAML 2.0 authentication source "saml:SP" +class sspmod_DebugSP_Auth_Source_SP extends sspmod_saml_Auth_Source_SP { + + public function __construct($info, $config) { + parent::__construct($info, $config); + } + + public function sendSAML2AuthnRequest(array &$state, \SAML2\Binding $binding, \SAML2\AuthnRequest $ar) { + + if ( isset( $state['DebugSP:AssertionConsumerServiceURL'] ) ) { + // Set the AssertionConsumerServiceURL in the AuthnRequest + $ar->setAssertionConsumerServiceURL( $state['DebugSP:AssertionConsumerServiceURL'] ); + } + + if ($binding instanceof \SAML2\HTTPPost) { + // replicate \SAML2\HTTPPost::send(Message $message) so we can set additional POST variables + $destination = $ar->getDestination(); + $relayState = $ar->getRelayState(); + $post = array(); + + // Set extra POST variables + if (isset($state['DebugSP:extraPOSTvars'])) { + assert(is_array($state['DebugSP:extraPOSTvars']), 'DebugSP:extraPOSTvars must be array()'); + foreach ($state['DebugSP:extraPOSTvars'] as $key => $value) { + $post[$key] = $value; + } + } + + // Create SAMLRequest + $msgStr = $ar->toSignedXML(); + $msgStr = $msgStr->ownerDocument->saveXML($msgStr); + + \SAML2\Utils::getContainer()->debugMessage($msgStr, 'out'); + + $post['SAMLRequest'] = base64_encode($msgStr); + + if ($relayState !== null) { + $post['RelayState'] = $relayState; + } + + \SAML2\Utils::getContainer()->postRedirect($destination, $post); + + return; + } + + // Use partent implementation + parent::sendSAML2AuthnRequest($state, $binding, $ar); + } +} diff --git a/docker/ssp-debug-sp/conf/DebugSP/www/sp/saml2-acs.php b/docker/ssp-debug-sp/conf/DebugSP/www/sp/saml2-acs.php new file mode 100644 index 0000000..5ee7952 --- /dev/null +++ b/docker/ssp-debug-sp/conf/DebugSP/www/sp/saml2-acs.php @@ -0,0 +1,26 @@ + 'urn:mace:dir:attribute-def:sn', + 'givenName' => 'urn:mace:dir:attribute-def:givenName', + 'cn' => 'urn:mace:dir:attribute-def:cn', + 'displayName' => 'urn:mace:dir:attribute-def:displayName', + 'mail' => 'urn:mace:dir:attribute-def:mail', + 'uid' => 'urn:mace:dir:attribute-def:uid', + 'eduPersonAffiliation' => 'urn:mace:dir:attribute-def:eduPersonAffiliation', + 'eduPersonEntitlement' => 'urn:mace:dir:attribute-def:eduPersonEntitlement', + 'eduPersonPrincipalName' => 'urn:mace:dir:attribute-def:eduPersonPrincipalName', + 'preferredLanguage' => 'urn:mace:dir:attribute-def:preferredLanguage', + 'eduPersonTargetedID' => 'urn:mace:dir:attribute-def:eduPersonTargetedID', + // urn:mace:terena.org + 'schacHomeOrganization' => 'urn:mace:terena.org:attribute-def:schacHomeOrganization', + 'schacHomeOrganizationType' => 'urn:mace:terena.org:attribute-def:schacHomeOrganizationType', +); diff --git a/docker/ssp-debug-sp/conf/accountgen.inc b/docker/ssp-debug-sp/conf/accountgen.inc new file mode 100644 index 0000000..fde731f --- /dev/null +++ b/docker/ssp-debug-sp/conf/accountgen.inc @@ -0,0 +1,85 @@ + 'urn:collab:person:'.$scope.':'.$uid, + 'uid' => array($uid), + 'eduPersonPrincipalName' => $uid.'@'.$scope, + 'givenName' => 'gn-'.$uid, + 'sn' => 'sn-'.$scope, + 'cn' => $uid.' '.$scope, + 'mail' => str_replace('@', '+'.$uid.'@', $email), + 'displayName' => 'd-'.$uid.' '.$scope, + 'eduPersonAffiliation' => array('student'), + 'schacHomeOrganization' => $scope, + 'schacHomeOrganizationType' => 'urn:mace:terena.org:schac:homeOrganizationType:int:university', + ); + $config['example-userpass'][$uid.':'.$uid]=$account; + } + + // Without SHO + $uid=$prefix.'-nosho'; + $account=array( + 'NameID' => 'urn:collab:person:'.$scope.':'.$uid, + 'uid' => array($uid), + 'eduPersonPrincipalName' => $uid.'@'.$scope, + 'givenName' => 'gn-'.$uid, + 'sn' => 'sn-'.$scope, + 'cn' => $uid.' '.$scope, + 'mail' => str_replace('@', '+'.$uid.'@', $email), + 'displayName' => 'd-'.$uid.' '.$scope, + 'eduPersonAffiliation' => array('student'), + //'schacHomeOrganization' => $scope, + 'schacHomeOrganizationType' => 'urn:mace:terena.org:schac:homeOrganizationType:int:university', + ); + $config['example-userpass'][$uid.':'.$uid]=$account; + + // Without mail + $uid=$prefix.'-nomail'; + $account=array( + 'NameID' => 'urn:collab:person:'.$scope.':'.$uid, + 'uid' => array($uid), + 'eduPersonPrincipalName' => $uid.'@'.$scope, + 'givenName' => 'gn-'.$uid, + 'sn' => 'sn-'.$scope, + 'cn' => $uid.' '.$scope, + //'mail' => str_replace('@', '+'.$uid.'@', $email), + 'displayName' => 'd-'.$uid.' '.$scope, + 'eduPersonAffiliation' => array('student'), + 'schacHomeOrganization' => $scope, + 'schacHomeOrganizationType' => 'urn:mace:terena.org:schac:homeOrganizationType:int:university', + ); + $config['example-userpass'][$uid.':'.$uid]=$account; + + // Without cn + $uid=$prefix.'-nocn'; + $account=array( + 'NameID' => 'urn:collab:person:'.$scope.':'.$uid, + 'uid' => array($uid), + 'eduPersonPrincipalName' => $uid.'@'.$scope, + 'givenName' => 'gn-'.$uid, + 'sn' => 'sn-'.$scope, + //'cn' => $uid.' '.$scope, + 'mail' => str_replace('@', '+'.$uid.'@', $email), + 'displayName' => 'd-'.$uid.' '.$scope, + 'eduPersonAffiliation' => array('student'), + 'schacHomeOrganization' => $scope, + 'schacHomeOrganizationType' => 'urn:mace:terena.org:schac:homeOrganizationType:int:university', + ); + $config['example-userpass'][$uid.':'.$uid]=$account; + +} \ No newline at end of file diff --git a/docker/ssp-debug-sp/conf/authsources.php b/docker/ssp-debug-sp/conf/authsources.php new file mode 100644 index 0000000..66797cd --- /dev/null +++ b/docker/ssp-debug-sp/conf/authsources.php @@ -0,0 +1,218 @@ + array( + // The default is to use core:AdminPassword, but it can be replaced with + // any authentication source. + + 'core:AdminPassword', + ), + + 'example-userpass' => array( + 'exampleauth:UserPass', + + 'admin:admin' => array( + 'NameID' => 'urn:collab:person:stepup.example.com:admin', + 'uid' => array('admin'), + 'mail' => 'admin@stepup.example.com', + 'eduPersonPrincipalName' => 'admin@stepup.example.com', + 'givenName' => 'Admin', + 'sn' => 'Admin', + 'cn' => 'Admin', + 'displayName' => 'Admin', + 'eduPersonAffiliation' => array('employee'), + 'schacHomeOrganization' => 'stepup.example.com', + 'schacHomeOrganizationType' => 'urn:mace:terena.org:schac:homeOrganizationType:int:university', + ), + + 'michiel:michiel' => array( + 'NameID' => 'urn:collab:person:stepup.example.com:michiel', + 'uid' => array('michiel'), + 'mail' => 'michiel@ibuildings.nl', + 'eduPersonPrincipalName' => 'michiel@stepup.example.com', + 'givenName' => 'Michiel', + 'sn' => 'Kodde', + 'cn' => 'JC', + 'displayName' => 'JC', + 'eduPersonAffiliation' => array('employee'), + 'schacHomeOrganization' => 'stepup.example.com', + 'schacHomeOrganizationType' => 'urn:mace:terena.org:schac:homeOrganizationType:int:NREN', + ), + + // Test accounts are added using account_gen below + + ), + + // An authentication source which can authenticate against both SAML 2.0 + // and Shibboleth 1.3 IdPs. + 'default-sp' => array( + 'DebugSP:SP', + + // The entity ID of this SP. + // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. + 'entityID' => 'https://ssp.stepup.example.com/module.php/saml/sp/metadata.php/default-sp', + + // The entity ID of the IdP this should SP should contact. + // Can be NULL/unset, in which case the user will be shown a list of available IdPs. + 'idp' => NULL, + + // The URL to the discovery service. + // Can be NULL/unset, in which case a builtin discovery service will be used. + 'discoURL' => NULL, + + 'certificate' => 'sp.crt', + 'privatekey' => 'sp.key', + + // See end of file for request.sign and signature alg config! + ), + 'second-sp' => array( + 'DebugSP:SP', + + // The entity ID of this SP. + // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. + 'entityID' => 'https://ssp.stepup.example.com/module.php/saml/sp/metadata.php/second-sp', + + // The entity ID of the IdP this should SP should contact. + // Can be NULL/unset, in which case the user will be shown a list of available IdPs. + 'idp' => NULL, + + // The URL to the discovery service. + // Can be NULL/unset, in which case a builtin discovery service will be used. + 'discoURL' => NULL, + + 'certificate' => 'sp.crt', + 'privatekey' => 'sp.key', + + // See end of file for request.sign and signature.algorithm config! + //'redirect.sign' => TRUE, + //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + ), + 'third-sp' => array( + 'DebugSP:SP', + + // The entity ID of this SP. + // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. + 'entityID' => 'https://ssp.stepup.example.com/module.php/saml/sp/metadata.php/third-sp', + + // The entity ID of the IdP this should SP should contact. + // Can be NULL/unset, in which case the user will be shown a list of available IdPs. + 'idp' => NULL, + + // The URL to the discovery service. + // Can be NULL/unset, in which case a builtin discovery service will be used. + 'discoURL' => NULL, + + 'certificate' => 'sp.crt', + 'privatekey' => 'sp.key', + + // See end of file for request.sign and signature.algorithm config! + //'redirect.sign' => TRUE, + //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + ), + 'fourth-sp' => array( + 'DebugSP:SP', + + // The entity ID of this SP. + // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. + 'entityID' => 'https://ssp.stepup.example.com/module.php/saml/sp/metadata.php/fourth-sp', + + // The entity ID of the IdP this should SP should contact. + // Can be NULL/unset, in which case the user will be shown a list of available IdPs. + 'idp' => NULL, + + // The URL to the discovery service. + // Can be NULL/unset, in which case a builtin discovery service will be used. + 'discoURL' => NULL, + + 'certificate' => 'sp.crt', + 'privatekey' => 'sp.key', + + // See end of file for request.sign and signature.algorithm config! + //'redirect.sign' => TRUE, + //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + ), + +); + + +// Use the the global variables that were set in sp.php to modify the hosted SP configuration on the fly +// They won't always be set (e.g. when SSP is used as IdP) so we use isset() to reduce notices + +if ( isset($GLOBALS['gSP_redirect_sign']) ) { + $config['default-sp']['redirect.sign'] = $GLOBALS['gSP_redirect_sign'] ? TRUE : FALSE; + $config['second-sp']['redirect.sign'] = $GLOBALS['gSP_redirect_sign'] ? TRUE : FALSE; + $config['third-sp']['redirect.sign'] = $GLOBALS['gSP_redirect_sign'] ? TRUE : FALSE; + $config['fourth-sp']['redirect.sign'] = $GLOBALS['gSP_redirect_sign'] ? TRUE : FALSE; +} +if ( isset($GLOBALS['gSP_signature_algorithm']) && strlen($GLOBALS['gSP_signature_algorithm']) > 0 ) { + $config['default-sp']['signature.algorithm'] = $GLOBALS['gSP_signature_algorithm']; + $config['second-sp']['signature.algorithm'] = $GLOBALS['gSP_signature_algorithm']; + $config['third-sp']['signature.algorithm'] = $GLOBALS['gSP_signature_algorithm']; + $config['fourth-sp']['signature.algorithm'] = $GLOBALS['gSP_signature_algorithm']; +} +if ( isset($GLOBALS['gSP_secondary_key']) && $GLOBALS['gSP_secondary_key']) { + $config['default-sp']['certificate']='sp2.crt'; + $config['default-sp']['privatekey']='sp2.key'; + $config['second-sp']['certificate']='sp2.crt'; + $config['second-sp']['privatekey']='sp2.key'; + $config['third-sp']['certificate']='sp2.crt'; + $config['third-sp']['privatekey']='sp2.key'; + $config['fourth-sp']['certificate']='sp2.crt'; + $config['fourth-sp']['privatekey']='sp2.key'; +} + +if ( isset($GLOBALS['gSP_ProtocolBinding']) ) { + $config['default-sp']['ProtocolBinding'] = $GLOBALS['gSP_ProtocolBinding']; + $config['second-sp']['ProtocolBinding'] = $GLOBALS['gSP_ProtocolBinding']; + $config['third-sp']['ProtocolBinding'] = $GLOBALS['gSP_ProtocolBinding']; + $config['fourth-sp']['ProtocolBinding'] = $GLOBALS['gSP_ProtocolBinding']; +} + +# In test mode (testcookie is present) use the test certificates for the SP's +if ( isset($_COOKIE['testcookie']) ) { + $config['default-sp']['certificate'] = '/vagrant/deploy/tests/behat/fixtures/test_public_key.crt'; + $config['default-sp']['privatekey'] = '/vagrant/deploy/tests/behat/fixtures/test_private_key.key'; + $config['second-sp']['certificate'] = '/vagrant/deploy/tests/behat/fixtures/test_public_key.crt'; + $config['second-sp']['privatekey'] = '/vagrant/deploy/tests/behat/fixtures/test_private_key.key'; + $config['third-sp']['certificate'] = '/vagrant/deploy/tests/behat/fixtures/test_public_key.crt'; + $config['third-sp']['privatekey'] = '/vagrant/deploy/tests/behat/fixtures/test_private_key.key'; + $config['fourth-sp']['certificate'] = '/vagrant/deploy/tests/behat/fixtures/test_public_key.crt'; + $config['fourth-sp']['privatekey'] = '/vagrant/deploy/tests/behat/fixtures/test_private_key.key'; +} + +// Accounts for accountgen script +// Allows read email addresses to be used for multiple accounts +// The accountsgen scrip mangles the email address to e.g. joe+slug@stepup.example.com +$accounts=array( + // username => email (this can be a real email address) + 'user' => 'user@stepup.example.com', + 'joe' => 'joe@stepup.example.com', + 'jane' => 'jane@stepup.example.com', +); + +// List of varieties of account to generate +$slugs=array( + "1", "2", "3", "4", "5", "sms", "-yk", "-tiqr", "-u2f", "-bio", "-ra", "-raa" +); + +// for a username 'joe' this will generate joe-a1, joe-a2, ..., joe-a-yk, ... joe-a-raa +// for a username 'joe' this will generate joe-b1, joe-b2, ..., joe-b-yk, ... joe-b-raa +// ... +// For all accounts the username is equal to the password. E.g. "joe-a1" / "joe-a1" +foreach ($accounts as $user => $email) { + // username , email, schachomeorganization + account_gen($config, "${user}-", $email, 'stepup.example.com', $slugs); + account_gen($config, "${user}-a", $email, 'institution-a.example.com', $slugs); + account_gen($config, "${user}-b", $email, 'institution-b.example.com', $slugs); + account_gen($config, "${user}-c", $email, 'institution-c.example.com', $slugs); + account_gen($config, "${user}-d", $email, 'Institution-D.EXAMPLE.COM', $slugs); // Note: uppercase "I" and "D" + account_gen($config, "${user}-e", $email, 'Institution-e.example.com', $slugs); + account_gen($config, "${user}-f", $email, 'Institution-f.example.com', $slugs); +} diff --git a/docker/ssp-debug-sp/conf/config.php b/docker/ssp-debug-sp/conf/config.php new file mode 100644 index 0000000..0fe2ff3 --- /dev/null +++ b/docker/ssp-debug-sp/conf/config.php @@ -0,0 +1,597 @@ + 'https://ssp.stepup.example.com/', + + /** + * Locations on the filesystem: + */ + 'certdir' => '/app/cert/', + 'loggingdir' => '/var/log/simplesamlphp/', + 'datadir' => '/var/lib/simplesamlphp/data/', + 'metadatadir' => '/app/metadata/', + 'attributenamemapdir' => '/app/attributemap/', + + /* + * A directory where simpleSAMLphp can save temporary files. + * + * SimpleSAMLphp will attempt to create this directory if it doesn't exist. + */ + 'tempdir' => '/tmp/simplesaml', + + + /* + * If you enable this option, simpleSAMLphp will log all sent and received messages + * to the log file. + * + * This option also enables logging of the messages that are encrypted and decrypted. + * + * Note: The messages are logged with the DEBUG log level, so you also need to set + * the 'logging.level' option to LOG_DEBUG. + */ + 'debug' => FALSE, + 'showerrors' => TRUE, + + /** + * Custom error show function called from SimpleSAML_Error_Error::show. + * See docs/simplesamlphp-errorhandling.txt for function code example. + * + * Example: + * 'errors.show_function' => array('sspmod_example_Error_Show', 'show'), + */ + + /** + * This option allows you to enable validation of XML data against its + * schemas. A warning will be written to the log if validation fails. + */ + 'debug.validatexml' => FALSE, + + /** + * This password must be kept secret, and modified from the default value 123. + * This password will give access to the installation page of simpleSAMLphp with + * metadata listing and diagnostics pages. + * You can also put a hash here; run "bin/pwgen.php" to generate one. + */ + 'auth.adminpassword' => 'admin', + 'admin.protectindexpage' => false, + 'admin.protectmetadata' => false, + + /** + * This is a secret salt used by simpleSAMLphp when it needs to generate a secure hash + * of a value. It must be changed from its default value to a secret value. The value of + * 'secretsalt' can be any valid string of any length. + * + * A possible way to generate a random salt is by running the following command from a unix shell: + * tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' /dev/null;echo + */ + 'secretsalt' => 'CHANGE_ME_for_testing_only', + + /* + * Some information about the technical persons running this installation. + * The email address will be used as the recipient address for error reports, and + * also as the technical contact in generated metadata. + */ + 'technicalcontact_name' => 'John Doe', + 'technicalcontact_email' => 'jdoe@stepup.example.com', + + /* + * The timezone of the server. This option should be set to the timezone you want + * simpleSAMLphp to report the time in. The default is to guess the timezone based + * on your system timezone. + * + * See this page for a list of valid timezones: http://php.net/manual/en/timezones.php + */ + 'timezone' => 'Europe/Amsterdam', + + /* + * Logging. + * + * define the minimum log level to log + * SimpleSAML_Logger::ERR No statistics, only errors + * SimpleSAML_Logger::WARNING No statistics, only warnings/errors + * SimpleSAML_Logger::NOTICE Statistics and errors + * SimpleSAML_Logger::INFO Verbose logs + * SimpleSAML_Logger::DEBUG Full debug logs - not reccomended for production + * + * Choose logging handler. + * + * Options: [syslog,file,errorlog] + * + */ + 'logging.level' => SimpleSAML\Logger::NOTICE, + 'logging.handler' => 'errorlog', + + /* + * Choose which facility should be used when logging with syslog. + * + * These can be used for filtering the syslog output from simpleSAMLphp into its + * own file by configuring the syslog daemon. + * + * See the documentation for openlog (http://php.net/manual/en/function.openlog.php) for available + * facilities. Note that only LOG_USER is valid on windows. + * + * The default is to use LOG_LOCAL5 if available, and fall back to LOG_USER if not. + */ + 'logging.facility' => defined('LOG_LOCAL5') ? constant('LOG_LOCAL5') : LOG_USER, + + /* + * The process name that should be used when logging to syslog. + * The value is also written out by the other logging handlers. + */ + 'logging.processname' => 'simplesamlphp', + + /* Logging: file - Logfilename in the loggingdir from above. + */ + 'logging.logfile' => 'simplesamlphp.log', + + /* (New) statistics output configuration. + * + * This is an array of outputs. Each output has at least a 'class' option, which + * selects the output. + */ + 'statistics.out' => array( + // Log statistics to the normal log. + /* + array( + 'class' => 'core:Log', + 'level' => 'notice', + ), + */ + // Log statistics to files in a directory. One file per day. + /* + array( + 'class' => 'core:File', + 'directory' => '/var/log/stats', + ), + */ + ), + + + /* + * Enable + * + * Which functionality in simpleSAMLphp do you want to enable. Normally you would enable only + * one of the functionalities below, but in some cases you could run multiple functionalities. + * In example when you are setting up a federation bridge. + */ + 'enable.saml20-idp' => true, + 'enable.shib13-idp' => false, + 'enable.adfs-idp' => false, + 'enable.wsfed-sp' => false, + 'enable.authmemcookie' => false, + + /* + * This value is the duration of the session in seconds. Make sure that the time duration of + * cookies both at the SP and the IdP exceeds this duration. + */ + 'session.duration' => 8 * (60*60), // 8 hours. + 'session.requestcache' => 4 * (60*60), // 4 hours + + /* + * Sets the duration, in seconds, data should be stored in the datastore. As the datastore is used for + * login and logout requests, thid option will control the maximum time these operations can take. + * The default is 4 hours (4*60*60) seconds, which should be more than enough for these operations. + */ + 'session.datastore.timeout' => (4*60*60), // 4 hours + + /* + * Sets the duration, in seconds, auth state should be stored. + */ + 'session.state.timeout' => (60*60), // 1 hour + + /* + * Option to override the default settings for the session cookie name + */ + 'session.cookie.name' => 'SimpleSAMLSessionID', + + /* + * Expiration time for the session cookie, in seconds. + * + * Defaults to 0, which means that the cookie expires when the browser is closed. + * + * Example: + * 'session.cookie.lifetime' => 30*60, + */ + 'session.cookie.lifetime' => 0, + + /* + * Limit the path of the cookies. + * + * Can be used to limit the path of the cookies to a specific subdirectory. + * + * Example: + * 'session.cookie.path' => '/simplesaml/', + */ + 'session.cookie.path' => '/', + + /* + * Cookie domain. + * + * Can be used to make the session cookie available to several domains. + * + * Example: + * 'session.cookie.domain' => '.example.org', + */ + 'session.cookie.domain' => NULL, + + /* + * Set the secure flag in the cookie. + * + * Set this to TRUE if the user only accesses your service + * through https. If the user can access the service through + * both http and https, this must be set to FALSE. + */ + 'session.cookie.secure' => TRUE, + + /* + * When set to FALSE fallback to transient session on session initialization + * failure, throw exception otherwise. + */ + 'session.disable_fallback' => TRUE, + + /* + * Enable secure POST from HTTPS to HTTP. + * + * If you have some SP's on HTTP and IdP is normally on HTTPS, this option + * enables secure POSTing to HTTP endpoint without warning from browser. + * + * For this to work, module.php/core/postredirect.php must be accessible + * also via HTTP on IdP, e.g. if your IdP is on + * https://idp.example.org/ssp/, then + * http://idp.example.org/ssp/module.php/core/postredirect.php must be accessible. + */ + 'enable.http_post' => FALSE, + + /* + * Options to override the default settings for php sessions. + */ + 'session.phpsession.cookiename' => null, + 'session.phpsession.savepath' => null, + 'session.phpsession.httponly' => TRUE, + + /* + * Option to override the default settings for the auth token cookie + */ + 'session.authtoken.cookiename' => 'SimpleSAMLAuthToken', + + /* + * Languages available, RTL languages, and what language is default + */ + 'language.available' => array('en', 'nl'), + 'language.rtl' => array (), // array('ar','dv','fa','ur','he'), + 'language.default' => 'en', + + /** + * Custom getLanguage function called from SimpleSAML_XHTML_Template::getLanguage(). + * Function should return language code of one of the available languages or NULL. + * See SimpleSAML_XHTML_Template::getLanguage() source code for more info. + * + * This option can be used to implement a custom function for determining + * the default language for the user. + * + * Example: + * 'language.get_language_function' => array('sspmod_example_Template', 'getLanguage'), + */ + + /* + * Extra dictionary for attribute names. + * This can be used to define local attributes. + * + * The format of the parameter is a string with :. + * + * Specifying this option will cause us to look for modules//dictionaries/.definition.json + * The dictionary should look something like: + * + * { + * "firstattribute": { + * "en": "English name", + * "no": "Norwegian name" + * }, + * "secondattribute": { + * "en": "English name", + * "no": "Norwegian name" + * } + * } + * + * Note that all attribute names in the dictionary must in lowercase. + * + * Example: 'attributes.extradictionary' => 'ourmodule:ourattributes', + */ + 'attributes.extradictionary' => NULL, + + /* + * Which theme directory should be used? + */ + 'theme.use' => 'default', + + + /* + * Default IdP for WS-Fed. + */ + 'default-wsfed-idp' => 'urn:federation:pingfederate:localhost', + + /* + * Whether the discovery service should allow the user to save his choice of IdP. + */ + 'idpdisco.enableremember' => TRUE, + 'idpdisco.rememberchecked' => TRUE, + + // Disco service only accepts entities it knows. + 'idpdisco.validate' => TRUE, + + 'idpdisco.extDiscoveryStorage' => NULL, + + /* + * IdP Discovery service look configuration. + * Wether to display a list of idp or to display a dropdown box. For many IdP' a dropdown box + * gives the best use experience. + * + * When using dropdown box a cookie is used to highlight the previously chosen IdP in the dropdown. + * This makes it easier for the user to choose the IdP + * + * Options: [links,dropdown] + * + */ + 'idpdisco.layout' => 'dropdown', + + /* + * Whether simpleSAMLphp should sign the response or the assertion in SAML 1.1 authentication + * responses. + * + * The default is to sign the assertion element, but that can be overridden by setting this + * option to TRUE. It can also be overridden on a pr. SP basis by adding an option with the + * same name to the metadata of the SP. + */ + 'shib13.signresponse' => TRUE, + + + + /* + * Authentication processing filters that will be executed for all IdPs + * Both Shibboleth and SAML 2.0 + */ + 'authproc.idp' => array( + + ), + + /* + * Authentication processing filters that will be executed for all SPs + * Both Shibboleth and SAML 2.0 + */ + 'authproc.sp' => array( + /* + 10 => array( + 'class' => 'core:AttributeMap', 'removeurnprefix' + ), + */ + + /* + * Generate the 'group' attribute populated from other variables, including eduPersonAffiliation. + */ + 60 => array('class' => 'core:GenerateGroups', 'eduPersonAffiliation'), + // All users will be members of 'users' and 'members' + 61 => array('class' => 'core:AttributeAdd', 'groups' => array('users', 'members')), + + // Adopts language from attribute to use in UI + 90 => 'core:LanguageAdaptor', + + ), + + + /* + * This option configures the metadata sources. The metadata sources is given as an array with + * different metadata sources. When searching for metadata, simpleSAMPphp will search through + * the array from start to end. + * + * Each element in the array is an associative array which configures the metadata source. + * The type of the metadata source is given by the 'type' element. For each type we have + * different configuration options. + * + * Flat file metadata handler: + * - 'type': This is always 'flatfile'. + * - 'directory': The directory we will load the metadata files from. The default value for + * this option is the value of the 'metadatadir' configuration option, or + * 'metadata/' if that option is unset. + * + * XML metadata handler: + * This metadata handler parses an XML file with either an EntityDescriptor element or an + * EntitiesDescriptor element. The XML file may be stored locally, or (for debugging) on a remote + * web server. + * The XML hetadata handler defines the following options: + * - 'type': This is always 'xml'. + * - 'file': Path to the XML file with the metadata. + * - 'url': The url to fetch metadata from. THIS IS ONLY FOR DEBUGGING - THERE IS NO CACHING OF THE RESPONSE. + * + * + * Examples: + * + * This example defines two flatfile sources. One is the default metadata directory, the other + * is a metadata directory with autogenerated metadata files. + * + * 'metadata.sources' => array( + * array('type' => 'flatfile'), + * array('type' => 'flatfile', 'directory' => 'metadata-generated'), + * ), + * + * This example defines a flatfile source and an XML source. + * 'metadata.sources' => array( + * array('type' => 'flatfile'), + * array('type' => 'xml', 'file' => 'idp.example.org-idpMeta.xml'), + * ), + * + * + * Default: + * 'metadata.sources' => array( + * array('type' => 'flatfile') + * ), + */ + 'metadata.sources' => array( + array('type' => 'flatfile'), + ), + + + /* + * Configure the datastore for simpleSAMLphp. + * + * - 'phpsession': Limited datastore, which uses the PHP session. + * - 'memcache': Key-value datastore, based on memcache. + * - 'sql': SQL datastore, using PDO. + * + * The default datastore is 'phpsession'. + * + * (This option replaces the old 'session.handler'-option.) + */ + //'store.type' => 'phpsession', + 'store.type' => 'phpsession', + + + /* + * The DSN the sql datastore should connect to. + * + * See http://www.php.net/manual/en/pdo.drivers.php for the various + * syntaxes. + */ + 'store.sql.dsn' => 'sqlite:/path/to/sqlitedatabase.sq3', + + /* + * The username and password to use when connecting to the database. + */ + 'store.sql.username' => NULL, + 'store.sql.password' => NULL, + + /* + * The prefix we should use on our tables. + */ + 'store.sql.prefix' => 'simpleSAMLphp', + + + /* + * Configuration for the MemcacheStore class. This allows you to store + * multiple redudant copies of sessions on different memcache servers. + * + * 'memcache_store.servers' is an array of server groups. Every data + * item will be mirrored in every server group. + * + * Each server group is an array of servers. The data items will be + * load-balanced between all servers in each server group. + * + * Each server is an array of parameters for the server. The following + * options are available: + * - 'hostname': This is the hostname or ip address where the + * memcache server runs. This is the only required option. + * - 'port': This is the port number of the memcache server. If this + * option isn't set, then we will use the 'memcache.default_port' + * ini setting. This is 11211 by default. + * - 'weight': This sets the weight of this server in this server + * group. http://php.net/manual/en/function.Memcache-addServer.php + * contains more information about the weight option. + * - 'timeout': The timeout for this server. By default, the timeout + * is 3 seconds. + * + * Example of redudant configuration with load balancing: + * This configuration makes it possible to lose both servers in the + * a-group or both servers in the b-group without losing any sessions. + * Note that sessions will be lost if one server is lost from both the + * a-group and the b-group. + * + * 'memcache_store.servers' => array( + * array( + * array('hostname' => 'mc_a1'), + * array('hostname' => 'mc_a2'), + * ), + * array( + * array('hostname' => 'mc_b1'), + * array('hostname' => 'mc_b2'), + * ), + * ), + * + * Example of simple configuration with only one memcache server, + * running on the same computer as the web server: + * Note that all sessions will be lost if the memcache server crashes. + * + * 'memcache_store.servers' => array( + * array( + * array('hostname' => 'localhost'), + * ), + * ), + * + */ + 'memcache_store.servers' => array( + array( + array('hostname' => 'localhost'), + ), + ), + + + /* + * This value is the duration data should be stored in memcache. Data + * will be dropped from the memcache servers when this time expires. + * The time will be reset every time the data is written to the + * memcache servers. + * + * This value should always be larger than the 'session.duration' + * option. Not doing this may result in the session being deleted from + * the memcache servers while it is still in use. + * + * Set this value to 0 if you don't want data to expire. + * + * Note: The oldest data will always be deleted if the memcache server + * runs out of storage space. + */ + 'memcache_store.expires' => 36 * (60*60), // 36 hours. + + + /* + * Should signing of generated metadata be enabled by default. + * + * Metadata signing can also be enabled for a individual SP or IdP by setting the + * same option in the metadata for the SP or IdP. + */ + 'metadata.sign.enable' => FALSE, + + /* + * The default key & certificate which should be used to sign generated metadata. These + * are files stored in the cert dir. + * These values can be overridden by the options with the same names in the SP or + * IdP metadata. + * + * If these aren't specified here or in the metadata for the SP or IdP, then + * the 'certificate' and 'privatekey' option in the metadata will be used. + * if those aren't set, signing of metadata will fail. + */ + 'metadata.sign.privatekey' => NULL, + 'metadata.sign.privatekey_pass' => NULL, + 'metadata.sign.certificate' => NULL, + + + /* + * Proxy to use for retrieving URLs. + * + * Example: + * 'proxy' => 'tcp://proxy.example.com:5100' + */ + 'proxy' => NULL, + +); diff --git a/docker/ssp-debug-sp/conf/nginx.conf b/docker/ssp-debug-sp/conf/nginx.conf new file mode 100644 index 0000000..b8b0146 --- /dev/null +++ b/docker/ssp-debug-sp/conf/nginx.conf @@ -0,0 +1,23 @@ +server { + listen 443 default_server; + + access_log /docker.stderr; + error_log /docker.stderr; + + server_name _ *.vm docker; + + root "/app/www"; + index index.php; + + include /opt/docker/etc/nginx/vhost.common.d/*.conf; + include /opt/docker/etc/nginx/vhost.ssl.conf; + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass php; + fastcgi_param PATH_INFO $fastcgi_path_info; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $request_filename; + fastcgi_read_timeout 600; + } +} diff --git a/docker/ssp-debug-sp/conf/saml20-idp-hosted.php b/docker/ssp-debug-sp/conf/saml20-idp-hosted.php new file mode 100644 index 0000000..6714f90 --- /dev/null +++ b/docker/ssp-debug-sp/conf/saml20-idp-hosted.php @@ -0,0 +1,157 @@ + '__DEFAULT__', + + 'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + + /* X.509 key and certificate. Relative to the cert directory. */ + 'privatekey' => 'idp.key', + 'certificate' => 'idp.crt', + + /* + * Authentication source to use. Must be one that is configured in + * 'config/authsources.php'. + */ + 'auth' => 'example-userpass', + + + //'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', + //'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', + 'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified', + + // Sign logout request and logout responses + 'redirect.sign' => TRUE, + + // Require validate signature on requests + 'redirect.validate' => FALSE, + + // Sign response + 'saml20.sign.response' => FALSE, + + // Sign assertion + 'saml20.sign.assertion' => TRUE, + + // No artifact binding support + 'saml20.sendartifact' => FALSE, + + //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + + 'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', + + // Use (or 'select') an unspecified NameID. The NameID is generated in the authproc below. + // This is the NameID that will be but in the Subject of the SAML Assertion + 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', + + // Authproc to make the output of this IdP sufficiently like OpenConext to allow + // OpenConext Stepup to work. + // The configured authsource must provide the required attributes. + // Required is an "NameID" attribute. This will be used both in the Subject and in the "eduPersonTargetedID" + // + 'authproc' => array( + + // Generate an unspecified NameID for use by this IdP + // Note that this NameID won't be used until it is "selected" in the saml20-idp-hosted.php by adding: + // 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', + // + // Use the value of the "NameID" attribute from the authsource as value for the NameID + 1 => array( + 'class' => 'saml:AttributeNameID', + 'attribute' => 'NameID', + 'Format' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', + + // Don't add NameQualifier and SPNameQualifier attributes to the generated NameID + 'NameQualifier' => FALSE, + 'SPNameQualifier' => FALSE, + ), + + // Copy the NameID to the eduPersonTargetedID attribute + // Note that this will generate a eduPersonTargetedID with a PERSISTENT targeted NameID + // + // This will not work when the RA and Selfservice are behind the Stepup Gateway + // Using this might be useful to test the Stepup Gateway NameID passing behaviour + // + // When the Stepup Selfservice and RA are behind the Stepup Gateway the NameID in the Subject + // and the NameID in the eduPersonTargetedID must match so that the Stepup Gatway will pass it to + // the SelfService and RA applications. An eduPersonTargetedID with an UNSPECIFIED NameID + // (For OpenConext urn:collab:person:etc..) is non standard. + // + // If you enable this (2) rule you will want to disable the custom (3) rule below as it overwrites the + // eduPersonTargetedID generated by this rule. + /* + 2 => array( + 'class' => 'core:TargetedID', // Generate a eduPersonTargetedID attribute + 'attribute' => 'NameID', + 'nameId' => TRUE, // Use the "Nested" NameID format + // Don't add NameQualifier and SPNameQualifier attributes to the generated NameID + 'NameQualifier' => FALSE, + 'SPNameQualifier' => FALSE, + ), + */ + + // Create an eduPersonTargetedID attribute with an unspecified NameID with the value + // of the "NameID" attribute from the authsource. + 3 => array( + 'class' => 'core:PHP', + 'code' => + ' + $nameId = new \SAML2\XML\saml\NameID(); + $nameId->value = $attributes["NameID"][0]; // Use value of "NameID" attribute + $nameId->Format = \SAML2\Constants::NAMEID_UNSPECIFIED; // Unspecified NameID + //$nameId->NameQualifier = "..."; + //$nameId->SPNameQualifier = "..."; + $doc = \SAML2\DOMDocumentFactory::create(); + $root = $doc->createElement("root"); + $doc->appendChild($root); + $nameId->toXML($root); + $eduPersonTargetedID = $doc->saveXML($root->firstChild); + $attributes["eduPersonTargetedID"] = array($eduPersonTargetedID); + ', + ), + + // Remove the NameID attribute to prevent any confusion, it was only there to specify the NameID + // to use in the Subject and eduPersonTargetedID attribute + 4 => array( + 'class' => 'core:AttributeAlter', + 'subject' => 'NameID', + 'pattern' => '/.*/', + '%remove', + ), + + // Convert "short" atribute names (uid, mail, eduPersonTargetedID, ...) to their long urn:mace... + // equivalent + 10 => array( + 'class' => 'core:AttributeMap', + 'SURFconext_short_to_urn' + ), + + ), + + // Required because the eduPersonTargetedID is a "complex" attribute and not a simple string value. + 'attributeencodings' => array( + 'urn:mace:dir:attribute-def:eduPersonTargetedID' => 'raw' + ), + +); + +if ( isset($_COOKIE['testcookie']) ) { + $metadata['https://ssp.stepup.example.com/saml2/idp/metadata.php']['publickey'] = '/vagrant/deploy/tests/behat/fixtures/test_public_key.crt'; + $metadata['https://ssp.stepup.example.com/saml2/idp/metadata.php']['privatekey'] = '/vagrant/deploy/tests/behat/fixtures/test_private_key.key'; +} diff --git a/docker/ssp-debug-sp/conf/saml20-idp-remote.php b/docker/ssp-debug-sp/conf/saml20-idp-remote.php new file mode 100644 index 0000000..d8e5ef4 --- /dev/null +++ b/docker/ssp-debug-sp/conf/saml20-idp-remote.php @@ -0,0 +1,138 @@ + 'https://ssp.stepup.example.com/saml2/idp/metadata.php', + 'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + 'certificate' => 'idp.crt', + 'SingleSignOnService' => + array ( + 0 => + array ( + 'Binding' => $GLOBALS['gSP_SSOBinding'], + 'Location' => 'https://ssp.stepup.example.com/saml2/idp/SSOService.php', + ), + ), + 'ArtifactResolutionService' => + array ( + 0 => + array ( + 'index' => 0, + 'Location' => 'https://ssp.stepup.example.com/saml2/idp/ArtifactResolutionService.php', + 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP', + ), + ), + 'name' => array( + 'en' => 'ssp.stepup.example.com - SSP Test IdP', + 'nl' => 'ssp.stepup.example.com - SSP Test IdP', + ), + +); + + +//////////////////////////////////////////////////////////////////////////// +// The metadata of the OpenConext Stepup IdP, for use by the hosted SPs + +$metadata['https://gateway.stepup.example.com/authentication/metadata'] = array ( + 'entityid' => 'https://gateway.stepup.example.com/authentication/metadata', + //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + 'contacts' => + array ( + ), + 'metadata-set' => 'saml20-idp-remote', + 'SingleSignOnService' => + array ( + 0 => + array ( + 'Binding' => $GLOBALS['gSP_SSOBinding'], + 'Location' => 'https://gateway.stepup.example.com/authentication/single-sign-on', + ), + ), + 'SingleLogoutService' => + array ( + ), + 'ArtifactResolutionService' => + array ( + ), + 'keys' => + array ( + 0 => + array ( + 'encryption' => false, + 'signing' => true, + 'type' => 'X509Certificate', + 'X509Certificate' => '{{ gateway_saml_idp_publickey | depem }}', + ), + ), +); + +if ( isset($_COOKIE['testcookie']) ) { + $metadata['https://gateway.stepup.example.com/authentication/metadata']['keys'][0]['X509Certificate'] = depem(file_get_contents('/vagrant/deploy/tests/behat/fixtures/test_public_key.crt')); +} + +//////////////////////////////////////////////////////////////////////////// +// The metadata of the OpenConext Stepup IdP - SFO, for use by the hosted SPs + +$metadata['https://gateway.stepup.example.com/second-factor-only/metadata'] = array ( + 'entityid' => 'https://gateway.stepup.example.com/second-factor-only/metadata', + //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + 'contacts' => + array ( + ), + 'metadata-set' => 'saml20-idp-remote', + 'SingleSignOnService' => + array ( + 0 => + array ( + 'Binding' => $GLOBALS['gSP_SSOBinding'], + 'Location' => 'https://gateway.stepup.example.com/second-factor-only/single-sign-on', + ), + ), + 'SingleLogoutService' => + array ( + ), + 'ArtifactResolutionService' => + array ( + ), + 'keys' => + array ( + 0 => + array ( + 'encryption' => false, + 'signing' => true, + 'type' => 'X509Certificate', + 'X509Certificate' => '{{ gateway_saml_idp_publickey | depem }}', + ), + ), +); + +if ( isset($_COOKIE['testcookie']) ) { + $metadata['https://gateway.stepup.example.com/second-factor-only/metadata']['keys'][0]['X509Certificate'] = depem(file_get_contents('/vagrant/deploy/tests/behat/fixtures/test_public_key.crt')); +} + +/** + * Remove the spicing from the certificate, this is a php port of the python (keyczar) implementation that is used + * in the ninja templates ( return re.sub(r'\s+|(-----(BEGIN|END).*-----)', '', string) ) + */ +function depem($input) +{ + return str_replace([ + '-----BEGIN CERTIFICATE-----', + '-----END CERTIFICATE-----', + "\r\n", + "\n", + ], [ + '', + '', + "\n", + '' + ], $input); +} diff --git a/docker/ssp-debug-sp/conf/saml20-sp-remote.php b/docker/ssp-debug-sp/conf/saml20-sp-remote.php new file mode 100644 index 0000000..d15fb6b --- /dev/null +++ b/docker/ssp-debug-sp/conf/saml20-sp-remote.php @@ -0,0 +1,47 @@ + + array ( + 0 => + array ( + 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + 'Location' => 'https://ssp.stepup.example.com/module.php/saml/sp/saml2-acs.php/default-sp', + 'index' => 0, + ), + ), + 'SingleLogoutService' => + array ( + 0 => + array ( + 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + 'Location' => 'https://ssp.stepup.example.com/module.php/saml/sp/saml2-logout.php/default-sp', + ), + ), + 'certificate' => 'sp.crt' +); + + +/////////////////////////////////////////////////////////////////////////////////// +// Stepup Gateway in it's SP role + +$metadata['https://gateway.stepup.example.com/authentication/metadata'] = array( + 'AssertionConsumerService' => + array ( + 0 => + array ( + 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + 'Location' => 'https://gateway.stepup.example.com/authentication/consume-assertion', + 'index' => 0, + ), + ), + 'certificate' => '{{ gateway_saml_sp_publickey | depem }}' +); diff --git a/docker/ssp-debug-sp/conf/sp-config.inc b/docker/ssp-debug-sp/conf/sp-config.inc new file mode 100644 index 0000000..87d7eef --- /dev/null +++ b/docker/ssp-debug-sp/conf/sp-config.inc @@ -0,0 +1,48 @@ + array( + 'name' => 'Displayname of the IdP in the SP interface', + 'loa' => array( + 1 => 'AuthnContextClassRef for loa 1', + 2 => 'AuthnContextClassRef for loa 2', + 3 => 'AuthnContextClassRef for loa 3', + ), + ) + */ + 'https://gateway.stepup.example.com/authentication/metadata' => array( + 'name' => 'OpenConext Stepup Gateway - gateway.stepup.example.com', + 'loa' => array( + '1.5' => 'http://stepup.example.com/assurance/loa-self-asserted', + 1 => 'http://stepup.example.com/assurance/level1', + 2 => 'http://stepup.example.com/assurance/level2', + 3 => 'http://stepup.example.com/assurance/level3', + ), + ), + 'https://gateway.stepup.example.com/second-factor-only/metadata' => array( + 'name' => 'OpenConext Stepup Gateway - gateway.stepup.example.com - SFO', + 'loa' => array( + '1.5'=> 'http://stepup.example.com/assurance/loa-self-asserted', + 1 => 'http://no.level.1.for.sfo.example.com/assurance/sfo-level1', // Note does not exist + 2 => 'http://stepup.example.com/assurance/sfo-level2', + 3 => 'http://stepup.example.com/assurance/sfo-level3', + ), + ), + 'https://ssp.stepup.example.com/saml2/idp/metadata.php' => array( + 'name' => 'Local SSP IdP - ssp.stepup.example.com', + 'loa' => array( + '1.5' => '', + 1 => '', + 2 => '', + 3 => '', + ), + ), +); diff --git a/docker/ssp-debug-sp/conf/sp-utils.inc b/docker/ssp-debug-sp/conf/sp-utils.inc new file mode 100644 index 0000000..881cea2 --- /dev/null +++ b/docker/ssp-debug-sp/conf/sp-utils.inc @@ -0,0 +1,172 @@ + 0){ + $m = $l + $l - $v; + $sv = ($v - $m ) / $v; + $h *= 6.0; + $sextant = floor($h); + $fract = $h - $sextant; + $vsf = $v * $sv * $fract; + $mid1 = $m + $vsf; + $mid2 = $v - $vsf; + switch ($sextant) { + case 0: + $r = $v; $g = $mid1; $b = $m; + break; + case 1: + $r = $mid2; $g = $v; $b = $m; + break; + case 2: + $r = $m; $g = $v; $b = $mid1; + break; + case 3: + $r = $m; $g = $mid2; $b = $v; + break; + case 4: + $r = $mid1; $g = $m; $b = $v; + break; + case 5: + $r = $v; $g = $m; $b = $mid2; + break; + } + } + // Convert from RGB values (0 .. 1) to hex (00 .. FF) + $color='#' .str_pad(dechex($r*256),2,'0',STR_PAD_LEFT) + .str_pad(dechex($g*256),2,'0',STR_PAD_LEFT) + .str_pad(dechex($b*256),2,'0',STR_PAD_LEFT); + return $color; +} + + +function XMLTextNode2HTML_TS($domnode) +{ + if (!is_null($domnode) && isset($domnode[0])) { + $time = SimpleSAML_Utilities::parseSAML2Time($domnode[0]->textContent); + $offset = $time - time(); + $str = ''.gmdate('r', $time).''; + $str .= ' (now '. (($offset>0) ? '+':'') . round(($offset/60)) . ' minutes)'; + return $str; + } + + return 'N/A'; +} + + +function AttributeNameToHTML($attribute) { + static $oidToName = array( + 'urn:oid:1.3.6.1.4.1.1076.20.40.40.1' => 'collabPersonId, Deprecated!', + 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10' => 'urn:mace:dir:attribute-def:eduPersonTargetedID', + 'urn:oid:2.5.4.4' => 'urn:mace:dir:attribute-def:sn', + 'urn:oid:2.5.4.42' => 'urn:mace:dir:attribute-def:givenName', + 'urn:oid:2.5.4.3' => 'urn:mace:dir:attribute-def:cn', + 'urn:oid:2.16.840.1.113730.3.1.241' => 'urn:mace:dir:attribute-def:displayName', + 'urn:oid:0.9.2342.19200300.100.1.3' => 'urn:mace:dir:attribute-def:mail', + 'urn:oid:1.3.6.1.4.1.25178.1.2.9' => 'urn:mace:terena.org:attribute-def:schacHomeOrganization', + 'urn:oid:1.3.6.1.4.1.25178.1.2.10' => 'urn:mace:terena.org:attribute-def:schacHomeOrganizationType', + 'urn:oid:1.3.6.1.4.1.25178.1.2.14' => 'urn:schac:attribute-def:schacPersonalUniqueCode', + 'urn:oid:1.3.6.1.4.1.5923.1.1.1.1' => 'urn:mace:dir:attribute-def:eduPersonAffiliation', + 'urn:oid:1.3.6.1.4.1.5923.1.1.1.9' => 'urn:mace:dir:attribute-def:eduPersonScopedAffiliation', + 'urn:oid:1.3.6.1.4.1.5923.1.1.1.7' => 'urn:mace:dir:attribute-def:eduPersonEntitlement', + 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6' => 'urn:mace:dir:attribute-def:eduPersonPrincipalName', + 'urn:oid:1.3.6.1.4.1.5923.1.5.1.1' => 'urn:mace:dir:attribute-def:isMemberOf', + 'urn:oid:0.9.2342.19200300.100.1.1' => 'urn:mace:dir:attribute-def:uid', + 'urn:oid:2.16.840.1.113730.3.1.39' => 'urn:mace:dir:attribute-def:preferredLanguage', + 'urn:oid:1.3.6.1.4.1.5923.1.1.1.16' => 'urn:mace:dir:attribute-def:eduPersonORCID', + 'urn:oid:1.3.6.1.4.1.1466.115.121.1.15' => 'Directory String (RFC 4517), Error!' + ); + + static $error = array( + 'urn:oid:1.3.6.1.4.1.1076.20.40.40.1', // collabPersonId (deprecated) + 'urn:oid:1.3.6.1.4.1.1466.115.121.1.15' // This is an LDAP string type, not an attribute. This was mistakenly used by SURFconext instead of urn:oid:1.3.6.1.4.1.25178.1.2.9 (schacHomeOrganization) + ); + if (in_array($attribute, $error)) + $color="style='color: red'"; + if (isset($oidToName[$attribute])) { + $title=$oidToName[$attribute]; + return "".htmlentities($attribute).""; + } + + return htmlentities($attribute); +} + + +function XMLTextNode2HTML($domnode) +{ + if (!is_null($domnode) && isset($domnode[0])) { + return ''.htmlentities($domnode[0]->textContent).''; + } + + return 'N/A'; +} + + +function HTML_select($label, $id, $options, $value="", $info="") +{ + $label=htmlentities($label); + $id=htmlentities($id); + $value=htmlentities($value); + echo "

0) + echo " title=\"{$info}\""; + echo ">{$label}

"; +} + + +function NameIDArrayToHTML($nameID, $compact=false) +{ + foreach ($nameID as $key => $value) { + $k = htmlentities($key); + $v = htmlentities($value); + $color=''; + if ($k == 'Value') { + $color=HTMLColorFingerprint($v); + } + $labelstyle=''; + if ($compact) + $labelstyle="style='width: 60px; clear: both'"; + echo "{$v}
"; + } +} \ No newline at end of file diff --git a/docker/ssp-debug-sp/conf/sp.php b/docker/ssp-debug-sp/conf/sp.php new file mode 100644 index 0000000..199ab37 --- /dev/null +++ b/docker/ssp-debug-sp/conf/sp.php @@ -0,0 +1,589 @@ +isAuthenticated(); + +// Build return URL. This is where ask simplesamlPHP to direct the browser to after login or logout +// Point to this script, but without any request parameters so we won't trigger an login again (and again, and again, and ...) +$returnURL = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; +$returnURL .= $_SERVER['HTTP_HOST']; +$returnURL .= $_SERVER['SCRIPT_NAME']; +$returnURL .= '?sp='.urlencode($sp); + +// Process login and logout actions. Neither login nor logout return +if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'login' ) { + + // Save submitted form in session + $params_to_save=$_REQUEST; + unset($params_to_save['action']); + $session->setData('array', 'SSP_DEMO_SP_FORM_DATA', $params_to_save); + + // Unset existing RequiredAuthnContextClassRef first + $session->deleteData('string', 'RequiredAuthnContextClassRef'); + $bForceAuthn = false; + if ( (isset($_REQUEST['forceauthn'])) && ($_REQUEST['forceauthn'] == 'true') ) + $bForceAuthn = true; + + // For use by SAML2Keeper callback function + $session->setData('string', 'SAML2Keeper_ReturnTo', $returnURL); + + $context = array( + 'ReturnTo' => $returnURL, + 'ReturnCallback' => array('sspmod_saml2keeper_SAML2Keeper','loginCallback'), + 'ForceAuthn' => $bForceAuthn, + 'saml:NameIDPolicy' => null, + ); + + // IdP + if ( (isset($_REQUEST['idp'])) ) { + $context['saml:idp'] = $_REQUEST['idp']; + } + + // LOA + if ( isset($_REQUEST['loa']) && isset($_REQUEST['idp']) && isset($gIDPmap[$_REQUEST['idp']]['loa'][$_REQUEST['loa']]) ) { + $loa = $gIDPmap[$_REQUEST['idp']]['loa'][$_REQUEST['loa']]; + // Store the requested LOA in the session so we can verify it later + $session->setData('string', 'RequiredAuthnContextClassRef', $loa); + $context['saml:AuthnContextClassRef'] = $loa; // Specify LOA + } + + // Scoping IdPList + if ( isset($_REQUEST['scopingIDP']) && strlen($_REQUEST['scopingIDP']) > 0 ) { + $context['saml:IDPList'] = array($_REQUEST['scopingIDP']); + + if ( isset($_REQUEST['scopingIDP2']) && strlen($_REQUEST['scopingIDP2']) > 0 ) { + $context['saml:IDPList'][]=$_REQUEST['scopingIDP2']; + } + } + + // RequesterID + if ( isset($_REQUEST['requesterid']) && strlen($_REQUEST['requesterid']) > 0 ) { + $context['saml:RequesterID'] = array($_REQUEST['requesterid']); + + if ( isset($_REQUEST['requesterid2']) && strlen($_REQUEST['requesterid2']) > 0 ) { + $context['saml:RequesterID'][] = $_REQUEST['requesterid2']; + } + } + + // NameIDPolicy + if ( isset($_REQUEST['nameidpolicy']) && strlen($_REQUEST['nameidpolicy']) > 0 ) { + $context['saml:NameIDPolicy'] = $_REQUEST['nameidpolicy']; + } + + // Subject NameID + if ( isset($_REQUEST['subject']) && strlen($_REQUEST['subject']) > 0 ) { + $context['saml:NameID'] = array( + 'Value' => $_REQUEST['subject'], + 'Format' => SAML2_Const::NAMEID_UNSPECIFIED + ); + } + + // AssertionConsumerServiceURL + if ( isset($_REQUEST['acsurl']) && strlen($_REQUEST['acsurl']) > 0 ) { + $context['DebugSP:AssertionConsumerServiceURL'] = $_REQUEST['acsurl']; + } + + // Emulate ADFS + if ( (isset($_REQUEST['emulateadfs'])) && ($_REQUEST['emulateadfs'] == 'true') ) + { + $context['DebugSP:extraPOSTvars'] = array( + 'AuthMethod' => 'ADFS.SCSA', + 'Context' => '1C63828278F1B0AC2FE61429E099FFA7AC94917CQe1t1xgG78zLHhUxBXm0ous4yl0zfQumsKI79lrHMOIjdTdeF/i1Yx+pQ+mgnubT9mh+DfBYMs7wU1g+eXiAs2gnwKWmnMzeuxgG+m5Nky5Wd63NcEgLZ2zNTYuW70X514HMtLAw+l1H8cptQMXfXt9ageHOdY+65eq4IsNwnB0mPhRkua58R9xO3I4MfBzy90GqwgjmDeZAo5vsKgk0iZRgZ1CS4hPyIWX+ryU2tnYp5UEuDE9gGlR9cQr2uHW10LOG22ZfEy8rJie2T2A2bCQVyF47nmBnvoKYV6YyEDpozSYJpUqHmIgvaWgFu5dvDvZ0fvrVQaQ1ZUKHTT76Cg==6SO/qvyH0bmayeNGyzqAy/Oim2UAOvhxm18rTs+72Qm2fSK6Pfo1ZEDNKmLRk6IemCvkUYWMa4VmxIdATswREx/aSrp4YS3QejDBoZlCwz4LqFWJMiqTPxJfWhahP0hBNEORN8cU5vBQXXIahWqlkaHzs6IPjH4WoMe5vsSKVTetaOMbMC3ZML67BWpAnEXKWoR/gar1jH5v961ljdKJozzgwsJIAY4TNSoB+AEzRd4C3wLSTCott1DyRtMmEmS5DpaDOaxmZ/X+z16t1hb9VKgEqt1xZJ0uw451d5oeuisN9zSqbWQzyiJdkk6k11YU9q2rvg342qLJk6xeTtRc6+DLQ24vZIHC8RU2jcHveLDJvOq89BBJ0LHtnV/7PJpb4PGf1OUqWZidnRAS0/dqprEVzPEnvdzIJ8vPRGzE0dkQhgzDi+cbMsuZrDqYWaMuodvDbGrETxZ9hu0MI3l9pgjuIh8xF7TT/6qTJnGExRaGFebcjMXC99thZ3A7XeJESDNXNxgDgFQf6OwHLjLuhw==va+cZ6Y7NIyBU9vCVb+qRGSx0Yk=DNF3KVEb8ju/T+ise1j0QBS2OYsepwzgWaUtOASvUPI6NPlvyQIHxX1Py6oHcUkbWP1jaVTzwEGadaq428nPMWSeU/MDWqyz2jyrwuIUWglc64AMlcXd0BOdT1I6khKMsUGY8CSa1tRD2arcIH1TUrrk7jY3qfAGtgNbFlElPwc/2l4dkN7QXdHRcmntFp4D/9yEG9FkWzTyXLvCvGqcQeu8L1fKTwq8Upqk9iT2PKnmT/gH+IUt3votmCMV9bxYols0aQWfv2RX2HX3Gow9xKZuOn+ckjZRqBJ1Kp9wGMAB65XQPli5UQzezEHX28oUPH/PEgnu6RKDgsN55h22ag==DB540D051F8F73EA2F3B5190BFC0F349E595EB34 SAMLRequest: PHNhbWwycDpBdXRoblJlcXVlc3QgeG1sbnM6c2FtbDJwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iXzkwZWFkMWNlLTM3NmMtNGE1ZC05ODAzLWQ5Y2M4MDA2M2Q0ZiIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTgtMDQtMjNUMTM6NDk6NTBaIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zYS1ndy50ZXN0Mi5zdXJmY29uZXh0Lm5sL3NlY29uZC1mYWN0b3Itb25seS9zaW5nbGUtc2lnbi1vbiIgQXNzZXJ0aW9uQ29uc3VtZXJTZXJ2aWNlVVJMPSJodHRwczovL2FkZnMtMjAxMi50ZXN0Mi5zdXJmY29uZXh0Lm5sOjQ0My9hZGZzL2xzLz9TQU1MUmVxdWVzdD1wVkpOanhNeERQMHJvOXpubzVscFlhTzJVdGtLVVdtQmFsczRjRUZ1eGtNalpaSWhkbUQ1OTZRcGlJVkRMNXdTUGZzOVB6OTVTVERhU1cwaW45MGpmbzFJWER5TjFwSEtoWldJd1NrUFpFZzVHSkVVYTNYWXZIMVFzbXJVRkR4NzdhMTRScm5OQUNJTWJMd1R4VzY3RXAlMkZiMmVtdTBYTG90SnpMUmklMkJHV1R1SHJwJTJGTCUyQlFKMXYyaFBKOTNjZFMwTUlJcVBHQ2d4VnlJSkpUcFJ4SjBqQnNjSmFtWXZ5NllyWlh1Y3RhcGJxUGJGSjFGczB6YkdBV2ZXbVhraVZkZlFEMVNtZmxseEtzdUtZaGkwZCUyRmpFbGJPNVdsdXFSYkg1YmZYZU80b2poZ09HYjBiamg4ZUhQMktUUWNaUUFaaXM0ekNMa0Jrbml6bkE4MVNQdm84V3E4djNBdFYwZldVSm1qTGE0d0RSY2ttVEtQYSUyRkluMWxYRyUyRmNsOXRwbnE1TnBONGNqJTJGdHklMkYlMkY1d0ZPdmxSVnZsZE1MNlAyMk95TkFEd3o4dWwlMkZYekdjdnJCYjFMN25iYnZiZEclMkZ5aGUlMkJ6QUMzelolMkZRVXhmRHJsVmNRQkhCaDJuNEszMTMlMkI4REF1TktjSWdvNnZWMTVOOTN1djRKJmFtcDtSZWxheVN0YXRlPWh0dHBzJTNBJTJGJTJGcGlldGVyLmFhaS5zdXJmbmV0Lm5sJTJGc2ltcGxlc2FtbHBocCUyRnNwLnBocCUzRnNwJTNEZGVmYXVsdC1zcCZhbXA7U2lnQWxnPWh0dHAlM0ElMkYlMkZ3d3cudzMub3JnJTJGMjAwMSUyRjA0JTJGeG1sZHNpZy1tb3JlJTIzcnNhLXNoYTI1NiZhbXA7U2lnbmF0dXJlPUt6TzhYV0liVTZGdUVWZVZ4RFlNZzJ1T2xoZTlBQVAwd09uWlZVM3RVMU1ibWNKUDlXa3Q1Z0R3a2RKcXhDbUlJWGVDdnBhNDVLWUdlTzNFNWppampSOHlMUFpTalJUalJRem81V2h5bzJTaXRjTkxOZzZ4WFdZY0Z6bmdIcEdKeGRyJTJGVmxjSTR0RXFUNFZSN0VwbXp3amJtd1RaRGMyOW9hdEtZRGNUUjBjTjh2M0VtMVRIR0ZOc1B0bERvRVd5c0laWjFONkRpRVAxYmE4aTE5OVhoRiUyQldXZzVzNHdqMXltMnBDendQelJkYyUyRmpreDRQcG1MTyUyQjNVY3R3amoySG5RNmNiJTJCeHBsJTJCJTJCVUFwalZ1a3ZlNWdiempMbzI4JTJCUGklMkZXQmJ0Ym0lMkZrMzE5UlZ2dWFEdVVvJTJGM3VTUU1BJTJCbHR6b0ZIOGEwRTJ0Q0pNVGg1TWRnUm10ZyUzRCUzRCI+DQogIDxzYW1sMjpJc3N1ZXI+aHR0cDovL2FkZnMtMjAxMi50ZXN0Mi5zdXJmY29uZXh0Lm5sPC9zYW1sMjpJc3N1ZXI+PFNpZ25hdHVyZSB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+PFNpZ25lZEluZm8+PENhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8+PFNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiIC8+PFJlZmVyZW5jZSBVUkk9IiNfOTBlYWQxY2UtMzc2Yy00YTVkLTk4MDMtZDljYzgwMDYzZDRmIj48VHJhbnNmb3Jtcz48VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiIC8+PFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgLz48L1RyYW5zZm9ybXM+PERpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIgLz48RGlnZXN0VmFsdWU+Q2ZKV1hpTXJLU0g0b3pPVWZTL0VNOXBXbFRSc3p2QkpMN2Y3MUZrZ3ZCbz08L0RpZ2VzdFZhbHVlPjwvUmVmZXJlbmNlPjwvU2lnbmVkSW5mbz48U2lnbmF0dXJlVmFsdWU+YzFqakFhdnVjMi9TSHZQYzdJdktJVkRSZUZuZVAzbTlITkZzTzErZEx2bWhxUXl5NkhoN3ZRMlFJalVGb2FybkYxZnJpOUY1RlNxL2JsR1I4RENvNEpndUlxKzNnRXBjN1JYR2EyTWc4dE5CV2tWdUg2UnZBTGM1Qk5DSDNtODVTTHgwcklGbERWc0tzZi9IQ0lTc2taV3Z6VVJGVVRFZnZjRVljWjZZZjNXYURmK1YvbE5jYXpCeVQ0L3RmNVVFN0VIM1JYckc2dUFqbHhjekN4a09UUE1SMnIvNmxwaEF1UmIxcjY1bThYQXFZNVFnbG5SVXBOM3U3ZEt4bGN5VUVaY2xKTW5JN21ya2NyMUdwODV6allkK0N4TmFwanNEQXplVjdSSVNLdHNaY0NFYWhncStIdTZVOEtBUmZHZmdFQ1dZNGY0c2lWRGp2d0NVaTlUME13PT08L1NpZ25hdHVyZVZhbHVlPjxLZXlJbmZvPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSURFekNDQWZ1Z0F3SUJBZ0lRU044elc2Q1lsSUpPQUZ6ZFN0VFQrakFOQmdrcWhraUc5dzBCQVFzRkFEQXNNU293S0FZRFZRUUREQ0Z6YVdkdWFXNW5MbVF5TURFeUxuUmxjM1F5TG5OMWNtWmpiMjVsZUhRdWJtd3dIaGNOTVRjd09USTBNVFl6TkRFM1doY05Nakl3T1RJMU1UWXpOREUzV2pBc01Tb3dLQVlEVlFRRERDRnphV2R1YVc1bkxtUXlNREV5TG5SbGMzUXlMbk4xY21aamIyNWxlSFF1Ym13d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNkL1RXMUpvY05PV2w1aUZsN1JrWTQwa1A1U2NpQllCNnRJRXl3ZmxGNHRrRUR3S1Jxc1EyRXNaOTN1aWdnQi9wWFVhNlRHdlM3dnpRalJxZGhGZ0Nwb2htaGVwUzlQd3UvL0krcDY4VlpDdHNsdDFVSkd0NjJBRk9ad2FUU1FQbjRlR2RoRHI0c1g5TXIrdVVPU1plZWlEdHVFaGlNSWprZDJJYWJPeVNkOUxTK05Nc29pY1NoWEd5MERZR05yN2gyaHl1L2xUK3VMSnZsUFJ0V29aNDdpS1kwVUdpcVNJN013WlNQQjBoT2p5ZW9wbCsvWExENGhEKzNWVUFDMkttSDZaTzBBYWErc1JRZStNVFlVNHZvN29YTitkaEZoOG9VcFFrNjN4MjBtYTE1N3RSU1lqQlVwTURkclMvdk4vNWQ3c21URnQ1dFV4dlVHTGNGR0E4SkFnTUJBQUdqTVRBdk1BNEdBMVVkRHdFQi93UUVBd0lIZ0RBZEJnTlZIUTRFRmdRVUZ2ZzR3d3ByTDBlWi9ZL09zSDkyVDMrK3RsVXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRXEvQ2p5N2J0THFmWnp4dlZwUEJYZnVmYk5RSHJBeFY1QnA2a0QyY0NYUzlWQ0swdUdKdkZsemRVMDNDTE9uME4xYTJBUU5JSmZPZVg2dXlTQ1F1WXE0aDRWeUxVSVUyWE1QS1V3OGF2cWhuM0pxbGx4WUJuOE9XdENiRS9BWTdLU2lMWHk5V1BYcHRhdFpyeTV4T0x1SzYxZCtsSzJrdTlVc2xVcTY5b3BIZHhNZ3VqV0EvOUV1SkRINEVEblJ0c0lDT1oyZmxibEllQng4VU5zemExWjJ3NlIxUmtWQVN3YVZDL3JXOVpJaXhkTjdyQzUxQU1qU2YzUnBUc0cvT1Y2blNFcHJNa2hVWWRoSFdSb09XZk8rUGJmZGE1Sm85SHMyeHZENE43L2hPSjQzdC8wV0o1bng3NkNxMTNHcGlFYmlIbXZIQU1jS3R4aHVBS2M4NEk0PTwvWDUwOUNlcnRpZmljYXRlPjwvWDUwOURhdGE+PC9LZXlJbmZvPjwvU2lnbmF0dXJlPg0KICA8c2FtbDI6U3ViamVjdD4NCiAgICA8c2FtbDI6TmFtZUlEIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPnVybjpjb2xsYWI6cGVyc29uOmluc3RpdHV0aW9uLWEubmw6cGlldGVyLWExPC9zYW1sMjpOYW1lSUQ+DQogIDwvc2FtbDI6U3ViamVjdD4NCiAgPHNhbWwycDpSZXF1ZXN0ZWRBdXRobkNvbnRleHQgQ29tcGFyaXNvbj0iZXhhY3QiPg0KICAgIDxzYW1sMjpBdXRobkNvbnRleHRDbGFzc1JlZj5odHRwOi8vdGVzdDIuc3VyZmNvbmV4dC5ubC9hc3N1cmFuY2Uvc2ZvLWxldmVsMjwvc2FtbDI6QXV0aG5Db250ZXh0Q2xhc3NSZWY+DQogIDwvc2FtbDJwOlJlcXVlc3RlZEF1dGhuQ29udGV4dD4NCjwvc2FtbDJwOkF1dGhuUmVxdWVzdD4=' + ); + } + + + // login + $as->login( $context ); + + exit; // Added for clarity +} + +if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'logout' ) { + $as->logout( array ( + 'ReturnTo' => $returnURL, + ) ); // Process logout + exit; // Added for clarity +} + +if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'reset' ) { + $session->deleteData('array', 'SSP_DEMO_SP_FORM_DATA'); + $_REQUEST=array(); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Output HTML + +$saved_parameters = $session->getData('array', 'SSP_DEMO_SP_FORM_DATA'); +if (is_array($saved_parameters)) { + $saved_parameters = array(); +} +if (!isset($_REQUEST['idp'])) { + $_REQUEST=array_merge($saved_parameters, $_REQUEST); +} + +$idp=htmlentities(isset($_REQUEST['idp']) ? $_REQUEST['idp'] : ""); +$loa=htmlentities(isset($_REQUEST['loa']) ? $_REQUEST['loa'] : ""); +$nameidpolicy=htmlentities(isset($_REQUEST['nameidpolicy']) ? $_REQUEST['nameidpolicy'] : ""); +$ssobinding=htmlentities(isset($_REQUEST['ssobinding']) ? $_REQUEST['ssobinding'] : ""); +$requesterid=htmlentities(isset($_REQUEST['requesterid']) ? $_REQUEST['requesterid'] : ""); +$requesterid2=htmlentities(isset($_REQUEST['requesterid2']) ? $_REQUEST['requesterid2'] : ""); +$scopingIDP=htmlentities(isset($_REQUEST['scopingIDP']) ? $_REQUEST['scopingIDP'] : ""); +$scopingIDP2=htmlentities(isset($_REQUEST['scopingIDP2']) ? $_REQUEST['scopingIDP2'] : ""); +$sp=htmlentities(isset($_REQUEST['sp']) ? $_REQUEST['sp'] : "default-sp"); +$subject=htmlentities(isset($_REQUEST['subject']) ? $_REQUEST['subject'] : ""); +$acsurl=htmlentities(isset($_REQUEST['acsurl']) ? $_REQUEST['acsurl'] : ""); + +echo << + + + + + simpleSAMLphp Test SP + + +

simpleSAMLphp Test SP

+head; + +$authnInstant = ''; +$expire = ''; +if ( $bIsAuthenticated ) { + $attributes = $as->getAttributes(); + + /** @var $session SimpleSAML\Session */ + $requestedLOA = htmlentities($session->getData('string', 'RequiredAuthnContextClassRef')); + $IdPEntityID = htmlentities($as->getAuthData('saml:sp:IdP')); + $sessionIndex = htmlentities($as->getAuthData('saml:sp:SessionIndex')); + $authState = $session->getAuthState($sp); + //echo "
"; print_r($authState); echo "
"; + $authenticationAuthority=$authState['saml:AuthenticatingAuthority']; // Array of AuthenticatingAuthority's + $actualLOA = htmlentities($authState['saml:sp:AuthnContext']); + $nameID = $as->getAuthData('saml:sp:NameID'); + $authnInstant = htmlentities(gmdate('r', $authState['AuthnInstant'] )); + $expire = htmlentities(gmdate('r', $authState['Expire'] )); + + echo <<You are logged in to SP:{$sp}
+ {$IdPEntityID}
+
+

+
+html; + + echo "

Session

\n"; + + echo "

"; + if (strlen($sessionIndex) > 0) { + $color=HTMLColorFingerprint($sessionIndex); + echo "{$sessionIndex}
"; + } + echo "{$authnInstant}
"; + echo "{$expire}

"; + + echo "

LOA

"; + echo "
{$actualLOA}

"; + if (strlen($requestedLOA) > 0) { + echo "
{$requestedLOA}

"; + } + + echo "

NameID

\n"; + echo "

"; + NameIDArrayToHTML($nameID); + echo "

"; + + echo <<Attributes +
+ + +html; + foreach ($attributes as $attrName => $attrVal) { + echo " \n"; + } + echo "
AttributeValue(s)
".AttributeNameToHTML($attrName)."\n"; + if (is_array($attrVal)) { + for ($i=0;$i".htmlentities($attrVal[$i]).""; + } + if ($i+1"; + } + } + } + else + echo htmlentities($attrVal); + echo "
\n"; +} else { + echo <<Your are not logged in

+html; +} + +echo <<Login (again) +
+html; + +$idpOptions=array(); +foreach ($gIDPmap as $i => $v) { + $idpOptions[$i] = $v['name']; +} +HTML_select('Identity Provider: ', 'idp', $idpOptions, $idp, "Select the IdP to authenticate to"); + +HTML_select('Request LOA: ', 'loa', + array( + "" => "None", + "1.5" => "1.5 (self-asserted token LoA)", + "1" => "1", + "2" => "2", + "3" => "3", + ), + $loa, +"Select the level of assurance to include in the AuthnContextClassRef in the AuthnRequest. The value depends on the selected IdP and LoA and is only added when the IdP supports it." +); + +echo << +   
+

+

Advanced options

+html; + // Build direct login link from submitted parameters + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'show' ) { +echo << +
+

+html; + + $params=array(); + foreach ($_REQUEST as $p => $v) { + if (strlen($v) > 0) { + if ($p=='action') { + $v='login'; + } + $params[] = urlencode($p).'='.urlencode($v); + } + } + sort($params); + $params=implode('&', $params); + $login_link=strlen($_SERVER['HTTPS']) > 0 ? 'https://' : 'http://'; + $login_link.=$_SERVER['HTTP_HOST']; + $login_link.=$_SERVER['SCRIPT_NAME']."?".$params; + echo "

"; + echo "".htmlentities($login_link)."


\n"; + echo "


"; + } + else { +echo << +
+

+html; + } + + HTML_select("Service Provider EnityID: ", "sp", + array( + 'default-sp'=>'default-sp', + 'second-sp'=>'second-sp', + 'third-sp'=>'third-sp', + 'fourth-sp'=>'fourth-sp' + ), + $sp, + "Select the EnitytID to use for this SP. This value goes into the Issuer in the AuthnRequest." + ); + HTML_select("Signing: ", "signing", + array( + 'none'=>'none', + 'rsa-sha1'=>'rsa-sha1', + 'rsa-sha256'=>'rsa-sha256', + 'rsa-sha384'=>'rsa-sha384', + 'rsa-sha512'=>'rsa-sha512', + ), + $signing, + "Select the signing algorithm the SP must use to sign the AuthnRequest, select 'none' to disable signing." + ); + + HTML_select("Signing key: ", "key", + array( + 'default'=>'default', + 'secondary'=>'secondary', + ), + $key, + "Select the key the SP must use for signing the AuthnRequest. The default key is the key that is present in the SP metadata." + ); + + HTML_select("NameIDPolicy: ", "nameidpolicy", + array( + '' => 'None', + 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified' => 'unspecified', + 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' => 'persistent', + 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' => 'transient', + ), + $nameidpolicy, + "Select the NameID policy that the SP should request from the IdP. This value is put in the of the Format attribute in the NameIDPolicy in AuthnRequest. 'None' uses the simpleSAMLphp default behaviour based on the metadata SP and IdP metadata." + ); + + HTML_select("SSO Binding: ", "ssobinding", + array( + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect' => 'HTTP-Redirect', + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' => 'HTTP-POST', + ), + $ssobinding, + "Specify the SAML Binding that the SP must use to send the AuthnRequest to the IdP." + ); + +$commonSPs_datalist= +<< + + +html; +$commonIDPs_datalist= +<< + + + +html; + +$sspACSURL = SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'); +$sspDebugSPACSURL = SimpleSAML\Module::getModuleURL('DebugSP/sp/saml2-acs.php/'); + +$emulateADFSchecked = isset($_REQUEST['emulateadfs']) && $_REQUEST['emulateadfs'] == 'true' ? ' checked' : ''; +$forceAuthnChecked = isset($_REQUEST['forceauthn']) && $_REQUEST['forceauthn'] == 'true' ? ' checked' : ''; + +echo << +
+{$commonSPs_datalist} +
+{$commonSPs_datalist} +

+

+
+{$commonIDPs_datalist} +
+{$commonIDPs_datalist} +

+

+ + + +

+

+
+

+

+ + + +

+

+
+

+ +

+   
+

+
+html; + +$SAMLResponse = $session->getData('string', 'SAML2Keeper_SAMLResponse'); +if ($SAMLResponse) +{ + echo '

SAMLResponse

'; + $SAMLResponse = base64_decode($SAMLResponse); + if (false !== $SAMLResponse) + { + $document = new DOMDocument(); + $document->loadXML($SAMLResponse); + $xml = $document->firstChild; + + //$msg = new SAML2_Response($xml); + $response_IssueInstant = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/@IssueInstant'); + $assertion_IssueInstant = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/@IssueInstant'); + $condition_NotBefore = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/saml_assertion:Conditions/@NotBefore'); + $condition_NotOnOrAfter = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/saml_assertion:Conditions/@NotOnOrAfter'); + $audience_Restriction = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/saml_assertion:Conditions/saml_assertion:AudienceRestriction/saml:Audience'); + $assertion_AuthnInstant = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/saml_assertion:AuthnStatement/@AuthnInstant'); + $SessionNotOnOrAfter = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/saml_assertion:AuthnStatement/@SessionNotOnOrAfter'); + $SessionIndex = SAML2_Utils::xpQuery($xml, '/saml_protocol:Response/saml_assertion:Assertion/saml_assertion:AuthnStatement/@SessionIndex' ); + echo "

Response

"; + echo "IssueInstant: ".XMLTextNode2HTML_TS($response_IssueInstant)."
"; + echo "

Assertion

"; + echo "IssueInstant: ".XMLTextNode2HTML_TS($assertion_IssueInstant)."
"; + echo "Condition NotBefore: ".XMLTextNode2HTML_TS($condition_NotBefore)."
"; + echo "Condition NotOnOrAfter: ".XMLTextNode2HTML_TS($condition_NotOnOrAfter)."
"; + echo "AudienceRestriction: ".XMLTextNode2HTML($audience_Restriction)."
"; + echo "AuthnInstant: ".XMLTextNode2HTML_TS($assertion_AuthnInstant)."
"; + echo "SessionNotOnOrAfter: ".XMLTextNode2HTML_TS($SessionNotOnOrAfter)."
"; + echo "SessionIndex: ".XMLTextNode2HTML($SessionIndex)."
"; + echo '
';
+        echo htmlentities($SAMLResponse);
+        echo '
'; + } + else + { + echo 'Error decoding SAMLResponse (invalid base64)
'; + } +} + +echo << + +html; +