public class Saml2Parser
extends java.lang.Object
Provides a SAML2 (Security Assertion Markup Language) response parser - a helper
class for SSO Filter / Security Manager Get SSO Auth Token script. A SAML2
Response is sent by an Identity Provider (like Microsoft ADFS server) to a
Service Provider (TM). The Identity Provider http POST as SAML Response to TM
(Service Provider) receives the SAML token as HttpServletRequest request
parameter. The parser first Base64 decodes the SAML response converting the raw
response to XML. Note the response structure varies greatly from different types
of Identity Providers software and the way they are configured.
Saml2Parser Usage
Example 1 and 2 demostrate the use of the parser. There is a static convenience
method has SAMLResponse(request). Requests that don't have a SAMLResponse may be
redirected back to the Identity Provider. A parser is constructed using new
Saml2Parser() then chains Fluent style properties setters. These properties
include setting the validation certificate and the keystore holding the private
encryption key. In a live TM system these are configured in the associated
Security Manager's Certificates tab. Processing checks are run to validate the
SAML response. By default the class will try to run all the checks. If your
token has Assertion Signatures but no Response Signature then use skip
skipResonseSignatureValidation(), see example 2 below. It is possible for unit
testing to save a SAMLResponse captured in Chrome Tools or this tool. The issue
with using this response to run a test in the future it will fail because of the
timestamp checks. To get it working will have to skip a number the date checks
listed in the table below. Once you have completed calling the setters and skip
method you can call parse(request). This validates the class has been setup
correctly and if configured incorrectly will throw an IllegalArgumentException.
Otherwise it will try validating and parsing the SAMLResponse, returning a
Saml2ParserResult
which if successful result.isValid will contain
an result.ssoAuthToken. The SsoAuthToken holds the user attributes (name, email,
groups etc) parsed from the SAML Token. It is returned by the Security Manager
Get SSO Auth Token script.
Logging
The Saml2ParserResult provides the following properties which are useful for
troubleshooting: responseRaw: The raw SAMLResponse (String) taken from the
request parameter. This can be useful for debug the Saml2Parser in a separate
unit test. responseBase64: The SAMLResponse XML (String) after it has been
Base64 decoded. This is useful to inspect the error: This will be present when
result.isValid is false, it will be null when result.isValid is true. It holds
the Throwable error that occurred during validation and parsing. The error can
be inspected to the cause of failure. The SecurityLogger can log this error and
display the failure message and stack trace. infoLog: A summary level log that
records when higher level sections have been started or completed. Use the
Security Logger to store this log. Below is a Sample info log.
Start parse()
Start validateAndParse()
Skipping ResponseSignatureValidation
pre: responseSucessfulValidation(response
Skipping responseDateCheck
Assertion signature validated
Skipping AssertionConditionCheck
Skipping assertionAuthnStatementCheck
Skipping assertionSubjectCheck
Execution Duration(ms): 16
debugLog: A detailed level log in text format, includes all the info log plus a
lot of logging in the validation and parsing. Below shows some of the extra
detail captured in the detail log.
New AttributeStatement
parseAttributeStatements(): unencrypted attribute.getName() http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
parseAttributeStatements(): unencrypted attribute.getName() http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn
parseAttributeStatements(): unencrypted attribute.getName() http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
parseAttributeStatements(): unencrypted attribute.getName() http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
parseAttributeStatements(): unencrypted attribute.getName() http://schemas.xmlsoap.org/claims/Group
parseAttributeStatements(): unencrypted attribute.getName() http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname
unencrypted attributes added for AttributeStatement
Finished adding encrypted attributes for AttributeStatement
Start parseAttributes(
getSSOAuthToken() XMLObject getFirstChild().getTextContent(): peter
getSSOAuthToken() XMLObject getFirstChild().getTextContent(): peter.panda@test.avoka.com
getSSOAuthToken() XMLObject getFirstChild().getTextContent(): panda
getSSOAuthToken() XMLObject getFirstChild().getTextContent(): peter.panda@test.avoka.com
getSSOAuthToken() XMLObject getFirstChild().getTextContent(): CN=TransactionManagerAccess,OU=Group,OU=Marketing,DC=test,DC=avoka,DC=com
getSSOAuthToken() XMLObject getFirstChild().getTextContent(): peter.panda
parseAssertions(): subject not encryptedparseAssertions(): NameID=org.opensaml.saml.saml2.core.impl.NameIDImpl@2e11485, NameID.getValue=:peter.panda
Execution Duration(ms): 16
By default the Saml2Parser does not do any logging direct to the TM or server
logs. Use the SecurityLogger to capture these properties. You must explicitly
add the output to the SecurityLogger (logger.info result.responseRaw) as per
Example 1 below.
Example 1
This is called by the Security Manager Get SSO Auth Token script
import com.avoka.core.groovy.SecurityLogger as logger
import com.avoka.tm.security.*
import com.avoka.fc.core.util.RedirectUtils
import com.avoka.fc.core.util.PortalUtils
import com.avoka.fc.core.entity.SecurityManager
import com.avoka.fc.core.util.RedirectUtils
// Stores the Entry URL into the session which is used by the Auth Ok Response Script.
if (!Saml2Parser.hasSamlToken(request)) {
logger.info "No SAML Token, Storing sessionEntryUrl and redirecting to ADFS server"
RedirectUtils.storeSessionEntryUrl(request)
return null
}
Saml2ParserResult result = new Saml2Parser()
.setValidationCertData(securityManager.getSsoValidatorCertData())
.setKeystoreData(securityManager.getSsoKeystoreData())
.setKeystorePassword(securityManager.getSsoKeystorePassword())
.setPrivateKeyAlias(securityManager.getSsoPrivateKeyAlias())
.setPrivateKeyPassword(securityManager.getSsoPrivateKeyPassword())
.setGroupAttribName("http://schemas.xmlsoap.org/claims/Group")
.setRPIdentifier("https://{TM_Server_IP}/{PORTAL_Context}")
.parse(request)
if (result.isValid) {
return result.ssoAuthToken
} else {
logger.debug result.debugLog
logger.debug result.responseRaw
logger.info result.validationErrors.join("\n")
logger.info "Redirecting to " + PortalUtils.getNotAuthorizedPath(portal)
throw new RedirectException(PortalUtils.getNotAuthorizedPath(portal))
}
Example 2
This Groovy example shows how to bypass a some of the inbuilt checking when
parsing the SAMLToken
Saml2ParserResult result = new Saml2Parser()
.setValidationCertData(securityManager.getSsoValidatorCertData())
.setKeystoreData(securityManager.getSsoKeystoreData())
.setKeystorePassword(securityManager.getSsoKeystorePassword())
.setPrivateKeyAlias(securityManager.getSsoPrivateKeyAlias())
.setPrivateKeyPassword(securityManager.getSsoPrivateKeyPassword())
.setGroupAttribName("http://schemas.xmlsoap.org/claims/Group")
.setRPIdentifier("https://{TM_Server_IP}/{PORTAL_Context}")
.setUrlDecodeResponse()
.skipRequireEncryption()
.skipResponseDateCheck()
.skipAssertionSubjectCheck()
.skipAssertionAuthnStatementCheck()
.skipAssertionConditionCheck()
.skipAssertionSignatureValidation()
.parse(request)
SAML Token Structure
Example SAML2 Tokens can be found on www.samltool.com. The following table show
is the XML Node Hierarchy of the SAML Response
Node Heirachy Description Skip Method
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Response Attr: IssueInstant tstamp skipResponseDateCheck()
Destination skipDestinationEndpointCheck()
Signature (optional): Signature for the whole response. skipResonseSignatureValidation()
Issuer Issuing server url eg ADFS server
Assertion (List): Holder for the user details.
Normally Encrypted. skipRequireEncryption()
Signature (optional): The signature for the assertion. skipAssertionSignatureValidation()
Issuer: url of the issuing server
Subject: skipAssertionSubjectCheck()
NameID This gets written to ssoAuthToken.username
SubjectConfirmation
SubjectConfirmationData Attr: notOnOrAfter (tstamp) skipAssertionSubjectCheck()
recipient should be the same as RPIdenifier skipAssertionSubjectCheck() or skipDestinationEndpointCheck()
Conditions: Attr: notBefore and notOnOrAfter (tstamp) skipAssertionConditionCheck()
AudienceRestriction
Audience (List): Check Relying Party Identity in List skipAssertionConditionCheck() also requires parser.setRPIdentifier()
AttributeStatement
Attribute (List): Contains the details for each user attrib.
AuthnStatement Attr: NotOnOrAfter tstamp skipAssertionAuthnStatementCheck()
IssueInstant
- Since:
- 5.1.4
Field Summary
Fields
Modifier and Type |
Field |
Description |
protected static java.lang.String |
REQUEST_PARAM_SAML_RESPONSE |
The SAMLResponse - Request Parameter Name.
|
Constructor Summary
Constructors
Constructor |
Description |
Saml2Parser() |
|
Method Summary
All Methods Static Methods Instance Methods Concrete Methods
Modifier and Type |
Method |
Description |
static boolean |
hasSamlToken(javax.servlet.http.HttpServletRequest request)
|
Returns true if the request has a SAML2 SAMLRequest or SAMLResponse
request parameters.
|
Saml2ParserResult |
parse(javax.servlet.http.HttpServletRequest request)
|
Parse the SAMLResponse from the given POST request.
|
Saml2Parser |
setDestinationEndpoint(java.lang.String destinationEndpoint)
|
Sets the DesinationEndpoint for Response Destination attribute and
Assertion Subject.
|
Saml2Parser |
setGroupAttribName(java.lang.String groupAttribName)
|
Sets the Group Attribute Name.
|
Saml2Parser |
setKeystoreData(byte[] keystoreData) |
Sets the keystore that holds the private key and public Certificate
keys.
|
Saml2Parser |
setKeystorePassword(java.lang.String keystorePassword)
|
Sets the keystore password.
|
Saml2Parser |
setPrivateKeyAlias(java.lang.String privateKeyAlias)
|
Sets the Private Key Alias for the keystore.
|
Saml2Parser |
setPrivateKeyPassword(java.lang.String privateKeyPassword)
|
Sets the Private Key Password.
|
Saml2Parser |
setRPIdentifier(java.lang.String rpIdentifier) |
Sets the Relying Party Identifier used by the security manager.
|
Saml2Parser |
setUrlDecodeResponse() |
Specify whether to URL decode the SAML response befpre Base64 decoding.
|
Saml2Parser |
setValidationCertData(byte[] validatorCertData) |
Sets the token signing certificate used for validating the SAML2
Signature.
|
Saml2Parser |
skipAssertionAuthnStatementCheck() |
Specify whether to skip the execution of the Assertion AuthnStatment
checks.
|
Saml2Parser |
skipAssertionConditionCheck() |
Specify whether to skip the execution of checks associated with the
Assertion Condition.
|
Saml2Parser |
skipAssertionSignatureValidation() |
Specify whether to skip the execution of the Assertion Signature
Validation checks.
|
Saml2Parser |
skipAssertionSubjectCheck() |
Specify whether to skip the execution of checks associated with the
Assertion Subject.
|
Saml2Parser |
skipDestinationEndpointCheck() |
Specify whether to skip the execution of checks associated with the
Response.
|
Saml2Parser |
skipRequireEncryption() |
Specify whether to skip the encryption requirement and allow an
unencypted SAML token to be parsed.
|
Saml2Parser |
skipResponseDateCheck() |
Specify whether to skip the execution of the Response Date Check on the
Response:@IssueInstant timestamp attribute.
|
Saml2Parser |
skipResponseSignatureValidation() |
Specify whether to skip the execution of the Response Signature
Validation.
|
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString,
wait, wait, wait
Field Detail
REQUEST_PARAM_SAML_RESPONSE
protected static final java.lang.String REQUEST_PARAM_SAML_RESPONSE
The SAMLResponse - Request Parameter Name.
- See Also:
- Constant Field Values
Constructor Detail
Saml2Parser
public Saml2Parser()
Method Detail
hasSamlToken
public
static boolean hasSamlToken(javax.servlet.http.HttpServletRequest request)
Returns true if the request has a SAML2 SAMLRequest or SAMLResponse request
parameters.
- Parameters:
-
request
- the HttpServletRequest Containing the SAMLResponse
(required)
- Returns:
- true if has a SAMLRequest or SAMLResponse request parameter
setValidationCertData
public Saml2Parser setValidationCertData(byte[] validatorCertData)
Sets the token signing certificate used for validating the SAML2 Signature.
- Parameters:
-
validatorCertData
- byte[] the certificate used for validating
the SAML2 Signature (Optional)
- Returns:
- the Saml2Parser
setKeystoreData
public Saml2Parser setKeystoreData(byte[] keystoreData)
Sets the keystore that holds the private key and public Certificate keys.
- Parameters:
-
keystoreData
- byte[] that holds the private key and keys
(Optional)
- Returns:
- the Saml2Parser
setKeystorePassword
public Saml2Parser setKeystorePassword(java.lang.String keystorePassword)
Sets the keystore password.
- Parameters:
keystorePassword
- String
- Returns:
- the Saml2Parser
setPrivateKeyAlias
public Saml2Parser setPrivateKeyAlias(java.lang.String privateKeyAlias)
Sets the Private Key Alias for the keystore.
- Parameters:
privateKeyAlias
- String
- Returns:
- the Saml2Parser
setPrivateKeyPassword
public Saml2Parser setPrivateKeyPassword(java.lang.String privateKeyPassword)
Sets the Private Key Password.
- Parameters:
privateKeyPassword
- String
- Returns:
- the Saml2Parser
setRPIdentifier
public Saml2Parser setRPIdentifier(java.lang.String rpIdentifier)
Sets the Relying Party Identifier used by the security manager.
- Parameters:
-
rpIdentifier
- (Optional) String for this space / environment
and eg https://tm.server.com/sso
- Returns:
- the Saml2Parser
setGroupAttribName
public Saml2Parser setGroupAttribName(java.lang.String groupAttribName)
Sets the Group Attribute Name. If the SAML2 attribute parser has
groupAttributeName configured then the
SSOAuthenticationToken
will any parsed groups as Spring
GrantedAuthority
s.
- Parameters:
groupAttribName
- String
- Returns:
- the Saml2Parser
setDestinationEndpoint
public Saml2Parser setDestinationEndpoint(java.lang.String destinationEndpoint)
Sets the DesinationEndpoint for Response Destination attribute and Assertion
Subject. SubjectConfirmationData recipient attribute. Used for unit testing,
This value that is normally used is request.getRequestURL()
- Parameters:
destinationEndpoint
- the destinationEndpoint to set.
- Returns:
- the Saml2Parser
setUrlDecodeResponse
public Saml2Parser setUrlDecodeResponse()
Specify whether to URL decode the SAML response befpre Base64 decoding.
- Returns:
- the Saml2Parser
skipRequireEncryption
public Saml2Parser skipRequireEncryption()
Specify whether to skip the encryption requirement and allow an unencypted SAML
token to be parsed.
- Returns:
- the Saml2Parser
skipResponseSignatureValidation
public Saml2Parser skipResponseSignatureValidation()
Specify whether to skip the execution of the Response Signature Validation.
- Returns:
- the Saml2Parser
skipResponseDateCheck
public Saml2Parser skipResponseDateCheck()
Specify whether to skip the execution of the Response Date Check on the
Response:@IssueInstant timestamp attribute.
- Returns:
- the Saml2Parser
skipAssertionSignatureValidation
public Saml2Parser skipAssertionSignatureValidation()
Specify whether to skip the execution of the Assertion Signature Validation
checks.
- Returns:
- the Saml2Parser
skipAssertionAuthnStatementCheck
public Saml2Parser skipAssertionAuthnStatementCheck()
Specify whether to skip the execution of the Assertion AuthnStatment checks.
- Returns:
- the Saml2Parser
skipAssertionConditionCheck
public Saml2Parser skipAssertionConditionCheck()
Specify whether to skip the execution of checks associated with the Assertion
Condition.
- Returns:
- the Saml2Parser
skipAssertionSubjectCheck
public Saml2Parser skipAssertionSubjectCheck()
Specify whether to skip the execution of checks associated with the Assertion
Subject.
- Returns:
- the Saml2Parser
skipDestinationEndpointCheck
public Saml2Parser skipDestinationEndpointCheck()
Specify whether to skip the execution of checks associated with the Response.
Destination attribute and the Assertion SubjectConfirmationData recipient.
- Returns:
- the Saml2Parser
parse
public Saml2ParserResult parse(javax.servlet.http.HttpServletRequest request)
Parse the SAMLResponse from the given POST request.
- Parameters:
-
request
- the servlet request which contains the SAML Token
(required)
- Returns:
- the Saml2ParserResult