Chapter 7. Authentication

Abstract

This chapter describes how to use policies to configure authentication in a Apache CXF application. Currently, the only credentials type supported in the SOAP layer is the WS-Security UsernameToken.

7.1. Introduction to Authentication

Overview

In Apache CXF, an application can be set up to use authentication through a combination of policy assertions in the WSDL contract and configuration settings in Blueprint XML.

Note

Remember, you can also use the HTTPS protocol as the basis for authentication and, in some cases, this might be easier to configure. See Section 3.1, “Authentication Alternatives”.

Steps to set up authentication

In outline, you need to perform the following steps to set up an application to use authentication:

  1. Add a supporting tokens policy to an endpoint in the WSDL contract. This has the effect of requiring the endpoint to include a particular type of token (client credentials) in its request messages.
  2. On the client side, provide credentials to send by configuring the relevant endpoint in Blueprint XML.
  3. (Optional) On the client side, if you decide to provide passwords using a callback handler, implement the callback handler in Java.
  4. On the server side, associate a callback handler class with the endpoint in Blueprint XML. The callback handler is then responsible for authenticating the credentials received from remote clients.

7.2. Specifying an Authentication Policy

Overview

If you want an endpoint to support authentication, associate a supporting tokens policy assertion with the relevant endpoint binding. There are several different kinds of supporting tokens policy assertions, whose elements all have names of the form *SupportingTokens (for example, SupportingTokens, SignedSupportingTokens, and so on). For a complete list, see the section called “SupportingTokens assertions”.

Associating a supporting tokens assertion with an endpoint has the following effects:

  • Messages to or from the endpoint are required to include the specified token type (where the token’s direction is specified by the sp:IncludeToken attribute).
  • Depending on the particular type of supporting tokens element you use, the endpoint might be required to sign and/or encrypt the token.

The supporting tokens assertion implies that the runtime will check that these requirements are satisified. But the WS-SecurityPolicy policies do not define the mechanism for providing credentials to the runtime. You must use Blueprint XML configuration to specify the credentials (see Section 7.3, “Providing Client Credentials”).

Syntax

The *SupportingTokens elements (that is, all elements with the SupportingTokens suffix—see the section called “SupportingTokens assertions”) have the following syntax:

<sp:SupportingTokensElement xmlns:sp="..." ... >
  <wsp:Policy xmlns:wsp="...">
    [Token Assertion]+
    <sp:AlgorithmSuite ... > ... </sp:AlgorithmSuite> ?
    (
      <sp:SignedParts ... > ... </sp:SignedParts> |
      <sp:SignedElements ... > ... </sp:SignedElements> |
      <sp:EncryptedParts ... > ... </sp:EncryptedParts> |
      <sp:EncryptedElements ... > ... </sp:EncryptedElements> |
    ) *
    ...
  </wsp:Policy>
  ...
</sp:SupportingTokensElement>

Where SupportingTokensElement stands for one of the supporting token elements, *SupportingTokens.Typically, if you simply want to include a token (or tokens) in the security header, you would include one or more token assertions, [Token Assertion], in the policy. In particular, this is all that is required for authentication.

If the token is of an appropriate type (for example, an X.509 certificate or a symmetric key), you could theoretically also use it to sign or encrypt specific parts of the current message using the sp:AlgorithmSuite, sp:SignedParts, sp:SignedElements, sp:EncryptedParts, and sp:EncryptedElements elements. This functionality is currently not supported by Apache CXF, however.

Sample policy

Example 7.1, “Example of a Supporting Tokens Policy” shows an example of a policy that requires a WS-Security UsernameToken token (which contains username/password credentials) to be included in the security header. In addition, because the token is specified inside an sp:SignedSupportingTokens element, the policy requires that the token is signed. This example uses a transport binding, so it is the underlying transport that is responsible for signing the message.

For example, if the underlying transport is HTTPS, the SSL/TLS protocol (configured with an appropriate algorithm suite) is responsible for signing the entire message, including the security header that contains the specified token. This is sufficient to satisfy the requirement that the supporting token is signed.

Example 7.1. Example of a Supporting Tokens Policy

<wsp:Policy wsu:Id="UserNameOverTransport_IPingService_policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:TransportBinding> ... </sp:TransportBinding>
      <sp:SignedSupportingTokens
          xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:UsernameToken
              sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:WssUsernameToken10/>
            </wsp:Policy>
          </sp:UsernameToken>
        </wsp:Policy>
      </sp:SignedSupportingTokens>
      ...
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

