Wednesday, June 6, 2012

Transforming Claims and Tokens in the CXF STS

The Security Token Service (STS) shipped with Apache CXF 2.6.0 contains some advanced functionality relating to handling claims, as well as transforming both claims and security tokens.

1) ClaimsValue support

The following article describes in detail how Claims are handled by the STS. The client includes a Claims element in the request to the STS, which typically contains one or more ClaimType URIs, that describe the types of claims that are to be included in the issued token. For example, the following element indicates that the client wants the STS to embed the role of the authenticated client in the issued token:

<t:Claims Dialect="http://.../identity">
    <ic:ClaimType Uri="http://.../claims/role"/>
</t:Claims>

The RequestParser object parses the client request and converts a received Claims element into a RequestClaimCollection object. The RequestClaimCollection is just a list of RequestClaim objects, along with a dialect URI. The RequestClaim object holds the claimType URI as well as a boolean indicating whether the claim is optional or not. Since the 2.6.0 (and 2.5.3) release, the RequestClaim object now also holds a claimValue String. This means that the STS now supports processing a Claims element with ClaimValue elements rather than ClaimType elements, e.g.:

<t:Claims Dialect="http://.../identity">
    <ic:ClaimValue Uri="http://.../claims/role">
        <ic:Value>admin</ic:Value>
    </ic:ClaimValue>
</t:Claims>

2) Custom Claims Parsing

Prior to CXF 2.5.3 and 2.6.0, it was not possible to change how the RequestParser parses a received Claims child element into a RequestClaim object. In CXF 2.5.3 and 2.6.0 this behaviour is configurable. The ClaimsParser interface defines a method to parse a Claims child element, as well as return the supported dialect URI that the implementation can handle. CXF ships with a default implementation that handles the "http://schemas.xmlsoap.org/ws/2005/05/identity" URI, and can parse both ClaimType and ClaimValue elements.

The RequestParser is passed a list of ClaimsParser objects, and iterates through the list to find a ClaimsParser implementation that can handle the given dialect. It uses the first ClaimsParser implementation that matches the supported dialect to generate a RequestClaim object. Therefore, to support a custom or non-standard Claims dialect, it is necessary to implement one or more ClaimsParser implementations to handle that dialect. These ClaimsParser objects must then be set on the ClaimsManager.

3) Token and Claims Transformation

The following blog article describes how token transformation works in the STS prior to CXF 2.5.3 and 2.6.0. Token transformation occurs when the user calls the WS-Trust Validate binding to validate a given token. If the token is valid, and if the user specifies a TokenType that differs from the type of the given token, the STS will attempt to transform the validated token into a token of the requested type. If the token is being issued in a different realm to that of the validated token, the principal associated with the validated token may also need to be transformed. This can be done by specifying an IdentityMapper object on the STSPropertiesMBean object used to configure the STS. This interface is used to map identities across realms. It has a single method:
  • Principal mapPrincipal(String sourceRealm, Principal sourcePrincipal, String targetRealm) - Map a principal from a source realm to a target realm
If the source realm is not null (the realm of the validated token as returned in TokenValidatorResponse), and if it does not equal the target realm (as set by the RealmParser), then the identity mapper is used to map the principal to the target realm and this is stored in TokenProviderParameters for use in token generation.

3.1) Transformation via Relationships

The logic for token transformation as described above is abstracted in CXF 2.5.3 and 2.6.0 to add the ability to perform more powerful and custom token and claim transformations. Two new properties are added to the STSPropertiesMBean object:
  • List<Relationship> getRelationships() - Get the list of Relationship objects to use.
  • RelationshipResolver getRelationshipResolver() - Get the RelationshipResolver object to use.
The Relationship class holds the parameters that will be required to define
a one-way relationship between a source and target realm. It consists of five properties:
  • String sourceRealm - The source realm of this relationship.
  • String targetRealm - The target realm of this relationship.
  • IdentityMapper identityMapper - The IdentityMapper to use to map a principal from the source realm to the target realm.
  • ClaimsMapper claimsMapper - The ClaimsMapper to use to map claims from the source realm to the target realm.
  • String type - The relationship type. Two types of relationships are supported: FederatedIdentity and FederatedClaims.
The RelationshipResolver is instantiated with a list of Relationship objects and contains the following method:
  • Relationship resolveRelationship(String sourceRealm, String targetRealm) - Retrieve the Relationship object that maps from the given source realm to the given target realm. 
3.2) Principal Transformation using Relationships

The logic described above for transforming principals when doing token transformation is still valid, but is deprecated in favour of using Relationships. When the token is being issued in a different realm to that of the validated token, the STS will first try to retrieve a RelationshipResolver object from the STSPropertiesMBean. If it exists, it will query it to retrieve a Relationship object that can map claims and principals from the source realm to the target realm. If it finds a match it will store this object on the token provider parameters, so the TokenProvider implementation can use this RelationshipResolver to perform some internal or custom mapping when generating the transformed token.

If the type of the Relationship object matches the FederatedIdentity type, then the STS will try to retrieve an IdentityMapper object to map the principal from the Relationship object. Failing this it will try to query the STSPropertiesMBean object for a generic IdentityMapper object if one is configured. This IdentityMapper object will be used to map the principal to the target realm. 

3.4) Claims Transformation using Relationships

If the type of the Relationship object retrieved above is "FederatedClaims", then the principal is not mapped, as claims are transformed at the time when the claims are required to create a token, e.g. in ClaimsAttributeStatementProvider.



No comments:

Post a Comment