Thursday, October 27, 2011

Apache CXF STS documentation - part IV

In the previous post I covered the TokenProvider interface, which is used to generate tokens in the STS, and an implementation that ships with the STS to generate SecurityContextTokens. In this post, I will cover the other TokenProvider implementation that ships with the STS, which issues SAML Tokens (both 1.1 and 2.0).

1) The SAMLTokenProvider

The SAMLTokenProvider can issue SAML 1.1 and SAML 2.0 tokens. To request a SAML 1.1 token, the client must use one of the following Token Types:
  • http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1
  • urn:oasis:names:tc:SAML:1.0:assertion
To request a SAML 2.0 token, the client must use one of the following Token Types:
  • http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0
  • urn:oasis:names:tc:SAML:2.0:assertion
The following properties can be configured on the SAMLTokenProvider directly:
  • List<AttributeStatementProvider> attributeStatementProviders - A list of objects that can add attribute statements to the token.
  • List<AuthenticationStatementProvider> authenticationStatementProviders - A list of objects that can add authentication statements to the token.
  • List<AuthDecisionStatementProvider> authDecisionStatementProviders - A list of objects that can add authorization decision statements to the token.
  • SubjectProvider subjectProvider - An object used to add a Subject to the token.
  • ConditionsProvider conditionsProvider - An object used to add a Conditions statement to the token.
  • boolean signToken - Whether to sign the token or not. The default is true.
  • Map<String, SAMLRealm> realmMap - A map of realms to SAMLRealm objects.
We will explain each of these properties in more detail in the next few sections.

2) Realms in the TokenProviders

As explained in the previous post, the TokenProvider interface has a method that takes a realm parameter:
  • boolean canHandleToken(String tokenType, String realm) - Whether this TokenProvider implementation can provide a token of the given type, in the given realm
In other words, the TokenProvider implementation is being asked whether it can supply a token corresponding to the Token Type in a particular realm. How the STS knows what the desired realm is will be covered in a future post. However, we will explain how the realm is handled by the TokenProviders here. The SCTProvider ignores the realm in the canHandleToken method. In other words, the SCTProvider can issue a SecurityContextToken in *any* realm. If a realm is passed through via the TokenProviderParameters when creating the token, the SCTProvider will cache the token with the associated realm as a property (this was explained in the previous post).

Unlike the SCTProvider, the SAMLTokenProvider does not ignore the realm parameter to the "canHandleToken" method. Recall that the SAMLTokenProvider has a property "Map<String, SAMLRealm> realmMap". The canHandleToken method checks to see if the given realm is null, and if it is not null then the realmMap *must* contain a key which matches the given realm. So if the STS implementation is designed to issue tokens in different realms, then the realmMap of the SAMLTokenProvider must contain the corresponding realms in the key-set of the map.

The realmMap property maps realm Strings to SAMLRealm objects. The SAMLRealm class contains the following properties:
  • String issuer - the Issuer String to use in this realm
  • String signatureAlias - the keystore alias to use to retrieve the private key the SAMLTokenProvider uses to sign the generated token
In other words, if the SAMLTokenProvider is "realm aware", then it can issue tokens with an issuer name and signing key specific to a given realm. If no realm is passed to the SAMLTokenProvider, then these properties are obtained from the "system wide" properties defined in the STSPropertiesMBean object passed as part of the TokenProviderParameters, which can be set via the following methods:
  • void setSignatureUsername(String signatureUsername)
  • void setIssuer(String issuer)
Two additional properties are required when signing SAML Tokens. A password is required to access the private key in the keystore, which is supplied by a CallbackHandler instance. A WSS4J "Crypto" instance is also required which controls access to the keystore. These are both set on the STSPropertiesMBean object via:
  • void setCallbackHandler(CallbackHandler callbackHandler)
  • void setSignatureCrypto(Crypto signatureCrypto)
Note that the signature of generated SAML Tokens can be disabled, by setting the "signToken" property of the SAMLTokenProvider to "false". As per the SCTProvider, the generated SAML tokens are stored in the cache with the associated realm stored as a property.

3) Populating SAML Tokens

In the previous section we covered how a generated SAML token is signed, how to configure the key used to sign the assertion, and how to set the Issuer of the Assertion. In this section we will describe how to populate the SAML Token itself. The SAMLTokenProvider is designed to be able to issue a wide range of SAML Tokens. It does this by re-using the SAML abstraction library that ships with Apache WSS4J, which defines a collection of beans that are configured and then assembled in a CallbackHandler to create a SAML assertion.

3.1) Configure a Conditions statement

The SAMLTokenProvider has a "ConditionsProvider conditionsProvider" property, which can be used to configure the generated Conditions statement which is added to the SAML Assertion. The ConditionsProvider has a method to return a ConditionsBean object, and a method to return a lifetime in seconds. The ConditionsBean holds properties such as the not-before and not-after dates, etc. The SAMLTokenProvider ships with a default ConditionsProvider implementation that is used to insert a Conditions statement in every SAML token that is generated. This implementation uses a default lifetime of 5 minutes, and set the Audience Restriction URI of the Conditions Statement to be the received "AppliesTo" address, which is obtained from the TokenProviderParameters object.