Where the presence of the sp:WssUsernameToken10 sub-element indicates that the UsernameToken header should conform to version 1.0 of the WS-Security UsernameToken specification.

Token types

In principle, you can specify any of the WS-SecurityPolicy token types in a supporting tokens assertion. For SOAP-level authentication, however, only the sp:UsernameToken token type is relevant.

sp:UsernameToken

In the context of a supporting tokens assertion, this element specifies that a WS-Security UsernameToken is to be included in the security SOAP header. Essentially, a WS-Security UsernameToken is used to send username/password credentials in the WS-Security SOAP header. The sp:UsernameToken element has the following syntax:

<sp:UsernameToken sp:IncludeToken="xs:anyURI"? xmlns:sp="..." ... >
  (
    <sp:Issuer>wsa:EndpointReferenceType</sp:Issuer> |
    <sp:IssuerName>xs:anyURI</sp:IssuerName>
  ) ?
  <wst:Claims Dialect="..."> ... </wst:Claims> ?
  <wsp:Policy xmlns:wsp="...">
    (
      <sp:NoPassword ... /> |
      <sp:HashPassword ... />
    ) ?
    (
      <sp:RequireDerivedKeys /> |
      <sp:RequireImpliedDerivedKeys ... /> |
      <sp:RequireExplicitDerivedKeys ... />
    ) ?
    (
      <sp:WssUsernameToken10 ... /> |
      <sp:WssUsernameToken11 ... />
    ) ?
    ...
  </wsp:Policy>
  ...
</sp:UsernameToken>

The sub-elements of sp:UsernameToken are all optional and are not needed for ordinary authentication. Normally, the only part of this syntax that is relevant is the sp:IncludeToken attribute.

Note

Currently, in the sp:UsernameToken syntax, only the sp:WssUsernameToken10 sub-element is supported in Apache CXF.

sp:IncludeToken attribute

The value of the sp:IncludeToken must match the WS-SecurityPolicy version from the enclosing policy. The current version is 1.2, but legacy WSDL might use version 1.1. Valid values of the sp:IncludeToken attribute are as follows:

Never

The token MUST NOT be included in any messages sent between the initiator and the recipient; rather, an external reference to the token should be used. Valid URI values are:

Once

The token MUST be included in only one message sent from the initiator to the recipient. References to the token MAY use an internal reference mechanism. Subsequent related messages sent between the recipient and the initiator may refer to the token using an external reference mechanism. Valid URI values are:

AlwaysToRecipient

The token MUST be included in all messages sent from initiator to the recipient. The token MUST NOT be included in messages sent from the recipient to the initiator. Valid URI values are:

AlwaysToInitiator

The token MUST be included in all messages sent from the recipient to the initiator. The token MUST NOT be included in messages sent from the initiator to the recipient. Valid URI values are:

Always

The token MUST be included in all messages sent between the initiator and the recipient. This is the default behavior. Valid URI values are:

SupportingTokens assertions

The following kinds of supporting tokens assertions are supported:

sp:SupportingTokens

This element requires a token (or tokens) of the specified type to be included in the wsse:Security header. No additional requirements are imposed.

Warning

This policy does not explicitly require the tokens to be signed or encrypted. It is normally essential, however, to protect tokens by signing and encryption.

sp:SignedSupportingTokens

This element requires a token (or tokens) of the specified type to be included in the wsse:Security header. In addition, this policy requires that the token is signed, in order to guarantee token integrity.

Warning

This policy does not explicitly require the tokens to be encrypted. It is normally essential, however, to protect tokens both by signing and encryption.

sp:EncryptedSupportingTokens

This element requires a token (or tokens) of the specified type to be included in the wsse:Security header. In addition, this policy requires that the token is encrypted, in order to guarantee token confidentiality.

Warning

This policy does not explicitly require the tokens to be signed. It is normally essential, however, to protect tokens both by signing and encryption.

sp:SignedEncryptedSupportingTokens

This element requires a token (or tokens) of the specified type to be included in the wsse:Security header. In addition, this policy requires that the token is both signed and encrypted, in order to guarantee token integrity and confidentiality.

sp:EndorsingSupportingTokens

An endorsing supporting token is used to sign the message signature (primary signature). This signature is known as an endorsing signature or secondary signature. Hence, by applying an endorsing supporting tokens policy, you can have a chain of signatures: the primary signature, which signs the message itself, and the secondary signature, which signs the primary signature.

