ServiceProviderState
The new HTTP client shipped with nevisAuth 4.38.0.12 will likely require changes in this auth state configuration, specifically in the area of certificate configuration and handling.
Visit Appendix H for additional information.
Introduction and overview
The AuthState ServiceProviderState acts as a SAML 2.0 service provider (SP). It handles the following protocols according to the OASIS specification:
- Authentication Request Protocol (AuthnRequest, Response)
- SingleLogout (SP-initiated and IdP-initiated), with methods
- SOAP (as sender and receiver)
- POST (as sender and receiver)
- Other bindings described below
For information on assertions and protocols for the OASIS Security Assertion Markup Language (SAML) v2.0, see saml-core-2.0-os
Supported bindings:
- HTTP POST (as sender and receiver)
- HTTP Redirect (as sender and receiver)
- HTTP Artifact (as receiver)
- Additional, proprietary bindings
The ServiceProviderState verifies the SubjectConfirmations of incoming SAML assertions as mandated by the SAML specification. As explained in chapter Prospect verification, the prospect verification setting covers some use cases where a SubjectConfirmation may not be verifiable by the ServiceProviderState itself.
Limitation of SP-initiated SOAP SingleLogout
At the moment nevisAuth dos not support the following:
- Encryption for SOAP calls: The LogoutRequest and LogoutReponse sent by this method will not be encrypted or decrypted using any key, they will be just a SAML message with a signature and encoded with base64.
- Asynchronization for SOAP calls: When doing a SOAP call, the SP will wait until the IdP returns with a LogoutResponse.
Description
The following table and chapters describe the characteristics of the AuthState.
Topic | Description |
---|---|
Class | ch.nevis.esauth.auth.states.saml.ServiceProviderState |
Logging | Saml |
Auditing | none |
Marker | SAML:federation |
Methods
authenticate
Tries to consume any incoming SAML responses and, if successful, redirects to the location indicated by
RelayState
. If no SAML response is found and the user is already authenticated, it will transition to ok. Otherwise, it will use the configuredout.binding
to forward a generated AuthnRequest to the configured idpURL.In case of IDP-initiated SingleLogout, and if the request does not belong to any existing session but SAML contains a SessionIndex, nevisAuth will terminate all the sessions related to SessionIndex then consume LogoutRequest and send back a LogoutResponse. EnablePollTerminatedCalls must be enabled in nevisProxy to terminate the terminated sessions at nevisProxy side as well.
stepup
Same as authenticate, but can also initiate a logout if a LogoutRequest has been consumed successfully. It will use the configured
out.binding
to forward a generated AuthnRequest to the configured idpURL if the user does not have roles required by a SecurityRolesFilter.logout
Will use the configured
out.binding
to forward a generated LogoutRequest to the configured idpURL. This is the first step in an SP-initiated SingleLogout protocol.
Properties
consumerURL
(string, -)URL of the SAML consumer location. Messages to the IdP will request responses to be sent to this URL. The value of this property will be used as the AssertionConsumerServiceURLelement of the generated AuthnRequest.
consumerIndex
(int, -1)The consumerIndex is used to uniquely identify the service provider using a non-negative integer. The value is substituted before being forwarded in the AssertionConsumerServiceIndex element of the AuthnRequest.
When this attribute is set, then the value of consumerURL will be ignored: AssertionConsumerServiceURL will not be included in the generated AuthnRequest.
idpURL
(string, -)URL of the IdP. Messages to the IdP will use this as destination address. This property is required if the ServiceProviderState may send a request to an IdP.
logoutCompletedURL
(string, -)URL to which a redirect will be issued when a SingleLogout was completed.
limitSessionLifetime
(boolean, false)When activated, this feature limits the maximum lifetime of the user session to the validity period of the consumed SAML assertion (the validity period of a SAML assertion is determined by the optional attributes NotBefore and NotOnOrAfter). When the assertion becomes invalid, the session will automatically become invalid as well.
soap.httpclient.*
(String)Configure the outgoing HTTP communication towards the web locations specified in the connection properties. For a list of valid HTTP properties, see HTTP Client.
relayState
(string, ${request:resource})relayState to be encoded and sent to the IdP. The user is redirected to this URL after the SAML operation is completed successfully.
relayState.transformation
(string { "NONE", "OBFUSCATED_AND_ENCODED" }, "OBFUSCATED_AND_ENCODED")Transform RelayState before sending out:
NONE
RelayState will be untouched.OBFUSCATED_AND_ENCODED
RelayState will be obfuscated and thenBase64
encoded.
logoutType
({NONE, POST, SOAP}, NONE)Defines how the SP does the SP-initiated SingleLogout request to the IdP
- NONE: The SP uses the binding method configured in the out.binding property.
- POST: It enforces the use of POST for sending LogoutRequests from SP to IdP.
- SOAP: It enforces the use of SOAP for sending LogoutRequests from SP to IdP. For this method, the browser does not change the URL. The entire logout process takes place behind the screens. It does the call from server to server. To inform IDP which session needs to be terminated, LogoutRequest must include the session of IDP, IDP must set the
out.sessionIndex
.
Note: for SOAP logout, the session is terminated by nevisAuth. Therefore, EsAuth4ConnectorServlet in nevisProxy must set
EnablePollTerminatedCalls
to true for IdentityProvider to terminate the session in nevisProxy as well.
Input
in.binding
({auto,http-post,http-redirect,http-artifact, internal, internal-assertion, none}, "auto")Defines the accepted SAML binding. Set it to auto to have the AuthState guess the incoming binding.
A more fine-grained configuration allows incoming messages to use only specific bindings, depending on the type of message. This can be defined as follows:
<messageType>:<binding>, <messageType>:<binding>, ...
The following example will accept SAML Responses only if transmitted using artifact binding and LogoutRequests only if transmitted using redirect binding while accepting all other messages irrespective of the bindings used.
Response:http-artifact, LogoutRequest:http-redirect, auto
The binding none effectively disables processing of incoming messages such that input is ignored and only SP-initiated profiles are initiated.
In internal and internal-assertion binding, the AuthState expects the incoming message at the location configured in
in.internalBindingSource
. An internal-assertion causes the AuthState to expect and consume a SAML assertion instead of a SAML response. The state can handle plain or base64-encoded internal messages and will try to use base64-decode if it suspects that an encoded SAML message was received.infoFor the binding "http-artifact", hostname verification is enabled by default.
The relevant property is
soap.checkHostname
(boolean, true). When establishing an HTTPS connection, the client will check the hostname in the HTTPS server certificate against the actual server hostname by default. To disable hostname verification, set the propertysoap.checkHostname
to "false". For more information about the prefixsoap.*
, see the description of the propertysoap.*
further above in this list.in.internalBindingSource
(string, -)If the property
in.binding
is configured to "internal" or "internal-assertion", this propertyin.internalBindingSource
indicates the location of incoming messages.For example, suppose that the assertion is provided in the SAMLAssertion property of the inargs. The value of in.internalBindingSource must be
${inargs:SAMLAssertion}
.in.tolerance
(int (seconds), 5)Sets the tolerance for time constraints regarding the validation of incoming messages. This value should be set to the maximum expected clock skew between involved servers.
When the Service Provider receives an assertion, it will make the following checks:
- Validation of the AuthnInstant of the AuthnStatements in the assertion, by using
in.tolerance
+in.max_age
. - Validation of the IssueInstant of the assertion, by using
in.tolerance
+in.max_age
. - Validation of the NotBefore and NotAfter settings of the assertion, by using
in.tolerance
+ server currentTime.
- Validation of the AuthnInstant of the AuthnStatements in the assertion, by using
in.prospectVerification
(string, -)Comma-separated list of object types for which verification requirements are loosened. The precise nature of the verification done depends on the object type:
- Any signable object (like AuthnRequests, Assertions): prospectVerification means that the certificate of the signer may not be known in the configured truststore. This implies that the signature contains the signer's certificate or that it could not be verified.
- SubjectConfirmation: A HolderOfKey SubjectConfirmation is accepted even if it does not contain a reference to the client certificate of the request. The data of the SubjectConfirmation element is propagated in the notes with the prefix
saml.holder-of-key
(see the Notes.
in.audience
(string, -)Specifies the expected value of the audience attribute of an AudienceRestriction.
in.audienceRegex
(string, -)Similar to
in.audience
, but allows a regular expression to be configured, which is then matched against the audience attribute of an AudienceRestriction.in.audience.checkrequired
(boolean, false)Defines whether the audience check is required or not. If set to true, SAML assertions that do not contain AudienceRestriction elements will be rejected.
in.max_age
(int (seconds), 10)Defines the maximum time passed since the authentication of the subject took place (AuthnInstant). To disable the max age check, set the property value to -1. This is not recommended.
in.max_issue_age
(int (seconds), 10)Defines the maximum time passed since the assertion IssueInstant is generated. To disable the max age check, set the property value to -1. This is not recommended.
Note: If this value is not set, in.max_age is used for the assertion.
in.allowed_attributes
(string (list), -)Comma-separated list of allowed attributes of incoming assertions. If defined, this list functions as white-list for the attributes of incoming assertions.
in.required_attributes
(string (list), -)Comma-separated list of required attributes of incoming assertions. If defined, only assertions with all required attributes will be accepted.
in.artifact_sources
(string (map), required for artifact binding)List of sources for artifact resolution. The entries in the list have the following form:
[<sourceID>:]<sourceURL>
SourceID can be specified in hex (starting with 0x), base64 (exactly 28-character long) or as a string that must match the issuer ID. If the sourceID is omitted, the SHA-1 hash of the sourceURL will be used as the sourceID.
in.otu.class
(string, -)Defines a class implementing the interface
ch.nevis.esauth.auth.states.saml.OneTimeUseGuard
to handle the one-time use of SAML assertions.Supported implementations are:
ch.nevis.esauth.auth.states.saml.SimpleOneTimeUseGuard
File-based (local) assertion cache.
The class
nevis.esauth.auth.states.saml.SimpleOneTimeUseGuard
consumes the following configuration properties:in.otu.interval
(number [sec], 300)Assertion reaper run interval.
in.otu.dir
(strong, "/tmp/SAML-OneTimeUse-cache")Cache directory for processed assertions.
This class uses internal data structures to keep track of seen assertions and maintains files in the configured directory for persistency of this list in case of a shutdown or a crash. A reaper thread clears away entries and files of outdated assertions.
in.map_issuer_certificate
(boolean, "false")If set to true, the issuer of the incoming message will be used as
keyobjectref
for the configuredin.keystoreref
. This allows a secure consumption of SAML assertions from different IdPs.in.verify
(string (list), "Assertion, AuthnRequest, ArtifactResolve, ArtifactResponse")List of SAML message types that are expected to be signed and for which the signatures are verified against the configured key materials. See also chapter Signatures and signature validation.
in.verifyUniqueness
(boolean, "false")If set to true, the assertion will be checked for uniqueness, even if no HTTP POST binding is used.
in.keystoreref
,in.keyobjectref
(string, "DefaultKeyStore")These properties configure the key materials used to verify the signatures of SAML messages as listed in in.verify. Refer to chapter Certificates keys and public key infrastructure.
- If
in.map_issuer_certificate
is on,in.keyobjectref
should not be configured. Instead, thekeyobject
whose name matches the issuer of the incoming message will be used. - If
in.map_issuer_certificate
is off andin.ketobjectref
is not defined, the appropriate certificate will be searched in the keystore. In this case, one of the following must hold for the verification:- Signer certificate placed in signature and an exact duplicate of signer certificate found in the keystore
- Signer certificate placed in signature and the certificate of its issuing authority is found in the keystore
- In addition to the signer certificate, the certificate chain is delivered and the trusted root certificate can be found in the keystore.
- Signature references SKI, subject name, issuer serial or public key for which a certificate is found in the keystore
As part of the signature validation, trust, non-expiration and non-revocation is verified for all certificates involved in the trusted certificate chain. A configuration example can be found at the end of this chapter.
- If
in.decrypt.*
Properties for configuring decryption of incoming SAML messages. See also chapter Encryption and decryption.
in.relayState
(string, "${inargs:RelayState}"This property defines the source of the RelayState and may be used to manipulate or check incoming RelayStates.
Output
out.binding
({auto, http-post,http-redirect, http-post-deferred, http-redirect-deferred, propagate, internal}, "http-post")Defines the SAML binding for outgoing SAML messages.
The deferred bindings will prepare the necessary data, but instead of initiating the binding right away, it places those values in the following OutArg fields:
nevis.deferred-transfer.destination
The destination of the deferred bindingnevis.deferred-transfer.field.<fieldname>
The request, response and RelayState with field names SAMLRequest, SAMLResponse and RelayState respectively.
The internal binding may be used to propagate a SAML message, typically a SAML response, to a backend using nevisProxy's delegation mechanisms. The OutArgs
saml.SAMLResponse
,saml.SAMLRequest
andsaml.RelayState
will be set if applicable.In auto binding, the AuthState will attempt to use the binding of the incoming request. In that case, the configuration should ensure that there is always an incoming SAML request and that the same binding may be used to send the response.
As with
in.binding
, this setting may be further refined by defining different output bindings for different message types. For example:AuthnRequest:http-post, LogoutResponse:auto, LogoutRequest: http-redirect
out.issuer
(string, "${request:EsAuthId}")The issuer name to be used in outgoing SAML messages.
out.subject
(string, -)The subject in the AuthnRequest that will be stored in the
saml2:NameID
element.out.subject.nameQualifier
(string, -)The name qualifier in the AuthnRequest.
out.subject.spNameQualifier
(string, -)The name qualifier of the SP in the AuthnRequest.
out.subject.format
(string, -)The format definition in the AuthnRequest.
out.subject.spProviderId
(string, -)The SP provider ID in the AuthnRequest.
out.forceAuthn
(boolean, false)If set to true, the attribute ForceAuthn in the AuthnRequest will be set to true.
out.isPassive
(boolean, false)If set to true, the attribute IsPassive in the AuthnRequest will be set to true.
out.providerName
(string, -)The providerName in the AuthnRequest.
out.authnContextClassRef
(string, -)AuthnContextClassRef to be used in the authentication request protocol, e.g., "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
out.authnContextDeclRef
(string, -)The authentication context declaration provided by a URI to be used in the authentication request protocol.
out.authnContextComparison
(string, -)Specifies the comparison method used to evaluate the requested context classes or statements.
Possible values are:
- exact
- minimum
- maximum
- better
out.ttl
(int (seconds), 10)The time-to-live of generated SAML messages.
out.sign
(string (list), "LogoutRequest, AuthnRequest, ArtifactResolve")List of outgoing SAML message types that will be signed with the configured key materials for which the signatures. See also chapter Signatures and signature validation.
out.sign.hashAlgorithm
(string, "SHA256")Hash algorithm used in SAML signatures. Supported algorithms: SHA1, SHA256, SHA384, SHA512.
See also chapter Signatures and signature validation.
out.signatureKeyInfo
(comma-separated list of {SKI,Certificate,CertificateChain,Subject,IssuerSerial,CRLs,SubjectDN,SubjectCN,KeyNames,PublicKey}, SKI)List of KeyInfo content to add to signatures. One, several or none of the listed options may be configured. Note that some options require non-mandatory fields within signer certificate used. E.g., SKI may not add anything to the KeyInfo if the signer certificate does not contain an SKI.
infonevisAuth currently requires one SKI, Certificate or IssuerSerial to identify the correct verification certificate when several are configured. Similarly, Ninja only supports SKI when several verification certificates are configured.
out.keystoreref
,out.keyobjectref
These properties configure the key materials used to sign SAML messages whose type is listed in out.sign. Refer to chapter Certificates keys and public key infrastructure. The key material is validated for trust, non-expiration and non-revocation before the SAML message is signed.
out.encrypt.*
Properties for configuring encryption of outgoing SAML messages. See also chapter Encryption and decryption.
out.artifactSourceId
(string, issuer)The artifact source ID can optionally be set to define which identifier should be used in order for the other endpoint to identify the artifact resolution service. Usually, the issuer ID is used.
Plugins
out.extension.<extension-name>
(string, classname),<extension-name>.<property-name>
(syntax)This syntax specifies plug-ins that will be called to extend outgoing messages. Properties may be passed to the plug-ins using the second syntax shown.
Currently, only the output extender
ch.nevis.esauth.auth.states.saml.extensions.SuisseIDAttributeServiceExtender
is implemented for AuthnRequests. This extension adds requests for SuisseID attributes to outgoing messages. It takes the following properties:<extension-name>.Attribute
Comma-separated list of attributes to request in the issued message.
Example configuration for SuisseIDAttributeServiceExtender<property name="out.extension.SuisseID" value="ch.nevis.esauth.auth.states.saml.extensions.SuisseIDAttributeServiceExtender" />
<property name="SuisseID.Attribute" value="${inargs:attributes}" />
Input
All inputs used to resolve SAML bindings according to SAML specification: inargs: SAMLRequest, SAMLResponse, RelayState etc.
Transitions
ok
Successfully consumed incoming assertion or user is already authenticated.
logout
LogoutRequest was consumed.
logoutCompleted
A SingleLogout was completed and the final SingleLogoutResponse received.
logoutFailed
A SingleLogout failed.
status-*
The status-* transitions are based on status codes out of SAML response messages. The system traces such response status codes in the error log file and turns them into transitions. These transitions guide the authentication engine to the next AuthState in case something went wrong with the request.
When creating the status-* transitions, the system uses the following naming convention:
status-<StatusCode>-<SubStatusCode>
. For example, to react to the status codeurn:oasis:names:tc:SAML:2.0:status:Responder
, the system configures a transitionstatus-Responder
.infoThe subordinate second-level status code (
<SubStatusCode>
) is only added if it provides additional information on the error condition.Some examples of status-* transitions:
status-Responder
This transition comes into play if a request could not be performed due to an error on the part of the SAML responder or the SAML authority.
status-Responder-AuthnFailed
This transition becomes active if the responding provider was unable to successfully authenticate the principal.
Output
none
Errors
lasterror=99
lasterrorinfo=authentication error
Notes
saml.attributes.<attribute-name>
Attributes propagated in the SAML assertion
saml.issuer
Issuer of the SAML assertion
saml.destination
Destination of the SAML assertion
The following notes are propagated if a SubjectConfirmation element with the method "Holder of Key" is present. For detailed conditions also see the paragraph on "Holder of Key" in chapter "Prospect verification":
saml.holder-of-key.keyName
saml.holder-of-key.keyValue
saml.holder-of-key.encryptedKeys
saml.holder-of-key.certificate
saml.holder-of-key.ski
saml.holder-of-key.issuerName
saml.holder-of-key.serialNumber
saml.holder-of-key.subjectName
saml.holder-of-key.nameId
saml.holder-of-key.nameId.format
Key values of consumed SAML messages:
saml.request.*
saml.assertion.*
saml.response.*
The following values are propagated (with the appropriate prefix):
id, issuer, issueInstant, notBefore, notOnOrAfter, oneTimeUse, consent, destination, inResponseTo, statusCode, secondaryStatusCode, statusDetail, statusMessage, assertionConsumerServiceUrl, assertionConsumerServiceIndex, authnContextClassRef, authnContextDeclRef, authnContextDecl, authenticatingAuthorities, authnContextComparison, subjectLocality, subject, subject.nameQualifier, subject.spNameQualifier, subject.spProvidedId, subject.format, providerName, isPassive, forceAuthn, sessionIndex
Examples:
- To fetch the statusCode of a consumed response, use
${notes:saml.response.statusCode}
- To get the issuer of a consumed assertion, use
${notes:saml.assertion.issuer}
Example
<AuthState name="IGB2BServiceProvider" class="ch.nevis.esauth.auth.states.saml.ServiceProviderState" final="false">
<ResultCond name="ok" next="AuthDone" authLevel="auth.weak"/>
<Response value="AUTH_ERROR">
<Gui name="AuthErrorDialog"/>
</Response>
<property name="consumerURL" value="https://igb2b.zh.adnovum.ch/igb2b-consume/" />
<property name="idpURL" value="https://adnovum.igb2b.ch/consume/" />
<property name="in.verify" value="Assertion" />
<property name="in.binding" value="auto"/>
<property name="in.max_age" value="30"/>
<property name="in.keystoreref" value="IGB2BIdentityProvider" />
<property name="in.keyobjectref" value="IGB2B" />
<property name="in.allowed_attributes" value="language,surname,givenname,email" />
<property name="out.sign" value="none" />
<property name="out.binding" value="http-redirect"/>
<property name="out.ttl" value="10"/>
<property name="out.issuer" value="adnovum.ch" />
</AuthState>
<KeyStore name="TrustStore">
<KeyObject name="TrustedCertificates" certificate="/var/opt/keybox/nevis/truststore.jks">
<property name="certPassPhrase" value="secret">
</KeyStore>
<AuthState name="ServiceProvider" class="ch.nevis.esauth.auth.states.saml.ServiceProviderState" final="false">
<ResultCond name="ok" next="AuthDone" authLevel="auth.weak"/>
<Response value="AUTH_ERROR">
<Gui name="AuthErrorDialog"/>
</Response>
<property name="consumerURL" value="https://serviceprovider.zh.adnovum.ch/consume/" />
<property name="idpURL" value="https://identityprovider.ch/" />
<property name="in.verify" value="Assertion" />
<property name="in.binding" value="auto"/>
<property name="in.max_age" value="30"/>
<property name="in.keystoreref" value="TrustStore" />
<property name="in.allowed_attributes" value="language,surname,givenname,email" />
<property name="out.sign" value="none" />
<property name="out.binding" value="http-redirect"/>
<property name="out.ttl" value="10"/>
<property name="out.issuer" value="adnovum.ch" />
</AuthState>