The DefaultConditionsProvider can be configured to change the lifetime of the issued token. If you want to remove the ConditionsProvider altogether from the generation assertion, or implement a custom Conditions statement, then you must implement an instance of the ConditionsProvider interface, and set it on the SAMLTokenProvider.

3.2) Configure a Subject

The SAMLTokenProvider has a "SubjectProvider subjectProvider" property, which can be used to configure the Subject of the generated token, regardless of the version of the token. The SubjectProvider interface defines a single method to return a SubjectBean, given the token provider parameters, the parent Document of the assertion, and a secret key to use (if any). The SubjectBean contains the Subject name, name-qualifier, confirmation method, and KeyInfo element, amongst other properties. The SAMLTokenProvider ships with a default SubjectProvider implementation that is used to insert a Subject into every SAML Token that is generated.

The DefaultSubjectProvider has a single configuration method to set the subject name qualifier. It creates a subject confirmation method by checking the received key type. The subject name is the name of the principal obtained from TokenProviderParameters. Finally, a KeyInfo element is set on the SubjectBean under the following conditions:
  • If a "SymmetricKey" Key Type algorithm is specified by the client, then the secret key passed through to the SubjectProvider is encrypted with the X509Certificate of the recipient, and added to the KeyInfo element. How the provider knows the public key of the recipient will be covered later.
  • If a "PublicKey" KeyType algorithm is specified by the client, the X509Certificate that is received as part of the "UseKey" request is inserted into the KeyInfo element of the Subject.
If a "Bearer" KeyType algorithm is specified by the client, then no KeyInfo element is added to the Subject. For the "SymmetricKey" Key Type case, the SAMLTokenProvider creates a secret key using a SymmetricKeyHandler instance. The SymmetricKeyHandler first checks the key size that is supplied as part of the KeyRequirements object, by checking that it fits in between a minimum and maximum key size that can be configured. It also checks any client entropy that is supplied, as well as the computed key algorithm. It then creates some entropy and a secret key.

To add a custom Subject element to an assertion, you must create your own SubjectProvider implementation, and set it on the SAMLTokenProvider.

3.3) Adding Attribute Statements

The SAMLTokenProvider has a "List<AttributeStatementProvider> attributeStatementProviders" property, which can be used to add AttributeStatments to the generated assertion. Each object in the list adds a single Attribute statement. The AttributeStatementProvider contains a single method to return an AttributeStatementBean given the TokenProviderParameters object. This contains a SubjectBean (for SAML 1.1 assertions), and a list of AttributeBeans. The AttributeBean object holds the attribute name/qualified-name/name-format, and a list of attribute values, amongst other properties.

If no statement provider is configured in the SAMLTokenProvider, then the DefaultAttributeStatementProvider is invoked to create an Attribute statement to add to the assertion. It creates a default "authenticated" attribute, and also creates separate Attributes for any "OnBehalfOf" or "ActAs" elements that were received in the request. If the received OnBehalfOf/ActAs element was a UsernameToken, then the username is added as an Attribute. If the received element was a SAML Assertion, then the subject name is added as an Attribute. 

3.4) Adding Authentication Statements

The SAMLTokenProvider has a "List<AuthenticationStatementProvider> authenticationStatementProviders" property, which can be used to add AuthenticationStatements to the generated assertion. Each object in the list adds a single Authentication statement. The AuthenticationStatementProvider contains a single method to return an AuthenticationStatementBean given the TokenProviderParameters object. This contains a SubjectBean (for SAML 1.1 assertions), an authentication instant, authentication method, and other properties. No default implementation of the AuthenticationStatementProvider interface is provided in the STS, so if you want to issue Authentication Statements you will have to write your own.

3.5) Adding Authorization Decision Statements

The SAMLTokenProvider has a "List<AuthDecisionStatementProvider> authDecisionStatementProviders" property, which can be used to add AuthzDecisionStatements to the generated assertion. Each object in the list adds a single statement. The AuthDecisionStatementProvider  contains a single method to return an AuthDecisionStatementBean given the TokenProviderParameters object. This contains a SubjectBean (for SAML 1.1 assertions), the decision (permit/indeterminate/deny), the resource URI, a list of ActionBeans, amongst other properties. No default implementation of the AuthDecisionStatementProvider interface is provided in the STS.

Note that for SAML 1.1 tokens, the Subject is embedded in one of the Statements. When creating a SAML 1.1 Assertion, if a given Authentication/Attribute/AuthzDecision statement does not have a subject, then the standalone Subject is inserted into the statement. Finally, once a SAML token has been created, it is stored in the cache (if one is configured), with a lifetime corresponding to that of the Conditions statement. A TokenProviderResponse object is created with the DOM representation of the SAML Token, the SAML Token ID, lifetime, entropy bytes, references, etc.

No comments:

Post a Comment