Tuesday, June 19, 2012

SAML Web SSO profile support in Apache CXF

Apache CXF has an impressive range of security features for JAX-RS endpoints. It also has excellent documentation in this space, see for example the JAX-RS documentation for OAuth, SAML Assertions and XML Encryption/Signature.  Apache CXF 2.6.1 enhances the JAX-RS security story further by featuring support for the SAML 2.0 Web SSO profile.

The basic standard scenario for Web SSO involves a client browser accessing a secured (JAX-RS) endpoint. The endpoint constructs a SAML AuthnRequest and includes it in redirecting the browser to a Identity Provider (IDP) for authentication (via a dialog). The IDP constructs a SAML Response, and redirects the browser to a Request Assertion Consumer Service (RACS) URI contained in the AuthnRequest.  The RACS validates the SAML Response and redirects the browser yet again to the original secured endpoint. The endpoint stores the session in a cookie (hence single sign-on) and access is granted to the resource. The following steps detail how to implement this scenario in Apache CXF using the new "cxf-rt-rs-security-sso-saml" module.

1) JAX-RS binding filters

The SAML 2.0 bindings specification defines HTTP redirect and HTTP POST bindings which can be used to "redirect" the client browser, e.g. from the secured endpoint to the IDP. Apache CXF 2.6.1 provides a separate JAX-RS filter to support these bindings. Therefore, the first step in securing a JAX-RS endpoint is to decide which of these two bindings to use. The SamlRedirectBindingFilter class providers support for the HTTP redirect binding, and the SamlPostBindingFilter provides support for the HTTP POST binding. Both of these filters share the following configuration properties.

1.1) Required Configuration Properties

Each filter implementation must be configured with the URL of the IDP, as well as the URL of the RACS. It must also be configured with a SPStateManager implementation to keep track of the Authenticated sessions. CXF ships with an EhCache based implementation:
  • SPStateManager stateProvider - An object which keeps track of authenticated sessions.
  • String idpServiceAddress - The URL of the IDP.
  • String assertionConsumerServiceAddress - The URL of the RACS. This can be a relative or absolute URL.
1.2) Signature Configuration Properties 

The following configuration properties are only required if you wish to sign the AuthnRequest:
  • boolean signRequest - Whether to sign the AuthnRequest or not. The default is false.
  • String signatureUsername - The keystore alias to use to sign the AuthnRequest.
  • Crypto signatureCrypto - A WSS4J Crypto object if the SAML AuthnRequest is to be signed.
  • String signaturePropertiesFile - This points to a properties file that can be used to load a Crypto instance if the SAML AuthnRequest is to be signed. 
  • CallbackHandler callbackHandler - A CallbackHandler object to retrieve the private key password used to sign the request.
  • String callbackHandlerClass - A class name that is loaded for use as the CallbackHandler object. 
Either the "signatureCrypto" or "signaturePropertiesFile" properties must be set if "signRequest" is set to true. Similarly, either "callbackHandler" or "callbackHandlerClass" must be configured.

1.3) Optional Configuration Properties

Here are some optional configuration properties that can be set:
  • long stateTimeToLive - The default value (in milliseconds) that a session is valid for. The default value is 2 minutes. 
  • String issuerId - The Issuer Id value to be included in the AuthnRequest. It defaults to the Base URI.
  • AuthnRequestBuilder authnRequestBuilder - An object that constructs the AuthnRequest. It defaults to DefaultAuthnRequestBuilder.
There are some additional optional configuration properties relating to domains and web application contexts that will be covered in more detail on the CXF wiki.

1.4) Sample Spring configuration

Here is a sample spring configuration extract to support the redirect binding filter which signs AuthnRequests:

<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager"/>

<bean id="ssoSignedRedirectURI"  class="org.apache.cxf.rs.security.saml.sso.SamlRedirectBindingFilter">
        <property name="idpServiceAddress" value="https://.../idp-sig/"/>
        <property name="assertionConsumerServiceAddress"
                  value="/racs/sso"/>
        <property name="stateProvider" ref="stateManager"/>
        <property name="addEndpointAddressToContext" value="true"/>
        <property name="callbackHandlerClass" value="....SSOCallbackHandler"/>
        <property name="signatureUsername" value="myservicekey"/>
        <property name="signaturePropertiesFile" value="serviceKeystore.properties"/>
        <property name="signRequest" value="true"/>
</bean>

<jaxrs:server address="/app1">
       <jaxrs:serviceBeans><ref bean="..."/></jaxrs:serviceBeans>
       <jaxrs:providers><ref bean="ssoRedirectURI"/></jaxrs:providers>
</jaxrs:server>

2) The Request Assertion Consumer Service

The JAX-RS filters described above take care of creating a SAML AuthnRequest, optionally signing it, and redirecting the client browser to the IDP. The next step is to define a RequestAssertionConsumerService (RACS) which will intercept the SAML Response from the IDP. The RACS processes the SAML Response, and validates it in a number of ways:
  • The SAMLProtocolResponseValidator validates the Response against the specifications and checks the signature of the Response (if it exists), as well as doing the same for any child Assertion of the Response. It validates the status code of the Response as well. 
  • The SAMLSSOResponseValidator validates the Response according to the Web SSO profile. 
If validation is successful the RACS redirects to the service provider endpoint.

2.1) Configuration properties shared with the filters

