Last active
May 24, 2023 08:26
-
-
Save theseal/ed1d08a2c2c67dae6fc27675a1e913fa to your computer and use it in GitHub Desktop.
SWAMID Hackaton Shibboleth multifaktorinloggning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SWAMID Hackaton Shibboleth multifaktorinloggning |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<AttributeFilterPolicy id="saml-proxy-pass-through"> | |
<PolicyRequirementRule xsi:type="Issuer" value="https://idp.dev.eduid.se/idp.xml" /> | |
<AttributeRule attributeID="norEduPersonNIN" permitAny="true" /> | |
</AttributeFilterPolicy> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<AttributeDefinition xsi:type="SubjectDerivedAttribute" | |
forCanonicalization="true" | |
principalAttributeName="norEduPersonNIN" | |
id="proxied-nin" | |
/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<MetadataProvider xsi:type="FilesystemMetadataProvider" xmlns="urn:mace:shibboleth:2.0:metadata" | |
id="MyMetadata" | |
metadataFile="%{idp.home}/metadata/eduid-dev.xml" /> | |
<!-- | |
curl 'https://metadata.swamid.se/?rawXML=264&download' > /opt/shibboleth-idp/metadata/eduid-dev.xml | |
--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Properties that control authentication generally and the behavior of | |
# specific methods. | |
# Regular expression matching login flows to enable, e.g. IPAddress|Password | |
idp.authn.flows = MFA | |
# Default settings for most authentication methods. | |
#idp.authn.defaultLifetime = PT1H | |
#idp.authn.defaultTimeout = PT30M | |
#idp.authn.proxyRestrictionsEnforced = true | |
# Whether to populate relying party user interface information for display | |
# during authentication, consent, terms-of-use. | |
#idp.authn.rpui = true | |
# Whether to prioritize "active" results when an SP requests more than | |
# one possible matching login method (V2 behavior was to favor them) | |
#idp.authn.favorSSO = false | |
# Whether to fail requests when a user identity after authentication | |
# doesn't match the identity in a pre-existing session. | |
#idp.authn.identitySwitchIsError = false | |
# If using IdP discovery feature, provides a discovery location to use. | |
#idp.authn.discoveryURL = https://ds.example.org/shibboleth-ds/index.html | |
# Login flow audit logging (defaults false for log compatibility) | |
#idp.authn.audit.enabled = false | |
# Revocation (administrative logout) | |
#idp.authn.revocation = false | |
#idp.authn.revocation.lifetime = %{idp.authn.defaultAuthnLifetime:PT12H} | |
# Name of BiCondition to apply for check | |
#idp.authn.revocation.Condition = shibboleth.RevocationCacheCondition | |
# Set to true to treat lookup failures as being revoked. | |
#idp.authn.revocation.strict = false | |
# Set to true to check for address-based revocation. | |
#idp.authn.revocation.addressBased = false | |
# Default implementation based on a StorageService bean. | |
#idp.authn.revocation.cache = shibboleth.AuthnRevocationCache | |
#idp.authn.revocation.StorageService = shibboleth.StorageService | |
# Properties below override specific method behavior, as an alternative | |
# to defining Spring beans in XML. Refer to the documentation for a complete | |
# list. Many of the properties below are mentioned only because they are | |
# atypical defaults assumed for a given method. | |
# Flow selection among multiple equivalent options can be managed with | |
# the order properties, lower will be tried first. | |
#### Password #### | |
#idp.authn.Password.order = 1000 | |
#idp.authn.Password.passiveAuthenticationSupported = true | |
#idp.authn.Password.forcedAuthenticationSupported = true | |
# Override this and removeAfterValidation to require all validators to succeed | |
#idp.authn.Password.requireAll = false | |
# Override to keep the password around | |
#idp.authn.Password.removeAfterValidation = true | |
# Override to store password in Java Subject | |
#idp.authn.Password.retainAsPrivateCredential = false | |
# Simple username transforms before validation | |
#idp.authn.Password.trim = true | |
#idp.authn.Password.lowercase = false | |
#idp.authn.Password.uppercase = false | |
#idp.authn.Password.matchExpression = | |
# Override default form field names | |
#idp.authn.Password.usernameFieldName = j_username | |
#idp.authn.Password.passwordFieldName = j_password | |
#idp.authn.Password.ssoBypassFieldName = donotcache | |
# Unset if using customized Principals per validator | |
#idp.authn.Password.addDefaultPrincipals = true | |
# The Principal collection below is the typical default if not otherwise noted. | |
#idp.authn.Password.supportedPrincipals = \ | |
# saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport, \ | |
# saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Password, \ | |
# saml1/urn:oasis:names:tc:SAML:1.0:am:password | |
# Validators are controlled in password-authn-config.xml | |
#### Password Backends #### | |
# See ldap.properties for LDAP authn properties | |
# Kerberos settings | |
#idp.authn.Krb5.refreshConfig = false | |
#idp.authn.Krb5.preserveTicket = false | |
# Set next two for KDC verification | |
#idp.authn.Krb5.servicePrincipal = | |
#idp.authn.Krb5.keytab = | |
# JAAS settings | |
#idp.authn.JAAS.loginConfigNames = ShibUserPassAuth | |
#idp.authn.JAAS.loginConfig = %{idp.home}/conf/authn/jaas.config | |
#### External #### | |
#idp.authn.External.order = 1000 | |
#idp.authn.External.nonBrowserSupported = false | |
#idp.authn.External.matchExpression = | |
# Unset if you plan to return full Java Subject from external source | |
#idp.authn.External.addDefaultPrincipals = true | |
# Servlet context-relative path to wherever your implementation lives | |
idp.authn.External.externalAuthnPath = contextRelative:external.jsp | |
#### RemoteUser #### | |
#idp.authn.RemoteUser.order = 1000 | |
#idp.authn.RemoteUser.nonBrowserSupported = false | |
#idp.authn.RemoteUser.matchExpression = | |
# Unset in most cases only if using the authnMethodHeader or | |
# subjectAttribute settings | |
#idp.authn.RemoteUser.addDefaultPrincipals = true | |
# Most other settings need to be supplied via web.xml to the servlet | |
#### RemoteUserInternal #### | |
#idp.authn.RemoteUserInternal.order = 1000 | |
#idp.authn.RemoteUserInternal.nonBrowserSupported = true | |
# Unset in most cases only if using the authnMethodHeader feature | |
#idp.authn.RemoteUserInternal.addDefaultPrincipals = true | |
#idp.authn.RemoteUserInternal.checkRemoteUser = true | |
# Comma-delimited lists of attributes or headers to pull from | |
#idp.authn.RemoteUserInternal.checkAttributes = | |
#idp.authn.RemoteUserInternal.checkHeaders = | |
# Simple transforms to apply | |
#idp.authn.RemoteUserInternal.trim = true | |
#idp.authn.RemoteUserInternal.lowercase = false | |
#idp.authn.RemoteUserInternal.uppercase = false | |
#idp.authn.RemoteUserInternal.matchExpression = | |
#idp.authn.RemoteUserInternal.allowedUsernames = | |
#idp.authn.RemoteUserInternal.deniedUsernames = | |
#### SPNEGO #### | |
#idp.authn.SPNEGO.order = 1000 | |
#idp.authn.SPNEGO.nonBrowserSupported = false | |
#idp.authn.SPNEGO.enforceRun = false | |
#idp.authn.SPNEGO.refreshKrbConfig = false | |
#idp.authn.SPNEGO.matchExpression = | |
idp.authn.SPNEGO.supportedPrincipals = \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Kerberos, \ | |
saml1/urn:ietf:rfc:1510 | |
#### X509 #### | |
#idp.authn.X509.order = 1000 | |
#idp.authn.X509.nonBrowserSupported = false | |
# Servlet context-relative path to wherever your implementation lives | |
#idp.authn.X509.externalAuthnPath = contextRelative:x509-prompt.jsp | |
idp.authn.X509.supportedPrincipals = \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:X509, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient, \ | |
saml1/urn:ietf:rfc:2246 | |
#### X509Internal #### | |
#idp.authn.X509Internal.order = 1000 | |
#idp.authn.X509Internal.nonBrowserSupported = false | |
#idp.authn.X509Internal.saveCertificateToCredentialSet = true | |
idp.authn.X509Internal.supportedPrincipals = \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:X509, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient, \ | |
saml1/urn:ietf:rfc:2246 | |
#### IPAddress #### | |
#idp.authn.IPAddress.order = 1000 | |
#idp.authn.IPAddress.passiveAuthenticationSupported = true | |
#idp.authn.IPAddress.lifetime = PT60S | |
#idp.authn.IPAddress.inactivityTimeout = PT60S | |
idp.authn.IPAddress.supportedPrincipals = \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol | |
#### Function #### | |
#idp.authn.Function.order = 1000 | |
#idp.authn.Function.passiveAuthenticationSupported = true | |
# Unset if you plan to return full Java Subject from function | |
#idp.authn.Function.addDefaultPrincipals = true | |
#### Duo #### | |
#idp.authn.Duo.order = 1000 | |
#idp.authn.Duo.nonBrowserSupported = false | |
#idp.authn.Duo.forcedAuthenticationSupported = true | |
# Unset if you have advanced Duo integrations with individualized Principals | |
#idp.authn.Duo.addDefaultPrincipals = true | |
# The list below should be changed to reflect whatever locally- or | |
# community-defined values are appropriate to represent Duo. It is | |
# strongly advised that the value not be specific to Duo or any | |
# particular technology to avoid lock-in. | |
idp.authn.Duo.supportedPrincipals = \ | |
saml2/http://example.org/ac/classes/mfa, \ | |
saml1/http://example.org/ac/classes/mfa | |
# Default Duo integration settings are defined separately | |
# in duo.properties due to the sensitivity of the secret key. | |
#### SAML #### | |
#idp.authn.SAML.order = 1000 | |
#idp.authn.SAML.nonBrowserSupported = false | |
#idp.authn.SAML.passiveAuthenticationSupported = true | |
#idp.authn.SAML.forcedAuthenticationSupported = true | |
#idp.authn.SAML.proxyScopingEnforced = true | |
# Discovery options: | |
# Define shibboleth.authn.SAML.discoveryFunction bean | |
# Set proxyEntityID property | |
# Fall through to discovery via discoveryRequired property | |
#idp.authn.SAML.proxyEntityID = https://idp.dev.eduid.se/idp.xml | |
idp.authn.SAML.proxyEntityID = https://idp-sweden-connect-valfr-2017-sandbox.test.frejaeid.com | |
#idp.authn.SAML.discoveryRequired = true | |
# Generally left false with bidirectional mappings in | |
# conf/authn/authn-comparison.xml across the proxy boundary. | |
# Adjust as needed to reflect IdP's capabilities/support. | |
#idp.authn.SAML.addDefaultPrincipals = false | |
idp.authn.SAML.supportedPrincipals = \ | |
saml2/http://id.elegnamnden.se/loa/1.0/loa3, \ | |
saml2/https://refeds.org/profile/mfa, \ | |
saml1/https://refeds.org/profile/mfa | |
#### MFA #### | |
#idp.authn.MFA.order = 1000 | |
#idp.authn.MFA.passiveAuthenticationSupported = true | |
#idp.authn.MFA.forcedAuthenticationSupported = true | |
#idp.authn.MFA.validateLoginTransitions = true | |
# The list below almost certainly requires changes, and should generally be the | |
# union of any of the separate factors you combine in your particular MFA flow | |
# rules. The example corresponds to the example in mfa-authn-config.xml that | |
# combines IPAddress with Password. | |
idp.authn.MFA.supportedPrincipals = \ | |
saml2/http://id.elegnamnden.se/loa/1.0/loa3, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Password, \ | |
saml1/urn:oasis:names:tc:SAML:1.0:am:password, \ | |
saml2/https://refeds.org/profile/mfa, \ | |
saml1/https://refeds.org/profile/mfa | |
# Most actual setup via mfa-authn-config.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- conf/authn/authn.properties 2023-05-17 11:37:54.319811928 +0000 | |
+++ dist/conf/authn/authn.properties 2023-03-30 13:29:46.000000000 +0000 | |
@@ -2,7 +2,7 @@ | |
# specific methods. | |
# Regular expression matching login flows to enable, e.g. IPAddress|Password | |
-idp.authn.flows = MFA | |
+#idp.authn.flows = Password | |
# Default settings for most authentication methods. | |
#idp.authn.defaultLifetime = PT1H | |
@@ -206,17 +206,16 @@ | |
# Define shibboleth.authn.SAML.discoveryFunction bean | |
# Set proxyEntityID property | |
# Fall through to discovery via discoveryRequired property | |
-#idp.authn.SAML.proxyEntityID = https://idp.dev.eduid.se/idp.xml | |
-idp.authn.SAML.proxyEntityID = https://idp-sweden-connect-valfr-2017-sandbox.test.frejaeid.com | |
+#idp.authn.SAML.proxyEntityID = https://idp.example.org/idp/shibboleth | |
#idp.authn.SAML.discoveryRequired = true | |
# Generally left false with bidirectional mappings in | |
# conf/authn/authn-comparison.xml across the proxy boundary. | |
# Adjust as needed to reflect IdP's capabilities/support. | |
#idp.authn.SAML.addDefaultPrincipals = false | |
+idp.authn.SAML.supportedPrincipals = \ | |
+ saml2/https://refeds.org/profile/mfa, \ | |
+ saml1/https://refeds.org/profile/mfa | |
-#idp.authn.SAML.supportedPrincipals = \ | |
-# saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport, \ | |
-# saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Password, \ | |
-# saml1/urn:oasis:names:tc:SAML:1.0:am:password | |
#### MFA #### | |
@@ -229,11 +228,8 @@ | |
# rules. The example corresponds to the example in mfa-authn-config.xml that | |
# combines IPAddress with Password. | |
idp.authn.MFA.supportedPrincipals = \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport, \ | |
saml2/urn:oasis:names:tc:SAML:2.0:ac:classes:Password, \ | |
+ saml1/urn:oasis:names:tc:SAML:1.0:am:password, \ | |
+ saml2/https://refeds.org/profile/mfa, \ | |
+ saml1/https://refeds.org/profile/mfa | |
- saml1/urn:oasis:names:tc:SAML:1.0:am:password | |
# Most actual setup via mfa-authn-config.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# LDAP authentication (and possibly attribute resolver) configuration | |
# Note, this doesn't apply to the use of JAAS authentication via LDAP | |
## Authenticator strategy, either anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, adAuthenticator | |
#idp.authn.LDAP.authenticator = anonSearchAuthenticator | |
## Connection properties ## | |
idp.authn.LDAP.ldapURL = ldap://172.16.0.2:389 | |
idp.authn.LDAP.useStartTLS = false | |
# Time in milliseconds that connects will block | |
#idp.authn.LDAP.connectTimeout = PT3S | |
# Time in milliseconds to wait for responses | |
#idp.authn.LDAP.responseTimeout = PT3S | |
# Connection strategy to use when multiple URLs are supplied, either ACTIVE_PASSIVE, ROUND_ROBIN, RANDOM | |
#idp.authn.LDAP.connectionStrategy = ACTIVE_PASSIVE | |
## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust | |
#idp.authn.LDAP.sslConfig = certificateTrust | |
## If using certificateTrust above, set to the trusted certificate's path | |
idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt | |
## If using keyStoreTrust above, set to the truststore path | |
idp.authn.LDAP.trustStore = %{idp.home}/credentials/ldap-server.truststore | |
## Return attributes during authentication | |
idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining | |
## DN resolution properties ## | |
# Search DN resolution, used by anonSearchAuthenticator, bindSearchAuthenticator | |
# for AD: CN=Users,DC=example,DC=org | |
idp.authn.LDAP.baseDN = ou=people,dc=qa,dc=swamid,dc=se | |
#idp.authn.LDAP.subtreeSearch = false | |
idp.authn.LDAP.userFilter = (uid={user}) | |
# bind search configuration | |
# for AD: idp.authn.LDAP.bindDN=adminuser@domain.com | |
idp.authn.LDAP.bindDN = cn=professor1,ou=People,dc=qa,dc=swamid,dc=se | |
# Format DN resolution, used by directAuthenticator, adAuthenticator | |
# for AD use idp.authn.LDAP.dnFormat=%s@domain.com | |
idp.authn.LDAP.dnFormat = uid=%s,ou=people,dc=qa,dc=swamid,dc=se | |
# pool passivator, either none, bind or anonymousBind | |
#idp.authn.LDAP.bindPoolPassivator = none | |
# LDAP attribute configuration, see attribute-resolver.xml | |
# Note, this likely won't apply to the use of legacy V2 resolver configurations | |
idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} | |
idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} | |
idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} | |
idp.attribute.resolver.LDAP.connectionStrategy = %{idp.authn.LDAP.connectionStrategy:ACTIVE_PASSIVE} | |
idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} | |
idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} | |
idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} | |
idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} | |
idp.attribute.resolver.LDAP.searchFilter = (|(uid=$resolutionContext.principal)(norEduPersonNIN=$resolutionContext.principal)) | |
# LDAP pool configuration, used for both authn and DN resolution | |
#idp.pool.LDAP.minSize = 3 | |
#idp.pool.LDAP.maxSize = 10 | |
#idp.pool.LDAP.validateOnCheckout = false | |
#idp.pool.LDAP.validatePeriodically = true | |
#idp.pool.LDAP.validatePeriod = PT5M | |
#idp.pool.LDAP.validateDN = | |
#idp.pool.LDAP.validateFilter = (objectClass=*) | |
#idp.pool.LDAP.prunePeriod = PT5M | |
#idp.pool.LDAP.idleTime = PT10M | |
#idp.pool.LDAP.blockWaitTime = PT3S |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- conf/ldap.properties 2023-05-11 12:09:52.116733811 +0000 | |
+++ dist/conf/ldap.properties 2023-05-11 06:38:12.085000000 +0000 | |
@@ -52,7 +52,7 @@ | |
idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} | |
idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} | |
idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} | |
+idp.attribute.resolver.LDAP.searchFilter = (|(uid=$resolutionContext.principal)(norEduPersonNIN=$resolutionContext.principal)) | |
-idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal) | |
# LDAP pool configuration, used for both authn and DN resolution | |
#idp.pool.LDAP.minSize = 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# https://shibboleth.atlassian.net/wiki/spaces/KB/pages/1459979597/Using+SAML+Proxying+to+another+IdP#UsingSAMLProxyingtoanotherIdP-UpdateyourIdP'smetadata | |
# | |
--- idp-metadata.xml 2023-05-17 13:16:45 | |
+++ idp-metadata-with-sp.xml 2023-05-17 13:27:17 | |
@@ -12,6 +12,91 @@ | |
<mdrpi:RegistrationPolicy xml:lang="en">http://swamid.se/policy/mdrps</mdrpi:RegistrationPolicy> | |
</mdrpi:RegistrationInfo> | |
</md:Extensions> | |
+ <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> | |
+ <md:Extensions> | |
+ <mdui:UIInfo> | |
[..] | |
+ </mdui:UIInfo> | |
+ </md:Extensions> | |
+ <md:KeyDescriptor use="signing"> | |
[...] | |
+ </md:KeyDescriptor> | |
+ <md:KeyDescriptor use="encryption"> | |
[...] | |
+ </md:KeyDescriptor> | |
+ <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://shibmfa.test.swamid.se/idp/profile/Authn/SAML2/POST/SSO" index="0"/> | |
+ </md:SPSSODescriptor> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /tmp/mfa-authn-config.xml.idpnew 2023-05-17 11:50:11.406497913 +0000 | |
+++ /tmp/mfa-authn-config.xml 2023-05-17 11:51:26.749225639 +0000 | |
@@ -60,7 +60,7 @@ | |
<constructor-arg> | |
<value> | |
<![CDATA[ | |
- nextFlow = "authn/Password"; | |
+ nextFlow = "authn/SAML"; | |
// Check if second factor is necessary for request to be satisfied. | |
authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
Activate MFA: | |
/opt/shibboleth-idp/bin/module.sh -e idp.authn.MFA | |
--> | |
<?xml version="1.0" encoding="UTF-8"?> | |
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:context="http://www.springframework.org/schema/context" | |
xmlns:util="http://www.springframework.org/schema/util" | |
xmlns:p="http://www.springframework.org/schema/p" | |
xmlns:c="http://www.springframework.org/schema/c" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd | |
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" | |
default-init-method="initialize" | |
default-destroy-method="destroy"> | |
<!-- | |
This is a map of transition rules that guide the behavior of the MFA flow | |
and controls how factors are sequenced, skipped, etc. The key of each entry | |
is the name of the step/flow out of which control is passing. The starting | |
rule has an empty key. | |
Each entry is a bean inherited from "shibboleth.authn.MFA.Transition". Per | |
the Javadoc for net.shibboleth.idp.authn.MultiFactorAuthenticationTransition: | |
p:nextFlow (String) | |
- A flow to run if the previous step signaled a "proceed" event, for simple | |
transitions. | |
p:nextFlowStrategy (Function<ProfileRequestContext,String>) | |
- A function to run if the previous step signaled a "proceed" event, for dynamic | |
transitions. Returning null ends the MFA process. | |
p:nextFlowStrategyMap (Map<String,Object> where Object is String or Function<ProfileRequestContext,String>) | |
- Fully dynamic way of expressing control paths. Map is keyed by a previously | |
signaled event and the value is a flow to run or a function to | |
return the flow to run. Returning null ends the MFA process. | |
When no rule is provided, there's an implicit "null" that ends the MFA flow | |
with whatever event was last signaled. If the "proceed" event from a step is | |
the final event, then the MFA process attempts to complete itself successfully. | |
--> | |
<util:map id="shibboleth.authn.MFA.TransitionMap"> | |
<!-- First rule runs the IPAddress login flow. --> | |
<entry key=""> | |
<bean parent="shibboleth.authn.MFA.Transition" p:nextFlow="authn/Password" /> | |
</entry> | |
<!-- | |
Second rule runs a function if IPAddress succeeds, to determine whether an additional | |
factor is required. | |
--> | |
<entry key="authn/Password"> | |
<bean parent="shibboleth.authn.MFA.Transition" p:nextFlowStrategy-ref="checkSecondFactor" /> | |
</entry> | |
<!-- An implicit final rule will return whatever the final flow returns. --> | |
</util:map> | |
<!-- Example script to see if second factor is required. --> | |
<bean id="checkSecondFactor" parent="shibboleth.ContextFunctions.Scripted" factory-method="inlineScript"> | |
<constructor-arg> | |
<value> | |
<![CDATA[ | |
nextFlow = "authn/SAML"; | |
// Check if second factor is necessary for request to be satisfied. | |
authCtx = input.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); | |
mfaCtx = authCtx.getSubcontext("net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext"); | |
if (mfaCtx.isAcceptable()) { | |
nextFlow = null; | |
} | |
nextFlow; // pass control to second factor or end with the first | |
]]> | |
</value> | |
</constructor-arg> | |
</bean> | |
</beans> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Properties that control the behavior of post-login subject c14n flows. | |
# A few more advanced settings require XML configuration, see flow-specific docs. | |
# Simple username -> principal name c14n | |
#idp.c14n.simple.lowercase = false | |
#idp.c14n.simple.uppercase = false | |
#idp.c14n.simple.trim = true | |
# Attribute resolution -> principal name c14n | |
#idp.c14n.attribute.lowercase = false | |
#idp.c14n.attribute.uppercase = false | |
#idp.c14n.attribute.trim = true | |
# Lists of attributes to resolve... | |
idp.c14n.attribute.attributesToResolve = proxied-nin | |
# and then select a principal name from | |
idp.c14n.attribute.attributeSourceIds = proxied-nin | |
# Allows direct use of attributes via SAML proxy authn, bypasses resolver | |
#idp.c14n.attribute.resolveFromSubject = false | |
#idp.c14n.attribute.resolutionCondition = shibboleth.Conditions.TRUE | |
# X.509 certificate -> principal name c14n | |
#idp.c14n.x500.lowercase = false | |
#idp.c14n.x500.uppercase = false | |
#idp.c14n.x500.trim = true | |
# Precedence is to check for a subjectAltName and then an OID RDN | |
# Comma-delimited list of subjectAltName type numbers | |
# (See https://tools.ietf.org/html/rfc5280#section-4.2.1.6) | |
#idp.c14n.x500.subjectAltNameTypes = | |
# Comma-delimited list of OIDS | |
#idp.c14n.x500.objectIDs = | |
# Proxied SAML NameID -> principal name c14n | |
#idp.c14n.saml.proxy.lowercase = false | |
#idp.c14n.saml.proxy.uppercase = false | |
# NameID consumption from SAML requests | |
#idp.c14n.saml.lowercase = false | |
#idp.c14n.saml.uppercase = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- conf/c14n/subject-c14n.properties 2023-05-11 10:42:55.824627047 +0000 | |
+++ dist/conf/c14n/subject-c14n.properties 2023-03-30 13:29:46.000000000 +0000 | |
@@ -13,9 +13,9 @@ | |
#idp.c14n.attribute.uppercase = false | |
#idp.c14n.attribute.trim = true | |
# Lists of attributes to resolve... | |
+idp.c14n.attribute.attributesToResolve = proxied-nin | |
-#idp.c14n.attribute.attributesToResolve = | |
# and then select a principal name from | |
+idp.c14n.attribute.attributeSourceIds = proxied-nin | |
-#idp.c14n.attribute.attributeSourceIds = | |
# Allows direct use of attributes via SAML proxy authn, bypasses resolver | |
#idp.c14n.attribute.resolveFromSubject = false | |
#idp.c14n.attribute.resolutionCondition = shibboleth.Conditions.TRUE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<beans xmlns="http://www.springframework.org/schema/beans" | |
xmlns:context="http://www.springframework.org/schema/context" | |
xmlns:util="http://www.springframework.org/schema/util" | |
xmlns:p="http://www.springframework.org/schema/p" | |
xmlns:c="http://www.springframework.org/schema/c" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | |
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd | |
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" | |
default-init-method="initialize" | |
default-destroy-method="destroy"> | |
<!-- ========================= Java Subject -> Principal Mapping ========================= --> | |
<!-- | |
These are lists of Subject Canonicalization flows that turn complex Subject data into a string-based | |
principal name that the rest of the IdP can operate on. They're used primarily after authentication | |
and also during less common operations like SAML attribute queries, to map the SAML Subject into a | |
principal name. | |
Flows are identified with an ID that corresponds to a Spring Web Flow subflow name. | |
Most of the simple settings that configure these flows are in subject-c14n.properties. | |
--> | |
<!-- | |
==================================================================== | |
Flows used after authentication to produce canonical principal name. | |
==================================================================== | |
--> | |
<util:list id="shibboleth.PostLoginSubjectCanonicalizationFlows"> | |
<!-- | |
This is an advanced post-login step that performs attribute resolution and then produces a username | |
from an attribute value. To enable universally, just uncomment, but if you want it to run under more | |
specific conditions, set an activationCondition property to a condition to apply. | |
--> | |
<bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" /> | |
<!-- | |
This is an advanced option for use with SAML 2 proxy authentication to a second IdP that | |
derives the principal name semi-directly from the incoming NameID value. It is functionally | |
akin to the c14n/SAML2Transform flow for SAML Request scenarios, but separately defined so | |
a suitably restrictive format list and/or condition can be applied to it. | |
--> | |
<!-- <ref bean="c14n/SAML2ProxyTransform" /> --> | |
<!-- | |
This is an alternative that handles Subjects containing an X500Principal object and | |
allows extraction from the DN. | |
--> | |
<ref bean="c14n/x500" /> | |
<!-- | |
This is the standard post-login step that returns a username derived from the login process. If you | |
have more complex needs such as mapping a certificate DN into a principal name, an alternative may | |
be required such as that above, but you can use this for simple transforms. | |
--> | |
<ref bean="c14n/simple" /> | |
</util:list> | |
<!-- What SAML NameID formats do you want to support direct transformations for while proxying? --> | |
<util:list id="shibboleth.ProxyNameTransformFormats"> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</value> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</value> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</value> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</value> | |
<value>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</value> | |
</util:list> | |
<!-- | |
Under what conditions should direct NameID mapping during proxying be allowed? By default, never. | |
Any condition can be used here; the example is suitable for enumerating a number of IdPs to allow. | |
--> | |
<bean id="shibboleth.ProxyNameTransformPredicate" parent="shibboleth.Conditions.ProxyAuthentication"> | |
<constructor-arg name="collection"> | |
<list> | |
<!-- <value>https://idp-proxy.example.org</value> --> | |
</list> | |
</constructor-arg> | |
</bean> | |
<!-- | |
Regular expression transforms to apply to incoming proxied subject names. The default empty list just | |
echoes the name through unmodified. | |
--> | |
<util:list id="shibboleth.ProxyNameTransforms"> | |
<!-- | |
<bean parent="shibboleth.Pair" p:first="^(.+)@example\.org$" p:second="$1" /> | |
--> | |
</util:list> | |
<!-- | |
======================================================================= | |
Flows used during SAML requests to reverse-map NameIdentifiers/NameIDs. | |
Below the list are some settings that might be useful to adjust. | |
======================================================================= | |
--> | |
<util:list id="shibboleth.SAMLSubjectCanonicalizationFlows"> | |
<!-- The next four are for handling transient IDs (in-storage and stateless variants). --> | |
<ref bean="c14n/SAML2Transient" /> | |
<ref bean="c14n/SAML2CryptoTransient" /> | |
<ref bean="c14n/SAML1Transient" /> | |
<ref bean="c14n/SAML1CryptoTransient" /> | |
<!-- Handle a SAML 2 persistent ID, provided a stored strategy is in use. --> | |
<!-- <ref bean="c14n/SAML2Persistent" /> --> | |
<!-- | |
Finally we have beans for decoding arbitrary SAML formats directly. By default, these are turned off, | |
having *no* circumstances for which they apply (see shibboleth.TransformNamePredicate below). | |
--> | |
<ref bean="c14n/SAML2Transform" /> | |
<ref bean="c14n/SAML1Transform" /> | |
</util:list> | |
<!-- What SAML NameID formats do you want to support direct transformations for? --> | |
<util:list id="shibboleth.NameTransformFormats"> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</value> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</value> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</value> | |
<value>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</value> | |
<value>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</value> | |
</util:list> | |
<!-- | |
Under what conditions should direct NameID mapping be allowed? By default, never. | |
Any condition can be used here; the example is suitable for enumerating a number of SPs to allow. | |
--> | |
<bean id="shibboleth.NameTransformPredicate" parent="shibboleth.Conditions.RelyingPartyId"> | |
<constructor-arg name="candidates"> | |
<list> | |
<!-- <value>https://sp.example.org</value> --> | |
</list> | |
</constructor-arg> | |
</bean> | |
<!-- | |
Regular expression transforms to apply to incoming subject names. The default empty list just | |
echoes the name through unmodified. | |
--> | |
<util:list id="shibboleth.NameTransforms"> | |
<!-- | |
<bean parent="shibboleth.Pair" p:first="^(.+)@example\.org$" p:second="$1" /> | |
--> | |
</util:list> | |
<util:map id="umich.shibboleth.authn.MFA.customMap"> | |
<entry key="AttributeResolver" value-ref="shibboleth.AttributeResolverService" /> | |
<entry key="request" value-ref="shibboleth.HttpServletRequest" /> | |
</util:map> | |
<bean id="shibboleth.c14n.attribute.PrincipalNameLookupStrategy" | |
parent="shibboleth.ContextFunctions.Scripted" | |
factory-method="inlineScript" p:customObject-ref="umich.shibboleth.authn.MFA.customMap"> | |
<constructor-arg> | |
<value> | |
<![CDATA[ | |
logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute.resolver.eppnbuilder"); | |
var principalName = null; | |
var subject = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getSubject(); | |
var princs = subject.getPrincipals(Java.type("net.shibboleth.idp.authn.principal.UsernamePrincipal").class); | |
var princs2 = subject.getPrincipals(Java.type("net.shibboleth.idp.authn.principal.IdPAttributePrincipal").class); | |
if (princs.size() == 1) { | |
principalName = princs.iterator().next().getName(); | |
if (princs2.size() == 1) { | |
resCtx = input.getSubcontext("net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true); | |
resCtx.setPrincipal(principalName); | |
resCtx.getRequestedIdPAttributeNames().add("norEduPersonNIN"); | |
resCtx.resolveAttributes(custom["AttributeResolver"]); | |
orig_nin = resCtx.getResolvedIdPAttributes().get("norEduPersonNIN").getValues().get(0).getValue(); | |
eduid_nin = resCtx.getResolvedIdPAttributes().get("proxied-nin").getValues().get(0).getValue(); | |
logger.info("SWAMID-origin-nin: " + orig_nin); | |
logger.info("SWAMID-eduid-nin: " + eduid_nin); | |
if (orig_nin != eduid_nin) { | |
throw new Error("'Identification attribute recived from eduID didn't match the local catalog'"); | |
} | |
} | |
} | |
principalName; | |
]]> | |
</value> | |
</constructor-arg> | |
</bean> | |
</beans> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- dist/conf/c14n/subject-c14n.xml 2023-03-30 13:29:46.000000000 +0000 | |
+++ conf/c14n/subject-c14n.xml 2023-05-16 11:53:04.522101535 +0000 | |
@@ -36,7 +36,7 @@ | |
from an attribute value. To enable universally, just uncomment, but if you want it to run under more | |
specific conditions, set an activationCondition property to a condition to apply. | |
--> | |
- <!-- <bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" /> --> | |
+ <bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" /> | |
<!-- | |
This is an advanced option for use with SAML 2 proxy authentication to a second IdP that | |
@@ -147,5 +147,48 @@ | |
<bean parent="shibboleth.Pair" p:first="^(.+)@example\.org$" p:second="$1" /> | |
--> | |
</util:list> | |
- | |
+ | |
+ <util:map id="umich.shibboleth.authn.MFA.customMap"> | |
+ <entry key="AttributeResolver" value-ref="shibboleth.AttributeResolverService" /> | |
+ <entry key="request" value-ref="shibboleth.HttpServletRequest" /> | |
+ </util:map> | |
+ | |
+ <bean id="shibboleth.c14n.attribute.PrincipalNameLookupStrategy" | |
+ parent="shibboleth.ContextFunctions.Scripted" | |
+ factory-method="inlineScript" p:customObject-ref="umich.shibboleth.authn.MFA.customMap"> | |
+ <constructor-arg> | |
+ <value> | |
+ <![CDATA[ | |
+ logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.attribute.resolver.eppnbuilder"); | |
+ | |
+ var principalName = null; | |
+ var subject = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectCanonicalizationContext").getSubject(); | |
+ var princs = subject.getPrincipals(Java.type("net.shibboleth.idp.authn.principal.UsernamePrincipal").class); | |
+ var princs2 = subject.getPrincipals(Java.type("net.shibboleth.idp.authn.principal.IdPAttributePrincipal").class); | |
+ | |
+ | |
+ if (princs.size() == 1) { | |
+ principalName = princs.iterator().next().getName(); | |
+ | |
+ if (princs2.size() == 1) { | |
+ resCtx = input.getSubcontext("net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext", true); | |
+ | |
+ resCtx.setPrincipal(principalName); | |
+ resCtx.getRequestedIdPAttributeNames().add("norEduPersonNIN"); | |
+ resCtx.resolveAttributes(custom["AttributeResolver"]); | |
+ | |
+ orig_nin = resCtx.getResolvedIdPAttributes().get("norEduPersonNIN").getValues().get(0).getValue(); | |
+ eduid_nin = resCtx.getResolvedIdPAttributes().get("proxied-nin").getValues().get(0).getValue(); | |
+ logger.info("SWAMID-origin-nin: " + orig_nin); | |
+ logger.info("SWAMID-eduid-nin: " + eduid_nin); | |
+ if (orig_nin != eduid_nin) { | |
+ throw new Error("'Identification attribute recived from eduID didn't match the local catalog'"); | |
+ } | |
+ } | |
+ } | |
+ principalName; | |
+ ]]> | |
+ </value> | |
+ </constructor-arg> | |
+ </bean> | |
</beans> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment