Tuesday, October 25, 2011

Apache CXF STS documentation - part III

In the next couple of blog posts I will describe how to generate tokens in the new STS implementation shipped as part of Apache CXF 2.5. In this post I will detail the interface that is used for generating tokens, as well as an implementation to generate SecurityContextTokens that ships with the STS. In the next post, I will describe how to generate SAML tokens.

1) The TokenProvider interface

Security tokens are created in the STS via the TokenProvider interface. It has three methods:
  • boolean canHandleToken(String tokenType) - Whether this TokenProvider implementation can provide a token of the given type
  • boolean canHandleToken(String tokenType, String realm) - Whether this TokenProvider implementation can provide a token of the given type, in the given realm
  • TokenProviderResponse createToken(TokenProviderParameters tokenParameters) - Create a token using the given parameters
A client can request a security token from the STS by either invoking the "issue" operation and supplying a desired token type, or else calling the "validate" operation and passing a (different) token type (token transformation). Assuming that the client request is authenticated and well-formed, the STS will iterate through a list of TokenProvider implementations to see if they can "handle" the received token type. If they can, then the implementation is used to create a security token, which is returned to the client. The second "canHandleToken" method which also takes a "realm" parameter will be covered in a future post.

So to support the issuing of a particular token type in an STS deployment, it is necessary to specify a TokenProvider implementation that can handle that token type. The STS currently ships with two TokenProvider implementations, one for generating SecurityContextTokens, and one for generating SAML Assertions. Before we look at these two implementations, let's take a look at the "createToken" operation in more detail. This method takes a TokenProviderParameters instance.

2) TokenProviderParameters

The TokenProviderParameters class is nothing more than a collection of configuration properties to use in creating the token, which are populated by the STS operations using information collated from the request, or static configuration, etc. The properties of the TokenProviderParameters are:
  • STSPropertiesMBean stsProperties - A configuration MBean that holds the configuration for the STS as a whole, such as information about the private key to use to sign issued tokens, etc. This will be covered later.
  • EncryptionProperties encryptionProperties - A properties object that holds encryption information relevant to the intended recipient of the token. This will be covered later.
  • Principal principal - The current client Principal object. This can be used as the "subject" of the generated token.
  • WebServiceContext webServiceContext - The current web service context object. This allows access to the client request.
  • RequestClaimCollection requestedClaims - The requested claims in the token. This will be covered later.
  • KeyRequirements keyRequirements - A set of configuration properties relating to keys. This will be covered later.
  • TokenRequirements tokenRequirements - A set of configuration properties relating to the token. This will be covered later.
  • String appliesToAddress - The URL that corresponds to the intended recipient of the token
  • ClaimsManager claimsManager - An object that can manage claims. This will be covered later.
  • Map<String, Object> additionalProperties - Any additional (custom) properties that might be used by a TokenProvider implementation.
  • STSTokenStore tokenStore - A cache used to store tokens.
  • String realm - The realm to create the token in (this should be the same as the realm passed to "canHandleToken"). This will be covered later.
If this looks complicated then remember that the STS will take care of populating all of these properties from the request and some additional configuration. You only need to worry about the TokenProviderParameters object if you are creating your own TokenProvider implementation.

3) TokenProviderResponse

The "createToken" method returns an object of type TokenProviderResponse. Similar to the TokenProviderParameters object, this just holds a collection of objects that is parsed by the STS operation to construct a response to the client. The properties are:
  • Element token - The (DOM) token that was created by the TokenProvider.
  • String tokenId - The ID of the token
  • long lifetime - The lifetime of the token
  • byte[] entropy - Any entropy associated with the token
  • long keySize - The key size of a secret key associated with the token.
  • boolean computedKey - Whether a computed key algorithm was used in generating a secret key.
  • TokenReference attachedReference - An object which gives information how to refer to the token when it is "attached".
  • TokenReference unAttachedReference" - An object which gives information how to refer to the token when it is "unattached".