The RequestAssertionConsumerService that ships with CXF shares a number of configuration properties with the filters, mainly relating to state and signature configuration:
  • SPStateManager stateProvider - An object which keeps track of authenticated sessions. This is required.
  • long stateTimeToLive - The default value (in milliseconds) that a session is valid for. The default value is 2 minutes.
  • Crypto signatureCrypto - A WSS4J Crypto object to use to validate a signed Response.
  • String signaturePropertiesFile - This points to a properties file that can be used to load a Crypto instance for signature validation.
  • CallbackHandler callbackHandler - A CallbackHandler object to retrieve the private key password used to decrypt an encrypted request.
  • String callbackHandlerClass - A class name that is loaded for use as the CallbackHandler object.  
Only the "stateProvider" property is required. Either the "signatureCrypto" or "signaturePropertiesFile" properties must be set if you wish to support verifying signed Responses, or signed Assertions contained in a Response. Similarly, either "callbackHandler" or "callbackHandlerClass" must be configured if you wish to support decrypting encrypted Assertions. 

2.2) Additional Optional Configuration properties

The RACS supports the following additional (optional) configuration properties:
  • boolean supportDeflateEncoding - Whether Deflate encoding is used to inflate a token received via the Redirect binding. The default is true.
  • boolean supportBase64Encoding - Whether the token is Base64 decoded or not. The default is true.
  • boolean enforceAssertionsSigned - Whether the Assertions contained in a Response must be signed or not. The default is true.
  • boolean enforceKnownIssuer - Whether the Issuer of the Response (and child Assertions) is "known" to the RACS. This value is compared against the IDP URL configured on the filter. The default value is true.
  • TokenReplayCache<String> replayCache - A TokenReplayCache implementation to store Assertion ID's for the POST binding to guard against replay attacks. The default uses an implementation based on EhCache.
2.4) Sample Spring Configuration

Here is a sample spring configuration extract to set up a RACS, that could be used with the filter configuration in section 1.4:

 <bean id="consumerService" class="org.apache.cxf.rs.security.saml.sso.RequestAssertionConsumerService">
        <property name="stateProvider" ref="stateManager"/>
        <property name="signaturePropertiesFile" value="serviceKeystore.properties"/>
        <property name="enforceKnownIssuer" value="false"/>
        <property name="callbackHandlerClass" value="...SSOCallbackHandler"/>
</bean>

3) The Identity Provider (IDP)

The remaining piece of the puzzle is the Identity Provider (IDP) which receives the SAML AuthnRequest from the service provider, processes it accordingly, and then interacts with the client browser to authenticate the client. It then creates a SAML Response and redirects the client browser to the RACS defined in the AuthnRequest. Apache CXF does not (yet) ship with an IDP, although this may change in the near future. However, there are a number of open-source IDPs that can be used with a CXF JAX-RS endpoint that supports SAML Web SSO. These include Shibboleth, PicketLink, OpenAM, JOSSO, etc. I have tested against all of these products. Report any interop issues to the CXF JIRA.

4) Ongoing Development

SAML Web SSO profile support is still being actively developed. A number of bugs have been fixed that do not yet appear in a released version of CXF. For example, support for decrypting encrypted Assertions in a SAML Response, and some bugs relating to signed Assertions (CXF-4352 and CXF-4365).

Thursday, June 14, 2012

Simplified Apache CXF STS configuration

The Apache CXF STS configuration options have been covered in detail in previous posts on this blog. Following some suggestions by Glen Mazza, a new simplified way of configuring the STS will be available in Apache CXF 2.6.2. This new configuration is essentially a simpler and more intuitive way of catering for the most common STS scenarios. The older configuration style is still fully supported.

An example of how to configure the CXF STS using the old configuration is available here. It involves a mixture of the STS Provider API that lives in the WS-Security module in CXF, and the concrete STS functionality that is available in the STS services module in CXF. The SecurityTokenServiceProvider in the CXF API is instantiated with implementations of the various Operations (Issue/Validate/etc.) that are available in the CXF STS. However, the flexibility of this approach leads to a slightly verbose configuration style, which is perhaps overly complicated for the most common use-cases.

An example of the simpler configuration approach is available here. Rather than use the SecurityTokenServiceProvider in the CXF API, it uses a sub-class in the CXF STS (DefaultSecurityTokenServiceProvider). This implementation supports the issue and validate bindings by default. It also supports the ability to issue and validate SAML Tokens, and to validate UsernameTokens and X.509 Tokens. Therefore, for any of these use-cases there is no need to use the old-style configuration, which involves explicitly instantiating each TokenProvider or TokenValidator instance and setting them on an IssueOperation/ValidateOperation instance.  However, if you want to use the renew or cancel bindings, or do anything with SecurityContextTokens, it's necessary to use the old configuration.

The DefaultSecurityTokenServiceProvider can be configured with the following (optional) properties:
  • boolean encryptIssuedToken - Whether to encrypt the issued token or not. The default is false.
  • List<ServiceMBean> services - A list of service endpoints to support. See here for more information.
  • boolean returnReferences - Whether to return references to an issued token or not. The default is true.
  • TokenStore tokenStore - The TokenStore caching implementation to use. See here for more information.
  • ClaimsManager claimsManager - The ClaimsManager to use if you want to be able to handle claims. See here for more information.

Thursday, June 7, 2012

New security vulnerabilities in Apache CXF

Two new security vulnerabilities have been announced in Apache CXF. Those of you using WS-SecurityPolicy should read the announcements carefully to make sure that you are not affected. If these vulnerabilities apply to your deployment then you should upgrade to a more recent version of CXF that contains fixes for these vulnerabilities. The issues in question are:
  • CVE-2012-2378 - Apache CXF does not pick up some child policies of
    WS-SecurityPolicy 1.1 SupportingToken policy assertions on the client
    side.
  • CVE-2012-2379 - Apache CXF does not verify that elements were
    signed or encrypted by a particular Supporting Token.

     

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.