Atlassian uses cookies to improve your browsing experience, perform analytics and research, and conduct advertising. Accept all cookies to indicate that you agree to our use of cookies on your device.
Atlassian uses cookies to improve your browsing experience, perform analytics and research, and conduct advertising. Accept all cookies to indicate that you agree to our use of cookies on your device. Atlassian cookies and tracking notice, (opens new window)
The "authn/X509Internal" login flow leverages any surrounding mechanism you have available for TLS client certificate authentication, provided the standard servlet request attribute (now "jakarta.servlet.request.X509Certificate") is populated. By default, this flow is configured without support for advanced authentication controls like passive or forced authentication since this is not generally possible with client certificate authentication.
Please re-read that paragraph; the IdP does not do X.509 authentication for you, and it can’t. Only a web server can negotiate mutual TLS with an HTTP client, and the IdP is not a web server. Java containers, while they make decent web servers in some cases, are terrible at this. They can do it, to a point, but they’re very hard to configure and they tend to be very opinionated about certificates they can accept without custom work. Generally using more standard software such as Apache tends to work better for this use case.
The difference between this flow and the X509 flow is that this flow doesn't redirect to a protected path; rather, the path of the requested profile flow has to be protected, which typically will trigger as soon as the client makes its first request. This is primarily suited to non-browser clients or other scenarios in which authentication is uniformly certificate-based.
The main disadvantage of using this flow for browser use cases is that it will perform the request for authentication without having a chance to determine if the request will succeed, which may be undesirable from a usability perspective.
The result of this flow is a Java Subject containing an X500Principal derived from the subject of the certificate, and the certificate is added as a public credential of the Subject. Note that no actual "username" is produced; rather, a suitable post-login Subject Canonicalization flow must be enabled/configured to pull a suitable principal name out of the Subject.
Note that if you have a web server that is configured to perform the certificate evaluation for you and populate a header or variable with the "username" to use based on the certificate, you almost certainly will want to use the RemoteUser or RemoteUserInternal flow. This flow pulls in the certificate as the primary result of the authentication and relies on downstream logic (often the x500 subject canonicalization flow) to get a username out of it.
General Configuration
There is no configuration required, but you may use conf/global.xml to define a Spring bean named shibboleth.authn.X509Internal.TrustEngine as an OpenSAML TrustEngine that should be used to validate the client certificate chain. Of course, it's often simpler and more common to do this validation at the web server itself, although that's less flexible.
An example of a PKIX-based TrustEngine declaration follows. The bean ID is defined to allow the built-in flow to locate it.
The beans supported by this flow follow: Bean ID Type Description shibboleth.authn.X509Internal.TrustEngine TrustEngine<X509Credential> An optional bean for validating the client certificate shibboleth.authn.X509Internal.resultCachingPredicate Predicate<ProfileRequestContext> An optional bean that can be defined to control whether to preserve the authentication result in an IdP session shibboleth.authn.X509Internal.ClassifiedMessageMap Map<String,Collection<String>> Optional remapping of exception messages or events into specific Spring Web Flow events.
The properties specific to this flow defined in authn/authn.properties are: Name Default Description idp.authn.X509Internal.saveCertificateToCredentialSet true Whether to save the certificate into the Subject's public credential set. Disable to reduce the size if not relying on the certificate for subject c14n. The general properties configuring this flow via authn/authn.properties are: Name Default Description idp.authn.X509Internal.order 1000 Flow priority relative to other enabled login flows (lower is "higher" in priority) idp.authn.X509Internal.nonBrowserSupported true Whether the flow should handle non-browser request profiles (e.g., ECP) idp.authn.X509Internal.passiveAuthenticationSupported false Whether the flow allows for passive authentication idp.authn.X509Internal.forcedAuthenticationSupported false Whether the flow supports forced authentication idp.authn.X509Internal.proxyRestrictionsEnforced %{idp.authn.enforceProxyRestrictions:true} Whether the flow enforces upstream IdP-imposed restrictions on proxying idp.authn.X509Internal.proxyScopingEnforced false Whether the flow considers itself to be proxying, and therefore enforces SP-signaled restrictions on proxying idp.authn.X509Internal.discoveryRequired false Whether to invoke IdP-discovery prior to running flow idp.authn.X509Internal.lifetime %{idp.authn.defaultLifetime:PT1H} Lifetime of results produced by this flow idp.authn.X509Internal.inactivityTimeout %{idp.authn.defaultTimeout:PT30M} Inactivity timeout of results produced by this flow idp.authn.X509Internal.lifetimeStrategy 5.2 Function returning null Bean ID of Function<ProfileRequestContext,Duration> overriding a specific result’s lifetime idp.authn.X509Internal.inactivityTimeoutStrategy 5.2 Function returning null Bean ID of Function<ProfileRequestContext,Duration> overriding a specific result’s inactivity timeout idp.authn.X509Internal.reuseCondition shibboleth.Conditions.TRUE Bean ID of Predicate<ProfileRequestContext> controlling result reuse for SSO idp.authn.X509Internal.activationCondition shibboleth.Conditions.TRUE Bean ID of Predicate<ProfileRequestContext> determining whether flow is usable for request idp.authn.X509Internal.subjectDecorator Bean ID of BiConsumer<ProfileRequestContext,Subject> for subject customization idp.authn.X509Internal.supportedPrincipals (see below) Comma-delimited list of protocol-specific Principal strings associated with flow idp.authn.X509Internal.addDefaultPrincipals true Whether to auto-attach the preceding set of Principal objects to each Subject produced by this flow idp.authn.X509Internal.c14n.flows 5.2 Comma-delimited list of c14n methods (beans) to run after use of this login flow As a non-password based flow, the supportedPrincipals property defaults to the following XML: <list>
<bean parent="shibboleth.SAML2AuthnContextClassRef"
c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:X509" />
<bean parent="shibboleth.SAML2AuthnContextClassRef"
c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient" />
<bean parent="shibboleth.SAML1AuthenticationMethod"
c:method="urn:ietf:rfc:2246" />
</list> In property form, this is expressed as (note the trailing commas): 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
To replace the internally defined flow descriptor bean, the following XML is required: <util:list id="shibboleth.AvailableAuthenticationFlows">
<bean p:id="authn/X509Internal" parent="shibboleth.AuthenticationFlow"
p:order="%{idp.authn.X509Internal.order:1000}"
p:nonBrowserSupported="%{idp.authn.X509Internal.nonBrowserSupported:false}"
p:passiveAuthenticationSupported="%{idp.authn.X509Internal.passiveAuthenticationSupported:false}"
p:forcedAuthenticationSupported="%{idp.authn.X509Internal.forcedAuthenticationSupported:false}"
p:proxyRestrictionsEnforced="%{idp.authn.X509Internal.proxyRestrictionsEnforced:%{idp.authn.enforceProxyRestrictions:true}}"
p:proxyScopingEnforced="%{idp.authn.X509Internal.proxyScopingEnforced:false}"
p:discoveryRequired="%{idp.authn.X509Internal.discoveryRequired:false}"
p:lifetime="%{idp.authn.X509Internal.lifetime:%{idp.authn.defaultLifetime:PT1H}}"
p:inactivityTimeout="%{idp.authn.X509Internal.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
p:reuseCondition-ref="#{'%{idp.authn.X509Internal.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
p:activationCondition-ref="#{'%{idp.authn.X509Internal.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.X509Internal.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.X509Internal.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
p:subjectDecorator="#{getObject('%{idp.authn.X509Internal.subjectDecorator:}'.trim())}">
<property name="supportedPrincipalsByString">
<bean parent="shibboleth.CommaDelimStringArray"
c:_0="#{'%{idp.authn.X509Internal.supportedPrincipals:}'.trim()}" />
</property>
</bean>
</util:list> In older versions and upgraded systems, this list is defined in conf/authn/general-authn.xml. In V45, no default version of the list is provided and it may simply be placed in conf/global.xml if needed.
Notes
The beans and properties governing this feature have evolved over the years and the documentation above is canonical for this release. Many older variants, which may include X509 instead of X509Internal in the name, remain supported for compatibility but are no longer documented here.