Most of these properties are optional as far as the STS operation is concerned, apart from the token and token ID. The TokenReference object contains information about how to refer to the token (direct reference vs. Key Identifier, etc.), that is used by the STS to generate the appropriate reference to return to the client. 

4) The SCTProvider

Now that we've covered the TokenProvider interface, let's look at an implementation that is shipped with the STS. The SCTProvider is used to provide a token known as a SecurityContextToken, that is defined in the WS-SecureConversation specification. A SecurityContextToken essentially consists of a String Identifier which is associated with a particular secret key. If a service provider receives a SOAP message with a digital signature which refers to a SecurityContextToken in the KeyInfo of the signature, then the service provider knows that it must somehow obtain a secret key associated with that particular Identifier to verify the signature. How this is done is "out of band" (more on this later).

To request a SecurityContextToken, the client must use one of the following Token Types:
  • http://schemas.xmlsoap.org/ws/2005/02/sc/sct
  • http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512
Two properties can be configured on the SCTProvider directly:
  • long lifetime - The lifetime of the generated SCT. The default is 5 minutes.
  • boolean returnEntropy - Whether to return any entropy bytes to the client or not. The default is true.
The SCTProvider generates a secret key using the KeyRequirements object that was supplied, and constructs a SecurityContextToken with a random Identifier. It creates a CXF SecurityToken object that wraps this information, and stores it in the supplied cache using the given lifetime. The SecurityContextToken element is then returned, along with the appropriate references, lifetime element, entropy, etc.

When requesting a token from an STS, the client will typically present some entropy along with a computed key algorithm. The STS will generate some entropy of its own, and combine it with the client entropy using the computed key algorithm to generate the secret key. Alternatively, the client will present no entropy, and the STS will supply all of the entropy. Any entropy the STS generates is then returned to the client, who can recreate the secret key using its own entropy, the STS entropy, and the computed key algorithm.

This secret key is then used for the SCT use-case to encrypt/sign some part of a message. The SecurityContextToken is placed in the security header of the message, and referred to in the KeyInfo element of the signed/encrypted structure. As noted earlier, the service provider must obtain somehow the secret key corresponding to the SecurityContextToken identifier. Perhaps the service provider shares a (secured) distributed cache with an STS instance. Or perhaps the service provider sends the SCT to an STS instance to "validate" it, and receives a SAML token in response with the embedded (encrypted) secret key.

5) Token caching in the TokenProvider

Finally, we will cover token caching in a TokenProvider implementation. The SCTProvider is essentially useless without a cache, as otherwise there is no way for a third-party to know the secret key corresponding to a SecurityContextToken. Any TokenProvider implementation can cache a generated token in the STSTokenStore object supplied as part of the TokenProviderParameters. This object simply wraps the TokenStore interface in the CXF WS-Security runtime, which itself contains basic methods for adding/removing/querying CXF SecurityToken objects.

The SCTProvider creates a SecurityToken with the ID of the SCT, the secret key associated with the SCT and the client principal. If a "realm" is passed through, then this is recorded as a property of the SecurityToken (keyed via STSConstants.TOKEN_REALM). Finally, the STS ships with two STSTokenStore implementations, an in-memory implementation based on eh-cache, and an implementation that uses Hazelcast.


  1. Hi Colm, I am slightly confused so I will reiterate. The client and STS generate a secret key like so:
    client entropy(optional) + server entropy -> client supplied key algorithm -> secret key

    This key is used for signing.

    My first question: I'm assuming that you must secure communication between client and STS when exchanging entropy and key algorithms otherwise an threat agent could easily steal the key.

    Same goes for key exchange between STS and SP (you mentioned this explicitly).

    My second question: what is the benefit of the entropy exchange? How is it any better than having the server generate a key? Is it just to increase the randomness of the key? Is it so the client can have some guarantee that the key is more random?



    1. Yes, all communication between an STS client and the STS must be secured either via TLS or message level security.

      I guess in theory the key exchange offers more security as an eavesdropper would have to intercept both the request + response to recreate the key. In practice though it doesn't make any real difference, as both should be secured.