Note

If you are using a transport binding (for example, HTTPS), the message signature is not actually part of the SOAP message, so it is not possible to sign the message signature in this case. If you specify this policy with a transport binding, the endorsing token signs the timestamp instead.

Warning

This policy does not explicitly require the tokens to be signed or encrypted. It is normally essential, however, to protect tokens by signing and encryption.

sp:SignedEndorsingSupportingTokens

This policy is the same as the endorsing supporting tokens policy, except that the tokens are required to be signed, in order to guarantee token integrity.

Warning

This policy does not explicitly require the tokens to be encrypted. It is normally essential, however, to protect tokens both by signing and encryption.

sp:EndorsingEncryptedSupportingTokens

This policy is the same as the endorsing supporting tokens policy, except that the tokens are required to be encrypted, in order to guarantee token confidentiality.

Warning

This policy does not explicitly require the tokens to be signed. It is normally essential, however, to protect tokens both by signing and encryption.

sp:SignedEndorsingEncryptedSupportingTokens

This policy is the same as the endorsing supporting tokens policy, except that the tokens are required to be signed and encrypted, in order to guarantee token integrity and confidentiality.

7.3. Providing Client Credentials

Overview

There are essentially two approaches to providing UsernameToken client credentials: you can either set both the username and the password directly in the client’s Blueprint XML configuration; or you can set the username in the client’s configuration and implement a callback handler to provide passwords programmatically. The latter approach (by programming) has the advantage that passwords are easier to hide from view.

Client credentials properties

Table 7.1, “Client Credentials Properties” shows the properties you can use to specify WS-Security username/password credentials on a client’s request context in Blueprint XML.

Table 7.1. Client Credentials Properties

PropertiesDescription

security.username

Specifies the username for UsernameToken policy assertions.

security.password

Specifies the password for UsernameToken policy assertions. If not specified, the password is obtained by calling the callback handler.

security.callback-handler

Specifies the class name of the WSS4J callback handler that retrieves passwords for UsernameToken policy assertions. Note that the callback handler can also handle other kinds of security events.

Configuring client credentials in Blueprint XML

To configure username/password credentials in a client’s request context in Blueprint XML, set the security.username and security.password properties as follows:

<beans ... >
    <jaxws:client name="{NamespaceName}LocalPortName"
                  createdFromAPI="true">
        <jaxws:properties>
            <entry key="security.username" value="Alice"/>
            <entry key="security.password" value="abcd!1234"/>
        </jaxws:properties>
    </jaxws:client>
    ...
</beans>

If you prefer not to store the password directly in Blueprint XML (which might potentially be a security hazard), you can provide passwords using a callback handler instead.

Programming a callback handler for passwords

If you want to use a callback handler to provide passwords for the UsernameToken header, you must first modify the client configuration in Blueprint XML, replacing the security.password setting by a security.callback-handler setting, as follows:

<beans ... >
    <jaxws:client name="{NamespaceName}LocalPortName"
                  createdFromAPI="true">
        <jaxws:properties>
            <entry key="security.username" value="Alice"/>
            <entry key="security.callback-handler" value="interop.client.UTPasswordCallback"/>
        </jaxws:properties>
    </jaxws:client>
    ...
</beans>

In the preceding example, the callback handler is implemented by the UTPasswordCallback class. You can write a callback handler by implementing the javax.security.auth.callback.CallbackHandler interface, as shown in Example 7.2, “Callback Handler for UsernameToken Passwords”.

Example 7.2. Callback Handler for UsernameToken Passwords

package interop.client;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class UTPasswordCallback implements CallbackHandler {

    private Map<String, String> passwords =
        new HashMap<String, String>();

    public UTPasswordCallback() {
        passwords.put("Alice", "ecilA");
        passwords.put("Frank", "invalid-password");
        //for MS clients
        passwords.put("abcd", "dcba");
    }

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];

            String pass = passwords.get(pc.getIdentifier());
            if (pass != null) {
                pc.setPassword(pass);
                return;
            }
        }

        throw new IOException();
    }

    // Add an alias/password pair to the callback mechanism.
    public void setAliasPassword(String alias, String password) {
        passwords.put(alias, password);
    }
}

The callback functionality is implemented by the CallbackHandler.handle() method. In this example, it assumed that the callback objects passed to the handle() method are all of org.apache.ws.security.WSPasswordCallback type (in a more realistic example, you would check the type of the callback objects).

