[java-idp-integration-tests] branch main updated: Initial test for consent with isPassive=true
Codeberg
noreply at shibboleth.net
Sat Nov 15 00:09:29 UTC 2025
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-idp-integration-tests.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-integration-tests/commit/bed8820e5a8c47186bea1792669434d58b13bd41
The following commit(s) were added to refs/heads/main by this push:
new bed8820 Initial test for consent with isPassive=true
bed8820 is described below
commit bed8820e5a8c47186bea1792669434d58b13bd41
Author: Tom Zeller <tzeller at dragonacea.biz>
AuthorDate: Fri Nov 14 18:09:01 2025 -0600
Initial test for consent with isPassive=true
https://shibboleth.atlassian.net/browse/IDP-2409
---
src/test/docker/shib-tests-sp/Dockerfile | 68 +++++
src/test/docker/shib-tests-sp/docker-compose.yml | 27 ++
.../shib-tests-sp/etc/httpd/conf.d/shib.conf | 59 ++++
.../shib-tests-sp/etc/pki/tls/certs/.gitignore | 2 +
.../shib-tests-sp/etc/pki/tls/private/.gitignore | 2 +
.../shib-tests-sp/etc/shibboleth/idp-metadata.xml | 79 ++++++
.../shib-tests-sp/etc/shibboleth/shibboleth2.xml | 116 ++++++++
.../etc/shibboleth/sp-encrypt-cert.pem | 25 ++
.../etc/shibboleth/sp-encrypt-key.pem | 40 +++
.../shib-tests-sp/etc/shibboleth/sp-metadata.xml | 120 ++++++++
.../etc/shibboleth/sp-signing-cert.pem | 25 ++
.../etc/shibboleth/sp-signing-key.pem | 40 +++
src/test/docker/shib-tests-sp/etc/supervisord.conf | 32 +++
.../shib-tests-sp/etc/yum.repos.d/shibboleth.repo | 9 +
.../docker/shib-tests-sp/var/www/cgi-bin/printenv | 26 ++
.../docker/shib-tests-sp/var/www/html/index.html | 10 +
.../shib-tests-sp/var/www/html/secure/index.html | 10 +
.../tests/consent/PassiveConsentTest.java | 225 +++++++++++++++
.../idp/integration/tests/consent/SPContainer.java | 304 +++++++++++++++++++++
19 files changed, 1219 insertions(+)
diff --git a/src/test/docker/shib-tests-sp/Dockerfile b/src/test/docker/shib-tests-sp/Dockerfile
new file mode 100644
index 0000000..bec090f
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/Dockerfile
@@ -0,0 +1,68 @@
+# Run httpd + shibboleth on Rocky Linux.
+#
+# Provides URLs which display the following :
+# / : "Hello world"
+# /secure/ : "Secure"
+# /cgi-bin/printenv/ : environment variables
+#
+# Only the /secure/ path is protected by the Shibboleth SP.
+
+# Use Rocky Linux 9 base image.
+FROM rockylinux:9
+
+# Enable Shibboleth repository
+COPY etc/yum.repos.d/shibboleth.repo /etc/yum.repos.d/shibboleth.repo
+
+# Install Apache with mod_auth_openidc.
+# Include perl for /cgi-bin/printenv.
+RUN dnf clean all && \
+ dnf install -y epel-release && \
+ dnf update -y && \
+ dnf install -y \
+ openssl \
+ httpd \
+ mod_ssl \
+ shibboleth \
+ perl \
+ supervisor \
+ libfaketime \
+ && dnf clean all \
+ && rm -rf /var/cache/yum
+
+# Replace ServerName with environment variable or the default 'sp.tests.shibboleth.net'.
+ENV ServerName=sp.tests.shibboleth.net
+
+RUN sed -i -e 's/#ServerName www.example.com:80/ServerName ${ServerName}:80/' /etc/httpd/conf/httpd.conf
+RUN sed -i -e 's/#ServerName www.example.com:443/ServerName ${ServerName}:443/' /etc/httpd/conf.d/ssl.conf
+
+# Enable httpd debug logging.
+# RUN sed -i -e 's/LogLevel warn/LogLevel debug/' /etc/httpd/conf.d/ssl.conf
+
+# Copy demo web pages, non-secure displays "Hello world" while secure displays "Secure".
+COPY var/www/html/index.html /var/www/html/index.html
+COPY var/www/html/secure/index.html /var/www/html/secure/index.html
+
+# Enable printenv
+COPY var/www/cgi-bin/printenv /var/www/cgi-bin/printenv
+RUN chmod ugo+x /var/www/cgi-bin/printenv
+
+# Copy Shibboleth SP configuration files
+COPY etc/shibboleth/ /etc/shibboleth/
+
+# Load Shibboleth module in Apache
+COPY etc/httpd/conf.d/shib.conf /etc/httpd/conf.d/shib.conf
+
+# Create temporary directory and chown to shibd since
+# supervisord runs shibd as the shibd user.
+RUN mkdir /var/run/shibboleth
+RUN chown shibd:shibd /var/run/shibboleth
+
+# Expose http and https ports.
+EXPOSE 80 443
+
+# Run httpd as apache user.
+RUN chown -R apache:apache /var/log/httpd
+RUN chown -R apache:apache /run/httpd
+
+COPY etc/supervisord.conf /etc/supervisord.conf
+CMD ["/usr/bin/supervisord", "--configuration=/etc/supervisord.conf", "--silent"]
diff --git a/src/test/docker/shib-tests-sp/docker-compose.yml b/src/test/docker/shib-tests-sp/docker-compose.yml
new file mode 100644
index 0000000..ba2faff
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/docker-compose.yml
@@ -0,0 +1,27 @@
+# Example Docker Compose file to run the test SP container.
+#
+# Docker Compose is not used by the integration tests (they use TestContainers.com).
+# Note that the ServerName is defined as an environment variable.
+#
+# TLS cert and key should be copied to etc/pki/tls/.
+#
+services:
+ shib-tests-sp:
+ container_name: shib-tests-sp
+ image: shib-tests-sp
+ build: .
+ environment:
+ - ServerName=${ServerName:-sp.tests.shibboleth.net}
+ extra_hosts:
+ - "idp.tests.shibboleth.net:host-gateway"
+ hostname: ${ServerName:-sp.tests.shibboleth.net}
+ ports:
+ - "30080:80"
+ - "30443:443"
+ volumes:
+ - ${tlsCert:-./etc/pki/tls/certs/fullchain.cer}:/etc/pki/tls/certs/localhost.crt
+ - ${tlsKey:-./etc/pki/tls/private/tests.shibboleth.net.key}:/etc/pki/tls/private/localhost.key
+
+networks:
+ default:
+ name: shib-tests-network
diff --git a/src/test/docker/shib-tests-sp/etc/httpd/conf.d/shib.conf b/src/test/docker/shib-tests-sp/etc/httpd/conf.d/shib.conf
new file mode 100644
index 0000000..6092ae7
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/httpd/conf.d/shib.conf
@@ -0,0 +1,59 @@
+# https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPApacheConfig
+
+# RPM installations on platforms with a conf.d directory will
+# result in this file being copied into that directory for you
+# and preserved across upgrades.
+
+# For non-RPM installs, you should copy the relevant contents of
+# this file to a configuration location you control.
+
+#
+# Load the Shibboleth module.
+#
+LoadModule mod_shib /usr/lib64/shibboleth/mod_shib_24.so
+
+#
+# Turn this on to support "require valid-user" rules from other
+# mod_authn_* modules, and use "require shib-session" for anonymous
+# session-based authorization in mod_shib.
+#
+ShibCompatValidUser Off
+
+#
+# Ensures handler will be accessible.
+#
+<Location /Shibboleth.sso>
+ AuthType None
+ Require all granted
+</Location>
+
+#
+# Used for example style sheet in error templates.
+#
+<IfModule mod_alias.c>
+ <Location /shibboleth-sp>
+ AuthType None
+ Require all granted
+ </Location>
+ Alias /shibboleth-sp/main.css /usr/share/shibboleth/main.css
+</IfModule>
+
+#
+# Configure the module for content.
+#
+# You MUST enable AuthType shibboleth for the module to process
+# any requests, and there MUST be a require command as well. To
+# enable Shibboleth but not specify any session/access requirements
+# use "require shibboleth".
+#
+<Location /secure>
+ AuthType shibboleth
+ ShibRequestSetting requireSession 1
+ require shib-session
+</Location>
+
+<Location /cgi-bin/printenv>
+ AuthType shibboleth
+ ShibRequestSetting requireSession 1
+ require shib-session
+</Location>
diff --git a/src/test/docker/shib-tests-sp/etc/pki/tls/certs/.gitignore b/src/test/docker/shib-tests-sp/etc/pki/tls/certs/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/pki/tls/certs/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/src/test/docker/shib-tests-sp/etc/pki/tls/private/.gitignore b/src/test/docker/shib-tests-sp/etc/pki/tls/private/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/pki/tls/private/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/idp-metadata.xml b/src/test/docker/shib-tests-sp/etc/shibboleth/idp-metadata.xml
new file mode 100644
index 0000000..b6a91d8
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/idp-metadata.xml
@@ -0,0 +1,79 @@
+<!--
+ This is example metadata only. Do *NOT* supply it as is without review,
+and do *NOT* provide it in real time to your partners.
+This metadata is not dynamic - it will not change as your configuration changes.
+On Demand Metadata Generation available from the metadatagen plugin.
+-->
+<md:EntityDescriptor entityID="https://idp.example.org" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+ <md:Extensions>
+ <shibmd:Scope regexp="false">example.org</shibmd:Scope>
+ <mdui:UIInfo>
+ <mdui:DisplayName xml:lang="en">A name for the IdP at idp.tests.shibboleth.net</mdui:DisplayName>
+ <mdui:Description xml:lang="en">Enter a description for the IdP at idp.tests.shibboleth.net</mdui:Description>
+ <mdui:Logo xml:lang="en" width="80" height="80">https://idp.tests.shibboleth.net/path/to/logo.png</mdui:Logo>
+ </mdui:UIInfo>
+ </md:Extensions>
+ <md:KeyDescriptor use="signing">
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>
+ MIIDtTCCAp2gAwIBAgIJAPmsD+VGldyPMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+ BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+ aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDExMTMzOTE4WhcNMjQwNDA4MTMzOTE4WjBF
+ MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
+ ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+ CgKCAQEAxg0TyQAP/tIvOH89EtaXuRRn8SYzTj7W1TbNY4VvBmobjkRmSkki4hH9
+ x4sQpi635wn6WtXTN/FNNmkTK3N/LspmBWxfZS+n+cc7I82E5yvCAPX67QsZgqgg
+ lp2W5dvK/FsMMCS6X6SVqzBLMP88NenXKxY+HMxMs0sT0UKYh1cAEqadrHRBO65a
+ DBcm5a0sBVYt9K6pgaOHrp/zSIbhnR5tFFLjBbtFktDpHL3AdGBH3OYidNGKBO3t
+ J3Ms7LeKXsM0+0Y4P+9fHZINL2X3E2N6GVnKs5PZTg9sP0FtIpAbYm/+zCx7Yj1E
+ T/Er8mDd6tNVGSQsn9s5xUBwGqn14wIDAQABo4GnMIGkMB0GA1UdDgQWBBSiQhSu
+ p9BYjD2ZuMkEiQK7w/Zq0TB1BgNVHSMEbjBsgBSiQhSup9BYjD2ZuMkEiQK7w/Zq
+ 0aFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
+ BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPmsD+VGldyPMAwGA1UdEwQF
+ MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHZmIo9GBTSsD5DJfKkCVUvBafwR089H
+ BkgVPOuVuEe803BRlKd4BVIsuxAUAy3oqdJYqf9ptPEx8Ef+ALbcDhRbWINhMgO7
+ 0/S4x3pS9gOn7/Y9yZplOe4Jd2q3R8QBef+hKLcD/Uv0Sqy2nilM8BnMga5tqsL+
+ 8oFt0blzXtQ2vcOVyNyG326uZBZv2Cf6FXFsYQX1L/tLeTBJegefgGkg2dqCTKIU
+ 1Qy/Kd2P3/S01kQxjDeG7UfXc9qtelJ68kvzK2d3WOJ2qmsdMxjMNfTItP7FO54M
+ i8V7gp9HK+EimdSbgu7xktKlrqA2Rsn+dBoPSgOUs/LOGtCS9/biF0w=
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+ <md:KeyDescriptor use="encryption">
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>
+ MIIDtTCCAp2gAwIBAgIJAPmsD+VGldyPMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+ BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+ aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDExMTMzOTE4WhcNMjQwNDA4MTMzOTE4WjBF
+ MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
+ ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+ CgKCAQEAxg0TyQAP/tIvOH89EtaXuRRn8SYzTj7W1TbNY4VvBmobjkRmSkki4hH9
+ x4sQpi635wn6WtXTN/FNNmkTK3N/LspmBWxfZS+n+cc7I82E5yvCAPX67QsZgqgg
+ lp2W5dvK/FsMMCS6X6SVqzBLMP88NenXKxY+HMxMs0sT0UKYh1cAEqadrHRBO65a
+ DBcm5a0sBVYt9K6pgaOHrp/zSIbhnR5tFFLjBbtFktDpHL3AdGBH3OYidNGKBO3t
+ J3Ms7LeKXsM0+0Y4P+9fHZINL2X3E2N6GVnKs5PZTg9sP0FtIpAbYm/+zCx7Yj1E
+ T/Er8mDd6tNVGSQsn9s5xUBwGqn14wIDAQABo4GnMIGkMB0GA1UdDgQWBBSiQhSu
+ p9BYjD2ZuMkEiQK7w/Zq0TB1BgNVHSMEbjBsgBSiQhSup9BYjD2ZuMkEiQK7w/Zq
+ 0aFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
+ BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPmsD+VGldyPMAwGA1UdEwQF
+ MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHZmIo9GBTSsD5DJfKkCVUvBafwR089H
+ BkgVPOuVuEe803BRlKd4BVIsuxAUAy3oqdJYqf9ptPEx8Ef+ALbcDhRbWINhMgO7
+ 0/S4x3pS9gOn7/Y9yZplOe4Jd2q3R8QBef+hKLcD/Uv0Sqy2nilM8BnMga5tqsL+
+ 8oFt0blzXtQ2vcOVyNyG326uZBZv2Cf6FXFsYQX1L/tLeTBJegefgGkg2dqCTKIU
+ 1Qy/Kd2P3/S01kQxjDeG7UfXc9qtelJ68kvzK2d3WOJ2qmsdMxjMNfTItP7FO54M
+ i8V7gp9HK+EimdSbgu7xktKlrqA2Rsn+dBoPSgOUs/LOGtCS9/biF0w=
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.tests.shibboleth.net/idp/profile/SAML2/SOAP/Redirect/SLO" />
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.tests.shibboleth.net/idp/profile/SAML2/POST/SLO" />
+ <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://idp.tests.shibboleth.net/idp/profile/SAML2/POST-SimpleSign/SSO" />
+ <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.tests.shibboleth.net/idp/profile/SAML2/Redirect/SSO" />
+ <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.tests.shibboleth.net/idp/profile/SAML2/POST/SSO" />
+ </md:IDPSSODescriptor>
+</md:EntityDescriptor>
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/shibboleth2.xml b/src/test/docker/shib-tests-sp/etc/shibboleth/shibboleth2.xml
new file mode 100644
index 0000000..c389e87
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/shibboleth2.xml
@@ -0,0 +1,116 @@
+<SPConfig xmlns="urn:mace:shibboleth:3.0:native:sp:config"
+ xmlns:conf="urn:mace:shibboleth:3.0:native:sp:config"
+ clockSkew="180">
+
+ <OutOfProcess tranLogFormat="%u|%s|%IDP|%i|%ac|%t|%attr|%n|%b|%E|%S|%SS|%L|%UA|%a" />
+
+ <!--
+ By default, in-memory StorageService, ReplayCache, ArtifactMap, and SessionCache
+ are used. See example-shibboleth2.xml for samples of explicitly configuring them.
+ -->
+
+ <!-- The ApplicationDefaults element is where most of Shibboleth's SAML bits are defined. -->
+ <ApplicationDefaults entityID="https://sp.tests.shibboleth.net/shibboleth"
+ REMOTE_USER="eppn subject-id pairwise-id persistent-id"
+ cipherSuites="DEFAULT:!EXP:!LOW:!aNULL:!eNULL:!DES:!IDEA:!SEED:!RC4:!3DES:!kRSA:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1">
+
+ <!--
+ Controls session lifetimes, address checks, cookie handling, and the protocol handlers.
+ Each Application has an effectively unique handlerURL, which defaults to "/Shibboleth.sso"
+ and should be a relative path, with the SP computing the full value based on the virtual
+ host. Use of TLS is now assumed because browsers are enforcing it due to SameSite
+ restrictions. Note that while we default checkAddress to "false", this makes an assertion
+ stolen in transit easier for attackers to misuse.
+ -->
+ <Sessions lifetime="28800" timeout="3600" relayState="ss:mem"
+ checkAddress="false" handlerSSL="true" cookieProps="https"
+ redirectLimit="exact">
+
+ <!--
+ Configures SSO for a default IdP. To properly allow for >1 IdP, remove
+ entityID property and adjust discoveryURL to point to discovery service.
+ You can also override entityID on /Login query string, or in RequestMap/htaccess.
+ -->
+ <SSO entityID="https://idp.example.org">
+ SAML2
+ </SSO>
+
+ <!-- SAML and local-only logout. -->
+ <Logout>SAML2 Local</Logout>
+
+ <!-- Administrative logout. -->
+ <LogoutInitiator type="Admin" Location="/Logout/Admin" acl="127.0.0.1 ::1" />
+
+ <!-- Extension service that generates "approximate" metadata based on SP configuration. -->
+ <Handler type="MetadataGenerator" Location="/Metadata" signing="false"/>
+
+ <!-- Status reporting service. -->
+ <Handler type="Status" Location="/Status" acl="127.0.0.1 ::1"/>
+
+ <!-- Session diagnostic service. -->
+ <Handler type="Session" Location="/Session" showAttributeValues="false"/>
+
+ <!-- JSON feed of discovery information. -->
+ <Handler type="DiscoveryFeed" Location="/DiscoFeed"/>
+ </Sessions>
+
+ <!--
+ Allows overriding of error template information/filenames. You can
+ also add your own attributes with values that can be plugged into the
+ templates, e.g., helpLocation below.
+ -->
+ <Errors supportContact="root at localhost"
+ helpLocation="/about.html"
+ styleSheet="/shibboleth-sp/main.css"/>
+
+ <!-- Example of locally maintained metadata. -->
+ <!--
+ <MetadataProvider type="XML" validate="true" path="partner-metadata.xml"/>
+ -->
+
+ <!-- Example of remotely supplied batch of signed metadata. -->
+ <!--
+ <MetadataProvider type="XML" validate="true"
+ url="http://federation.org/federation-metadata.xml"
+ backingFilePath="federation-metadata.xml" maxRefreshDelay="7200">
+ <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>
+ <MetadataFilter type="Signature" certificate="fedsigner.pem" verifyBackup="false"/>
+ <DiscoveryFilter type="Exclude" matcher="EntityAttributes" trimTags="true"
+ attributeName="http://macedir.org/entity-category"
+ attributeNameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
+ attributeValue="http://refeds.org/category/hide-from-discovery" />
+ </MetadataProvider>
+ -->
+
+ <!-- Example of remotely supplied "on-demand" signed metadata. -->
+ <!--
+ <MetadataProvider type="MDQ" validate="true" cacheDirectory="mdq"
+ baseUrl="http://mdq.federation.org" ignoreTransport="true">
+ <MetadataFilter type="RequireValidUntil" maxValidityInterval="2419200"/>
+ <MetadataFilter type="Signature" certificate="mdqsigner.pem" />
+ </MetadataProvider>
+ -->
+
+ <MetadataProvider type="XML" validate="true" path="idp-metadata.xml"/>
+
+ <!-- Map to extract attributes from SAML assertions. -->
+ <AttributeExtractor type="XML" validate="true" reloadChanges="false" path="attribute-map.xml"/>
+
+ <!-- Default filtering policy for recognized attributes, lets other data pass. -->
+ <AttributeFilter type="XML" validate="true" path="attribute-policy.xml"/>
+
+ <!-- Simple file-based resolvers for separate signing/encryption keys. -->
+ <CredentialResolver type="File" use="signing"
+ key="sp-signing-key.pem" certificate="sp-signing-cert.pem"/>
+ <CredentialResolver type="File" use="encryption"
+ key="sp-encrypt-key.pem" certificate="sp-encrypt-cert.pem"/>
+
+ </ApplicationDefaults>
+
+ <!-- Policies that determine how to process and authenticate runtime messages. -->
+ <SecurityPolicyProvider type="XML" validate="true" path="security-policy.xml"/>
+
+ <!-- Low-level configuration about protocols and bindings available for use. -->
+ <ProtocolProvider type="XML" validate="true" reloadChanges="false" path="protocols.xml"/>
+
+</SPConfig>
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/sp-encrypt-cert.pem b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-encrypt-cert.pem
new file mode 100644
index 0000000..f6c7731
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-encrypt-cert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAqugAwIBAgIUDvgaHmnHrCSksyAqJoa+1euneUEwDQYJKoZIhvcNAQEL
+BQAwIjEgMB4GA1UEAxMXc3AudGVzdHMuc2hpYmJvbGV0aC5uZXQwHhcNMjUxMTEw
+MjM1NjQwWhcNMzUxMTA4MjM1NjQwWjAiMSAwHgYDVQQDExdzcC50ZXN0cy5zaGli
+Ym9sZXRoLm5ldDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAOdco92D
+1kXYs4jNd10DctSdx07FtWbeSrxzixWpwejOJSLr8i49HD56VMZ1UPO2KxGtZ9F5
+JJ5eEmjzEsiJZcVUbddLpdmb6sGvZnHh4wrAMXS2JgWo55vMv3g2kwfHafYPtRqx
+qCJbfwKHQhDbZRyb/g9fQQr3eEVUSYtO127fdaY0MGe06xSyufQYWtvzz1/D7Z51
+UqTLs6I9N5gKR/+9O3x0v20/Gp1GrMkPpjIcHlAPuNFQolPYhkgYpN/W9mqtx5GR
+V2ybMZyBxlwB567QbgqMJxIoFNtS3YjfVpLPsaBv1Nri2NGOkvWhnfUpV9MieYie
+rV+k4KrsNQ06oc68fl0tjm4OyOu+XwK8tdCIIoV/v/0BMDxGOC3JffZoY/RQci2D
+6GvpUsB2Cr8fBvDS9ACTD/JSkZKj2yGJsnK/Ae6fQAZ+Im3h9+jPQxFhczidDM7s
+BeYAbcGtR0t0WTW2Rxj3vaZVMS/i5tlX8Uo45CbxntloblkDa8yoOBCZSwIDAQAB
+o3EwbzBOBgNVHREERzBFghdzcC50ZXN0cy5zaGliYm9sZXRoLm5ldIYqaHR0cHM6
+Ly9zcC50ZXN0cy5zaGliYm9sZXRoLm5ldC9zaGliYm9sZXRoMB0GA1UdDgQWBBTg
+7u4kVLhSD8vIaLXW7QED1WisSDANBgkqhkiG9w0BAQsFAAOCAYEAfH5/u/5Cj3w/
+lM37NDeUDKkKUH1LdZ5iCjShkKNaKpV91GyRhDAkBEM2pVSkWqa2o0q3SKy/F1Z4
+1B+TcJZHBOo9oVS2PZM1ZoqebEX48y4Cn8VBTLzzhArpGL95z20FFCBOzF+MuCz3
+gDsDLB9ys5Dnm8gIXJCkJL9xDXary/5r9zCBblg8ljusH92EQU0/060ewzTMAFIr
+OAdh1sNHL9IFi9yrV/gp251D6IUOG9yjTv+4ljQo7yay/9QQtBEn3zaWObcALokB
+RejdoTFEpEv7T7lZVCypLM6240Z7Oqt9384/WKm+5UgCZRXTI1aTIKZCox2Ea0x+
+oflSf8a6VEoTG0AYER3d+HInM83fYabsyQX/1KQY//KhzfuoitXHAvS2KY30u/Cp
+J7wiiRz8Nh65HkPwNLDSZLQSFk36+2Si/TykTBE5ExyYJVmife2QPENKCiqq++7m
+8T5RL2vwnhKbdrq4u7Nw7H9D06fBgp3afS2irNbUZgbjZJ7y+qyK
+-----END CERTIFICATE-----
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/sp-encrypt-key.pem b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-encrypt-key.pem
new file mode 100644
index 0000000..391f83b
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-encrypt-key.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+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
+nxk/cNRlmxe/LmTSmRkvZtU=
+-----END PRIVATE KEY-----
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/sp-metadata.xml b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-metadata.xml
new file mode 100644
index 0000000..b556b50
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-metadata.xml
@@ -0,0 +1,120 @@
+<!--
+This is example metadata only. Do *NOT* supply it as is without review,
+and do *NOT* provide it in real time to your partners.
+ -->
+<md:EntityDescriptor entityID="https://sp.tests.shibboleth.net/shibboleth" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_3282c45ccf4d5b0df797b7729a876ac356c6cfce" >
+
+ <md:Extensions xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport">
+ <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"/>
+ <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha384"/>
+ <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+ <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha224"/>
+ <alg:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2009/xmldsig11#dsa-sha256"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
+ <alg:SigningMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
+ </md:Extensions>
+
+ <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+ <md:Extensions>
+ <init:RequestInitiator xmlns:init="urn:oasis:names:tc:SAML:profiles:SSO:request-init"
+ Binding="urn:oasis:names:tc:SAML:profiles:SSO:request-init"
+ Location="https://sp.tests.shibboleth.net/Shibboleth.sso/Login" />
+ </md:Extensions>
+ <md:KeyDescriptor use="signing">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:KeyName>https://sp.tests.shibboleth.net/shibboleth</ds:KeyName>
+ <ds:KeyName>sp.tests.shibboleth.net</ds:KeyName>
+ <ds:X509Data>
+ <ds:X509SubjectName>CN=sp.tests.shibboleth.net</ds:X509SubjectName>
+ <ds:X509Certificate>
+MIIEQzCCAqugAwIBAgIUWxJO7XpqR99HZ5XS/OKjb0uXBdQwDQYJKoZIhvcNAQEL
+BQAwIjEgMB4GA1UEAxMXc3AudGVzdHMuc2hpYmJvbGV0aC5uZXQwHhcNMjUxMTEw
+MjM1MTM1WhcNMzUxMTA4MjM1MTM1WjAiMSAwHgYDVQQDExdzcC50ZXN0cy5zaGli
+Ym9sZXRoLm5ldDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAIh2620Q
+sBmwLAKNlVWKg2YD7vAJM1QADb7izMYB9LZSL+IrlmsoxouhKqqHfTBoYzaUZOPU
+l+EW7Udc6m+q4j6GfPguxrmrOWYFfpTla4xHvlcQS/791BNWlYp/l65Onw/70nYO
+a2InA/baRlsS2ty9l/7YxMIrbCwsqPQWOdFfv9xgSThgWn2HNIHdAcc8Qg+W7Gf8
+c/vDB9iPXhFemL1uZq08CcLotu/ACqPC28dlTk/ueSrr+ueceAetDmviiLaufXWB
+tU0ZUETC7KtNT2lO8+wSVlQcaqkec9HZQgzfqZqWHdhQur+/PjKl7s0UCRMMuJBs
+uPWj1ffvzNhCZ+0CgGQEZecn3A9xL1bRncByFot2KPfx8ANllec94HGrml4o/YtH
+FiQDECGA3+VbrpckhauyIIQ1ByxkDusVRTKdrrCtJuxbn2JjaWjLHpiBhCg/WaK/
+Yemq+jpw5r77KmdSSWAHLYCTUj/VBx5tMAQe1fo8oMfLkRdbPXtB/CjF9QIDAQAB
+o3EwbzBOBgNVHREERzBFghdzcC50ZXN0cy5zaGliYm9sZXRoLm5ldIYqaHR0cHM6
+Ly9zcC50ZXN0cy5zaGliYm9sZXRoLm5ldC9zaGliYm9sZXRoMB0GA1UdDgQWBBQU
+uj2YPLnPMhnOeptD8yO7PuEwmDANBgkqhkiG9w0BAQsFAAOCAYEAK2PRFM3K8LuO
+jcYOw9+6fRJhdLfkGKrGDdleu6icCV2b9vDlDy2diQSVrUJuepMRC6gPUTi83Cyu
+D9Kp0UjWgMirFLPlA1prsQM6PtBn8S4z/hKIFpr12bTtyQM+Z3TyIyT6Arxx7UpD
+ySm+FuOn9Fn4OH8EO6wnAWOhHF79raLlZvckUNgxczb5ksZp2x1R6UyZK1kDgNUc
+fpBw8WuiZQ6fbhE5md/5K6L8it6n2GrbRtDWeKouoRMIp7MQ/vQe/9LXR2sVBY60
+nq2D30eCr19kx+mQJLZvaGqJsi1D+oV79QYPhyXMYvolG7oBf+z509grxxWygjZ8
+XPJF8N3DJYm0zzwXvtos5U36lujzw/eQVfS/QuYl3CclIInB/ndUmg/wGosB2quG
+lxQlEqq6zZC8ERVndba4YWX/oodYgtgmBjdE3dt5uXih744atAC8Km8oWMR4PLJ/
+F8rqbS6FLy/KUIsziY8yoQtIOsnpDqGvZp8cV8OlHfJ2h3ppx2yb
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+ <md:KeyDescriptor use="encryption">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:KeyName>https://sp.tests.shibboleth.net/shibboleth</ds:KeyName>
+ <ds:KeyName>sp.tests.shibboleth.net</ds:KeyName>
+ <ds:X509Data>
+ <ds:X509SubjectName>CN=sp.tests.shibboleth.net</ds:X509SubjectName>
+ <ds:X509Certificate>
+MIIEQzCCAqugAwIBAgIUDvgaHmnHrCSksyAqJoa+1euneUEwDQYJKoZIhvcNAQEL
+BQAwIjEgMB4GA1UEAxMXc3AudGVzdHMuc2hpYmJvbGV0aC5uZXQwHhcNMjUxMTEw
+MjM1NjQwWhcNMzUxMTA4MjM1NjQwWjAiMSAwHgYDVQQDExdzcC50ZXN0cy5zaGli
+Ym9sZXRoLm5ldDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAOdco92D
+1kXYs4jNd10DctSdx07FtWbeSrxzixWpwejOJSLr8i49HD56VMZ1UPO2KxGtZ9F5
+JJ5eEmjzEsiJZcVUbddLpdmb6sGvZnHh4wrAMXS2JgWo55vMv3g2kwfHafYPtRqx
+qCJbfwKHQhDbZRyb/g9fQQr3eEVUSYtO127fdaY0MGe06xSyufQYWtvzz1/D7Z51
+UqTLs6I9N5gKR/+9O3x0v20/Gp1GrMkPpjIcHlAPuNFQolPYhkgYpN/W9mqtx5GR
+V2ybMZyBxlwB567QbgqMJxIoFNtS3YjfVpLPsaBv1Nri2NGOkvWhnfUpV9MieYie
+rV+k4KrsNQ06oc68fl0tjm4OyOu+XwK8tdCIIoV/v/0BMDxGOC3JffZoY/RQci2D
+6GvpUsB2Cr8fBvDS9ACTD/JSkZKj2yGJsnK/Ae6fQAZ+Im3h9+jPQxFhczidDM7s
+BeYAbcGtR0t0WTW2Rxj3vaZVMS/i5tlX8Uo45CbxntloblkDa8yoOBCZSwIDAQAB
+o3EwbzBOBgNVHREERzBFghdzcC50ZXN0cy5zaGliYm9sZXRoLm5ldIYqaHR0cHM6
+Ly9zcC50ZXN0cy5zaGliYm9sZXRoLm5ldC9zaGliYm9sZXRoMB0GA1UdDgQWBBTg
+7u4kVLhSD8vIaLXW7QED1WisSDANBgkqhkiG9w0BAQsFAAOCAYEAfH5/u/5Cj3w/
+lM37NDeUDKkKUH1LdZ5iCjShkKNaKpV91GyRhDAkBEM2pVSkWqa2o0q3SKy/F1Z4
+1B+TcJZHBOo9oVS2PZM1ZoqebEX48y4Cn8VBTLzzhArpGL95z20FFCBOzF+MuCz3
+gDsDLB9ys5Dnm8gIXJCkJL9xDXary/5r9zCBblg8ljusH92EQU0/060ewzTMAFIr
+OAdh1sNHL9IFi9yrV/gp251D6IUOG9yjTv+4ljQo7yay/9QQtBEn3zaWObcALokB
+RejdoTFEpEv7T7lZVCypLM6240Z7Oqt9384/WKm+5UgCZRXTI1aTIKZCox2Ea0x+
+oflSf8a6VEoTG0AYER3d+HInM83fYabsyQX/1KQY//KhzfuoitXHAvS2KY30u/Cp
+J7wiiRz8Nh65HkPwNLDSZLQSFk36+2Si/TykTBE5ExyYJVmife2QPENKCiqq++7m
+8T5RL2vwnhKbdrq4u7Nw7H9D06fBgp3afS2irNbUZgbjZJ7y+qyK
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#aes128-gcm"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#aes192-gcm"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#aes256-gcm"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes192-cbc"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#rsa-oaep"/>
+ <md:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
+ </md:KeyDescriptor>
+ <md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/Artifact/SOAP" />
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SLO/SOAP"/>
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SLO/Redirect"/>
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SLO/POST"/>
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SLO/Artifact"/>
+ <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SAML2/POST" index="1"/>
+ <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SAML2/POST-SimpleSign" index="2"/>
+ <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SAML2/Artifact" index="3"/>
+ <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="https://sp.tests.shibboleth.net/Shibboleth.sso/SAML2/ECP" index="4"/>
+ </md:SPSSODescriptor>
+
+</md:EntityDescriptor>
\ No newline at end of file
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/sp-signing-cert.pem b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-signing-cert.pem
new file mode 100644
index 0000000..7e1a730
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-signing-cert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAqugAwIBAgIUWxJO7XpqR99HZ5XS/OKjb0uXBdQwDQYJKoZIhvcNAQEL
+BQAwIjEgMB4GA1UEAxMXc3AudGVzdHMuc2hpYmJvbGV0aC5uZXQwHhcNMjUxMTEw
+MjM1MTM1WhcNMzUxMTA4MjM1MTM1WjAiMSAwHgYDVQQDExdzcC50ZXN0cy5zaGli
+Ym9sZXRoLm5ldDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAIh2620Q
+sBmwLAKNlVWKg2YD7vAJM1QADb7izMYB9LZSL+IrlmsoxouhKqqHfTBoYzaUZOPU
+l+EW7Udc6m+q4j6GfPguxrmrOWYFfpTla4xHvlcQS/791BNWlYp/l65Onw/70nYO
+a2InA/baRlsS2ty9l/7YxMIrbCwsqPQWOdFfv9xgSThgWn2HNIHdAcc8Qg+W7Gf8
+c/vDB9iPXhFemL1uZq08CcLotu/ACqPC28dlTk/ueSrr+ueceAetDmviiLaufXWB
+tU0ZUETC7KtNT2lO8+wSVlQcaqkec9HZQgzfqZqWHdhQur+/PjKl7s0UCRMMuJBs
+uPWj1ffvzNhCZ+0CgGQEZecn3A9xL1bRncByFot2KPfx8ANllec94HGrml4o/YtH
+FiQDECGA3+VbrpckhauyIIQ1ByxkDusVRTKdrrCtJuxbn2JjaWjLHpiBhCg/WaK/
+Yemq+jpw5r77KmdSSWAHLYCTUj/VBx5tMAQe1fo8oMfLkRdbPXtB/CjF9QIDAQAB
+o3EwbzBOBgNVHREERzBFghdzcC50ZXN0cy5zaGliYm9sZXRoLm5ldIYqaHR0cHM6
+Ly9zcC50ZXN0cy5zaGliYm9sZXRoLm5ldC9zaGliYm9sZXRoMB0GA1UdDgQWBBQU
+uj2YPLnPMhnOeptD8yO7PuEwmDANBgkqhkiG9w0BAQsFAAOCAYEAK2PRFM3K8LuO
+jcYOw9+6fRJhdLfkGKrGDdleu6icCV2b9vDlDy2diQSVrUJuepMRC6gPUTi83Cyu
+D9Kp0UjWgMirFLPlA1prsQM6PtBn8S4z/hKIFpr12bTtyQM+Z3TyIyT6Arxx7UpD
+ySm+FuOn9Fn4OH8EO6wnAWOhHF79raLlZvckUNgxczb5ksZp2x1R6UyZK1kDgNUc
+fpBw8WuiZQ6fbhE5md/5K6L8it6n2GrbRtDWeKouoRMIp7MQ/vQe/9LXR2sVBY60
+nq2D30eCr19kx+mQJLZvaGqJsi1D+oV79QYPhyXMYvolG7oBf+z509grxxWygjZ8
+XPJF8N3DJYm0zzwXvtos5U36lujzw/eQVfS/QuYl3CclIInB/ndUmg/wGosB2quG
+lxQlEqq6zZC8ERVndba4YWX/oodYgtgmBjdE3dt5uXih744atAC8Km8oWMR4PLJ/
+F8rqbS6FLy/KUIsziY8yoQtIOsnpDqGvZp8cV8OlHfJ2h3ppx2yb
+-----END CERTIFICATE-----
diff --git a/src/test/docker/shib-tests-sp/etc/shibboleth/sp-signing-key.pem b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-signing-key.pem
new file mode 100644
index 0000000..ae38cad
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/shibboleth/sp-signing-key.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+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
+/8YtuGpO29UNN3mY+zWqwG8=
+-----END PRIVATE KEY-----
diff --git a/src/test/docker/shib-tests-sp/etc/supervisord.conf b/src/test/docker/shib-tests-sp/etc/supervisord.conf
new file mode 100644
index 0000000..d91eab5
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/supervisord.conf
@@ -0,0 +1,32 @@
+[supervisord]
+logfile=/var/log/supervisor/supervisord.log
+nodaemon=true
+user=root
+
+[supervisorctl]
+serverurl=unix:///run/supervisor/supervisor.sock
+username=nobody
+password=password
+
+[unix_http_server]
+file=/run/supervisor/supervisor.sock
+username=nobody
+password=password
+
+[program:httpd]
+command=httpd -DFOREGROUND
+autostart=true
+autorestart=true
+user=apache
+
+[program:shibd]
+command=/usr/sbin/shibd -f -F
+autostart=true
+autorestart=true
+user=shibd
+
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
+
+[include]
+files = supervisord.d/*.ini
diff --git a/src/test/docker/shib-tests-sp/etc/yum.repos.d/shibboleth.repo b/src/test/docker/shib-tests-sp/etc/yum.repos.d/shibboleth.repo
new file mode 100644
index 0000000..2566410
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/etc/yum.repos.d/shibboleth.repo
@@ -0,0 +1,9 @@
+[shibboleth]
+name=Shibboleth (rockylinux9)
+# Please report any problems to https://shibboleth.atlassian.net/jira
+type=rpm-md
+mirrorlist=https://shibboleth.net/cgi-bin/mirrorlist.cgi/rockylinux9
+gpgcheck=1
+gpgkey=https://shibboleth.net/downloads/service-provider/RPMS/repomd.xml.key
+ https://shibboleth.net/downloads/service-provider/RPMS/cantor.repomd.xml.key
+enabled=1
\ No newline at end of file
diff --git a/src/test/docker/shib-tests-sp/var/www/cgi-bin/printenv b/src/test/docker/shib-tests-sp/var/www/cgi-bin/printenv
new file mode 100644
index 0000000..c15db75
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/var/www/cgi-bin/printenv
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+
+# To permit this cgi, replace # on the first line above with the
+# appropriate #!/path/to/perl shebang, and on Unix / Linux also
+# set this script executable with chmod 755.
+#
+# ***** !!! WARNING !!! *****
+# This script echoes the server environment variables and therefore
+# leaks information - so NEVER use it in a live server environment!
+# It is provided only for testing purpose.
+# Also note that it is subject to cross site scripting attacks on
+# MS IE and any other browser which fails to honor RFC2616.
+
+##
+## printenv -- demo CGI program which just prints its environment
+##
+use strict;
+use warnings;
+
+print "Content-type: text/plain; charset=iso-8859-1\n\n";
+foreach my $var (sort(keys(%ENV))) {
+ my $val = $ENV{$var};
+ $val =~ s|\n|\\n|g;
+ $val =~ s|"|\\"|g;
+ print "${var}=\"${val}\"\n";
+}
\ No newline at end of file
diff --git a/src/test/docker/shib-tests-sp/var/www/html/index.html b/src/test/docker/shib-tests-sp/var/www/html/index.html
new file mode 100644
index 0000000..767a6e7
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/var/www/html/index.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Hello World</title>
+</head>
+<body>
+Hello world
+</body>
+</html>
\ No newline at end of file
diff --git a/src/test/docker/shib-tests-sp/var/www/html/secure/index.html b/src/test/docker/shib-tests-sp/var/www/html/secure/index.html
new file mode 100644
index 0000000..020bf1f
--- /dev/null
+++ b/src/test/docker/shib-tests-sp/var/www/html/secure/index.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Secure</title>
+</head>
+<body>
+Secure
+</body>
+</html>
\ No newline at end of file
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/consent/PassiveConsentTest.java b/src/test/java/net/shibboleth/idp/integration/tests/consent/PassiveConsentTest.java
new file mode 100644
index 0000000..ef8a070
--- /dev/null
+++ b/src/test/java/net/shibboleth/idp/integration/tests/consent/PassiveConsentTest.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.integration.tests.consent;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.integration.tests.saml2.AbstractSAML2IntegrationTest;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.net.URISupport;
+
+/**
+ * Test consent with isPassive=true and allow global consent both true and false.
+ */
+public class PassiveConsentTest extends AbstractSAML2IntegrationTest {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PassiveConsentTest.class);
+
+ /** RP Docker containers. */
+ @Nonnull protected final List<SPContainer> sps = new ArrayList<>();
+
+ @BeforeClass
+ public void setUpURLs() throws Exception {
+
+ loginPageURLPath = "/idp/profile/SAML2/Redirect/SSO";
+
+ responsePageURLPath = "/sp/SAML2/POST/ACS";
+ }
+
+ @Test
+ /**
+ * Test consent with isPassive=true and global consent allowed (the default).
+ *
+ * @throws Exception
+ * if an error occurs
+ */
+ public void testIdP2409() throws Exception {
+
+ // Start SP
+
+ final SPContainer sp = startSP("shib-test-sp");
+
+ // Set up SP metadata with runtime port
+
+ setUpSPMetadata(sp.httpsPort);
+
+ // Start browser
+
+ startBrowser();
+
+ // Start IdP
+
+ startServer();
+
+ // Start flow at SP
+
+ final String target = sp.getBaseURL() + "/cgi-bin/printenv";
+
+ final String startFlowURL = sp.getBaseURL() + "/Shibboleth.sso/Login?target=" + URISupport.doURLEncode(target);
+
+ driver.get(startFlowURL);
+
+ // login
+
+ waitForLoginPage();
+
+ login();
+
+ // attribute release
+
+ waitForAttributeReleasePage();
+
+ // start flow again with isPassive=true
+
+ driver.get(startFlowURL + "&isPassive=true");
+
+ // should see NoPassive error
+
+ waitForPageBodyContains("Status: urn:oasis:names:tc:SAML:2.0:status:Requester");
+ waitForPageBodyContains("Sub-Status: urn:oasis:names:tc:SAML:2.0:status:NoPassive");
+ waitForPageBodyContains("Message: An error occurred");
+ }
+
+ @Test(enabled = false)
+ /**
+ * Test consent with isPassive=true and global consent not allowed.
+ *
+ * @throws Exception
+ * if an error occurs
+ */
+ public void testIdP2409AllowGlobalFalse() throws Exception {
+
+ // Do not allow global consent
+
+ replaceIdPProperty("idp.consent.allowGlobal", "false");
+
+ testIdP2409();
+ }
+
+ /**
+ * Set up metadata about/for the SP.
+ *
+ * Copies SP metadata to idp.home/metadata/sp-metadata.xml
+ *
+ * Updates port in SP metadata.
+ *
+ * Add SP metadata to the IdP.
+ *
+ * @throws Exception
+ * if an error occurs
+ */
+
+ public void setUpSPMetadata(@Nonnull final Integer port) throws Exception {
+
+ // Copy SP metadata to idp.home
+
+ final Path pathToDockerDir = Paths.get("src", "test", "docker");
+
+ final Path pathToImage = pathToDockerDir.resolve("shib-tests-sp");
+
+ final Path pathToImageSPMetadata = pathToImage.resolve(Paths.get("etc", "shibboleth", "sp-metadata.xml"));
+
+ final Path pathToSPMetadata = pathToIdPHome.toAbsolutePath().resolve("metadata").resolve("sp-metadata.xml");
+
+ Files.copy(pathToImageSPMetadata, pathToSPMetadata);
+
+ // Update port in SP metadata
+
+ replaceIdPHomeFile(pathToSPMetadata, //
+ "Location=\"https://sp.tests.shibboleth.net/",
+ "Location=\"https://sp.tests.shibboleth.net:" + port + "/");
+
+ // Enable SP metadata
+
+ final Path pathToMetadataProvidersXML = Paths.get("conf", "metadata-providers.xml");
+
+ final String oldText = "</MetadataProvider>";
+
+ final String newText = "<MetadataProvider id=\"SP\" xsi:type=\"FilesystemMetadataProvider\" metadataFile=\"%{idp.home}/metadata/sp-metadata.xml\" />"
+ + System.lineSeparator() + "</MetadataProvider>";
+
+ replaceIdPHomeFile(pathToMetadataProvidersXML, oldText, newText);
+ }
+
+ /**
+ * Set path to SP keystore to be credentials/idp-userfacing.p12 in either jetty-base/ or tomcat-base/ directories.
+ *
+ * @param sp
+ * the SP container
+ */
+ protected void setUpSKeyStore(final SPContainer sp) {
+
+ final Path pathToContainerBase = pathToJettyBase != null ? pathToJettyBase : pathToTomcatBase;
+
+ final Path pathToKeyStore = pathToContainerBase.resolve((Paths.get("credentials", "idp-userfacing.p12")));
+
+ log.debug("Path to key store '{}'", pathToKeyStore);
+
+ sp.setKeyStore(pathToKeyStore.toAbsolutePath().toString());
+ }
+
+ /**
+ * Start SP.
+ *
+ * @param id
+ * the id for logging
+ * @return the SP container
+ * @throws ComponentInitializationException
+ * if an error occurs
+ */
+ protected SPContainer startSP(@Nonnull final String id) throws ComponentInitializationException {
+
+ final SPContainer sp = new SPContainer();
+
+ sps.add(sp);
+
+ sp.setId(id);
+
+ sp.setIdPMetadata(pathToIdPHome.resolve(Paths.get("metadata", "idp-metadata.xml")));
+
+ setUpSKeyStore(sp);
+
+ sp.initialize();
+
+ sp.start();
+
+ return sp;
+ }
+
+ /**
+ * Stop all SPs.
+ */
+ @AfterMethod()
+ protected void stopSPs() {
+ for (final SPContainer sp : sps) {
+ if (sp != null && sp.isRunning()) {
+ sp.stop();
+ }
+ }
+ }
+}
diff --git a/src/test/java/net/shibboleth/idp/integration/tests/consent/SPContainer.java b/src/test/java/net/shibboleth/idp/integration/tests/consent/SPContainer.java
new file mode 100644
index 0000000..6281a75
--- /dev/null
+++ b/src/test/java/net/shibboleth/idp/integration/tests/consent/SPContainer.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.integration.tests.consent;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.Lifecycle;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.images.builder.ImageFromDockerfile;
+import org.testcontainers.images.builder.Transferable;
+import org.testcontainers.utility.MountableFile;
+
+import net.shibboleth.idp.integration.tests.BaseTest;
+import net.shibboleth.idp.integration.tests.util.CertificateHelper;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Start and stop a Shibboleth Service Provider (SP) Docker container.
+ *
+ * Ports are defined after the container is started.
+ *
+ * Default ServerName is sp.tests.shibboleth.net, may be overridden as system property.
+ *
+ * The TLS certificate and key for the RP are extracted from a P12 keystore. The path to the keystore must be set and
+ * the password provided as an environment variable.
+ *
+ * See src/test/docker/shib-tests-rp for Dockerfile and container files.
+ */
+public class SPContainer extends AbstractIdentifiableInitializableComponent implements Lifecycle {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(SPContainer.class);
+
+ /** Cached log prefix. */
+ @Nullable private String logPrefix;
+
+ /** The Docker container. */
+ @NonnullAfterInit public GenericContainer<?> container;
+
+ /** Exposed HTTP port. */
+ @Nullable public Integer httpPort;
+
+ /** Exposed HTTPS port. */
+ @Nullable public Integer httpsPort;
+
+ /** Name of Docker image. */
+ @Nonnull public String imageName = "shib-tests-sp";
+
+ /** IdP hostname or FQDN, defaults to "idp.tests.shibboleth.net" */
+ @Nonnull private String idpHost = "idp.tests.shibboleth.net";
+
+ /** SP hostname or FQDN, defaults to "sp.tests.shibboleth.net" */
+ @Nonnull public String spHost = "sp.tests.shibboleth.net";
+
+ /** Path to TLS keystore in P12 format. */
+ @NonnullAfterInit private Path pathToKeyStore;
+
+ /** Path to the IdP metadata. */
+ @NonnullAfterInit private Path pathToIdPMetadata;
+
+ /**
+ * Path to image directory src/test/docker/{@link #imageName}.
+ *
+ * @return path to image directory
+ */
+ protected Path pathToImage() {
+
+ final Path pathToImage = Paths.get("src", "test", "docker").resolve(imageName);
+
+ log.trace("{} Path to image '{}' directory '{}'", getLogPrefix(), imageName, pathToImage);
+
+ assert pathToImage.toFile().exists() : "Path to SP image does not exist";
+
+ return pathToImage;
+ }
+
+ /**
+ * Path to Dockerfile src/test/docker/{@link #imageName}/Dockerfile.
+ *
+ * @return path to Dockerfile
+ */
+ protected Path pathToDockerfile() {
+
+ final Path pathToDockerfile = pathToImage().resolve("Dockerfile");
+
+ log.debug("{} Path to Dockerfile '{}'", getLogPrefix(), pathToDockerfile);
+
+ assert pathToDockerfile.toFile().exists() : "Path to Dockerfile does not exist";
+
+ return pathToDockerfile;
+ }
+
+ /**
+ * Set up container.
+ *
+ * Copy TLS cert and key into container.
+ *
+ * Copy IdP metadata to container.
+ *
+ * Allow access to IdP on host.
+ *
+ * Set container name and hostname to id.
+ *
+ * Expose ports 80 and 443.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+
+ super.doInitialize();
+
+ if (pathToIdPMetadata == null) {
+ throw new ComponentInitializationException("Path to IdP metadata cannot be null");
+ }
+
+ if (pathToKeyStore == null) {
+ throw new ComponentInitializationException("Path to keystore cannot be null");
+ }
+
+ final String keyStorePassword = System.getenv(BaseTest.KEYSTORE_PASSWORD_ENV_VAR);
+ if (keyStorePassword == null) {
+ throw new ComponentInitializationException("Keystore password environment variable not set");
+ }
+
+ log.debug("{} Initializing", getLogPrefix());
+
+ // Do not delete image on exit
+ final ImageFromDockerfile image = new ImageFromDockerfile(imageName, false).withDockerfile(pathToDockerfile());
+ log.debug("{} Initializing with image '{}'", getLogPrefix(), image);
+ container = new GenericContainer<>(image);
+
+ // Copy TLS certificate and key to container from P12 keystore
+ final Pair<String, String> certAndKey = CertificateHelper.extractCertAndKey(pathToKeyStore, keyStorePassword);
+ container.withCopyToContainer(Transferable.of(certAndKey.getFirst()), "/etc/pki/tls/certs/localhost.crt");
+ container.withCopyToContainer(Transferable.of(certAndKey.getSecond()), "/etc/pki/tls/private/localhost.key");
+
+ // Copy OpenID Connect configuration to container
+ final MountableFile idpMetadata = MountableFile.forHostPath(pathToIdPMetadata);
+ container.withCopyFileToContainer(idpMetadata, "/etc/shibboleth/idp-metadata.xml");
+
+ // Add access to the IdP / OP
+ container.withAccessToHost(true);
+
+ // Add DNS resolution for the IdP / OP
+ container.withExtraHost(idpHost, "host-gateway");
+
+ // Set container name to the RP id
+ container.withCreateContainerCmdModifier(cmd -> cmd.withName(getId()));
+
+ // Set container hostname to the SP host name
+ container.withCreateContainerCmdModifier(cmd -> cmd.withHostName(spHost));
+
+ // Set 'ServerName' environment variable to the RP host name
+ container.withEnv("ServerName", spHost);
+
+ // Expose ports 80 and 443
+ container.addExposedPort(80);
+ container.addExposedPort(443);
+
+ log.debug("{} Initialized", getLogPrefix());
+ }
+
+ /**
+ * Get base URL of the form "https://<id>:<port>".
+ *
+ * For example : "https://sp.tests.shibboleth.net:<port>"
+ *
+ * The host name / FQDN is set via {@link #setSPHost(String)}.
+ *
+ * @return base URL
+ */
+ public String getBaseURL() {
+ return "https://" + spHost + ":" + httpsPort.toString();
+ }
+
+ /**
+ * Set the ID to the FQDN of the SP.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized void setId(String componentId) {
+ super.setId(componentId);
+ }
+
+ /**
+ * Set the hostname or FQDN of the SP.
+ *
+ * @param host
+ * SP host
+ */
+ public void setSPHost(@Nonnull final String host) {
+ Constraint.isNotNull(host, "SP host cannot be null");
+ spHost = host;
+ }
+
+ /**
+ * Set the path to the TLS keystore.
+ *
+ * @param path
+ * path to TLS keystore
+ */
+ public void setKeyStore(@Nonnull final String path) {
+ pathToKeyStore = Paths.get(path);
+ log.debug("{} Path to TLS keystore '{}'", getLogPrefix(), pathToKeyStore);
+ assert pathToKeyStore.toFile().exists() : "Path to TLS keystore " + path + " does not exist";
+ }
+
+ /**
+ * Set the path to the metadata for/about the IdP.
+ *
+ * @param path
+ * path to IdP metadata
+ */
+ public void setIdPMetadata(@Nonnull final Path path) {
+ pathToIdPMetadata = path;
+ log.debug("{} Path to IdP metdata '{}'", getLogPrefix(), pathToIdPMetadata);
+ assert pathToIdPMetadata.toFile().exists() : "Path to IdP metadata " + pathToIdPMetadata + " does not exist";
+ }
+
+ /**
+ * Start container and wait for web server to be available.
+ *
+ * Set {@link #httpPort} and {@link #httpsPort} from {@link GenericContainer#getMappedPort()}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void start() {
+
+ log.info("{} Starting ...", getLogPrefix());
+ container.start();
+ log.debug("{} Started container : '{}'", getLogPrefix(), container.getContainerName());
+
+ httpPort = container.getMappedPort(80);
+ log.debug("{} HTTP port {}", getLogPrefix(), httpPort);
+
+ httpsPort = container.getMappedPort(443);
+ log.debug("{} HTTPS port {}", getLogPrefix(), httpsPort);
+
+ log.debug("{} Waiting for \"/\" to be available ...", getLogPrefix());
+ container.waitingFor(Wait.forHttp("/"));
+ container.waitingFor(Wait.forHttps("/"));
+
+ log.info("{} Started", getLogPrefix());
+ }
+
+ @Override
+ public void stop() {
+ log.debug("{} Stopping ...", getLogPrefix());
+ container.stop();
+ log.info("{} Stopped", getLogPrefix());
+ }
+
+ @Override
+ public boolean isRunning() {
+ boolean isRunning = container.isRunning();
+ log.info("{} Is running '{}'", getLogPrefix(), isRunning);
+ return isRunning;
+ }
+
+ /**
+ * Return a prefix for logging messages for this component.
+ *
+ * @return a string for insertion at the beginning of any log messages
+ */
+ @Nonnull
+ @NotEmpty
+ protected String getLogPrefix() {
+ if (logPrefix == null) {
+ logPrefix = "SP '" + getId() + "' :";
+ }
+ assert logPrefix != null;
+ return logPrefix;
+ }
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list