A more realistic implementation of a client callback handler would probably consist of prompting the user to enter their password.

WSPasswordCallback class

When a CallbackHandler is called in a Apache CXF client for the purpose of setting a UsernameToken password, the corresponding WSPasswordCallback object has the USERNAME_TOKEN usage code.

For more details about the WSPasswordCallback class, see org.apache.ws.security.WSPasswordCallback.

The WSPasswordCallback class defines several different usage codes, as follows:

USERNAME_TOKEN

Obtain the password for UsernameToken credentials. This usage code is used both on the client side (to obtain a password to send to the server) and on the server side (to obtain a password in order to compare it with the password received from the client).

On the server side, this code is set in the following cases:

  • Digest password—if the UsernameToken contains a digest password, the callback must return the corresponding password for the given user name (given by WSPasswordCallback.getIdentifier()). Verification of the password (by comparing with the digest password) is done by the WSS4J runtime.
  • Plaintext password—implemented the same way as the digest password case (since Apache CXF 2.4.0).
  • Custom password type—if getHandleCustomPasswordTypes() is true on org.apache.ws.security.WSSConfig, this case is implemented the same way as the digest password case (since Apache CXF 2.4.0). Otherwise, an exception is thrown.

    If no Password element is included in a received UsernameToken on the server side, the callback handler is not called (since Apache CXF 2.4.0).

DECRYPT
Need a password to retrieve a private key from a Java keystore, where WSPasswordCallback.getIdentifier() gives the alias of the keystore entry. WSS4J uses this private key to decrypt the session (symmetric) key.
SIGNATURE
Need a password to retrieve a private key from a Java keystore, where WSPasswordCallback.getIdentifier() gives the alias of the keystore entry. WSS4J uses this private key to produce a signature.
SECRET_KEY
Need a secret key for encryption or signature on the outbound side, or for decryption or verification on the inbound side. The callback handler must set the key using the setKey(byte[]) method.
SECURITY_CONTEXT_TOKEN
Need the key for a wsc:SecurityContextToken, which you provide by calling the setKey(byte[]) method.
CUSTOM_TOKEN
Need a token as a DOM element. For example, this is used for the case of a reference to a SAML Assertion or SecurityContextToken that is not in the message. The callback handler must set the token using the setCustomToken(Element) method.
KEY_NAME
(Obsolete) Since Apache CXF 2.4.0, this usage code is obsolete.
USERNAME_TOKEN_UNKNOWN
(Obsolete) Since Apache CXF 2.4.0, this usage code is obsolete.
UNKNOWN
Not used by WSS4J.

7.4. Authenticating Received Credentials

Overview

On the server side, you can verify that received credentials are authentic by registering a callback handler with the Apache CXF runtime. You can either write your own custom code to perform credentials verification or you can implement a callback handler that integrates with a third-party enterprise security system (for example, an LDAP server).

Configuring a server callback handler in Blueprint XML

To configure a server callback handler that verifies UsernameToken credentials received from clients, set the security.callback-handler property in the server’s Blueprint XML configuration, as follows:

<beans ... >
    <jaxws:endpoint
       id="UserNameOverTransport"
       address="https://localhost:9001/UserNameOverTransport"
       serviceName="interop:PingService10"
       endpointName="interop:UserNameOverTransport_IPingService"
       implementor="interop.server.UserNameOverTransport"
       depends-on="tls-settings">

       <jaxws:properties>
            <entry key="security.username" value="Alice"/>
            <entry key="security.callback-handler" value="interop.client.UTPasswordCallback"/>
        </jaxws:properties>

    </jaxws:endpoint>
    ...
</beans>

In the preceding example, the callback handler is implemented by the UTPasswordCallback class.

Implementing the callback handler to check passwords

To implement a callback handler for checking passwords on the server side, implement the javax.security.auth.callback.CallbackHandler interface. The general approach to implementing the CallbackHandler interface for a server is similar to implementing a CallbackHandler for a client. The interpretation given to the returned password on the server side is different, however: the password from the callback handler is compared against the received client password in order to verify the client’s credentials.

For example, you could use the sample implementation shown in Example 7.2, “Callback Handler for UsernameToken Passwords” to obtain passwords on the server side. On the server side, the WSS4J runtime would compare the password obtained from the callback with the password in the received client credentials. If the two passwords match, the credentials are successfully verified.

A more realistic implementation of a server callback handler would involve writing an integration with a third-party database that is used to store security data (for example, integration with an LDAP server).