Tuesday, October 14, 2014

Using JAAS with Apache CXF

Apache CXF supports a wide range of tokens for authentication (SAML, UsernameTokens, Kerberos, etc.), and also offers different ways of authenticating these tokens. A standard way of authenticating a received token is to use a JAAS LoginModule. This article will cover some of the different ways you can configure JAAS in CXF, and some of the JAAS LoginModules that are available.

1) Configuring JAAS in Apache CXF

There are a number of different ways to configure your CXF web service to authenticate tokens via JAAS. For all approaches, you must define the System property "java.security.auth.login.config" to point towards your JAAS configuration file.

1.1) JAASLoginInterceptor

CXF provides a interceptor called the JAASLoginInterceptor that can be added either to the "inInterceptor" chain of an endpoint (JAX-WS or JAX-RS) or a CXF bus (so that it applies to all endpoints). The JAASLoginInterceptor typically authenticates a Username/Password credential (such as a WS-Security UsernameToken or HTTP/BA) via JAAS. Note that for WS-Security, you must tell WSS4J not to authenticate the UsernameToken itself, but just to process it and store it for later authentication via the JAASLoginInterceptor. This is done by setting the JAX-WS property "ws-security.validate.token" to "false".

At a minimum it is necessary to set the "contextName" attribute of the JAASLoginInterceptor, which references the JAAS Context Name to use. It is also possible to define how to retrieve roles as part of the authentication process, by default CXF assumes that javax.security.acl.Group Objects are interpreted as "role" Principals. See the CXF wiki for more information on how to configure the JAASLoginInterceptor. After successful authentication, a CXF SecurityContext Object is created with the name and roles of the authenticated principal.

1.2) JAASAuthenticationFeature

Newer versions of CXF also have a CXF Feature called the JAASAuthenticationFeature. This simply wraps the JAASLoginInterceptor with default configuration for Apache Karaf. If you are deploying a CXF endpoint in Karaf, you can just add this Feature to your endpoint or Bus without any additional information, and CXF will authenticate the received credential to whatever Login Modules have been configured for the "karaf" realm in Apache Karaf.

1.3) JAASUsernameTokenValidator

As stated above, it is possible to validate a WS-Security UsernameToken in CXF via the JAASLoginInterceptor or the JAASAuthenticationFeature by first setting the JAX-WS property "ws-security.validate.token" to "false". This tells WSS4J to avoid validating UsernameTokens. However it is possible to also validate UsernameTokens using JAAS directly in WSS4J via the JAASUsernameTokenValidator. You can configure this validator when using WS-SecurityPolicy via the JAX-WS property "ws-security.ut.validator".

2) Using JAAS LoginModules in Apache CXF

Once you have decided how you are going to configure JAAS in Apache CXF, it is time to pick a JAAS LoginModule that is appropriate for your authentication requirements. Here are some examples of LoginModules you can use.

2.1) Validating a Username + Password to LDAP / Active Directory

For validating a Username + Password to an LDAP / Active Directory backend, use one of the following login modules:
  • com.sun.security.auth.module.LdapLoginModule: Example here (context name "sun").
  • org.eclipse.jetty.plus.jaas.spi.LdapLoginModule: Example here (context name "jetty"). Available via the org.eclipse.jetty/jetty-plus dependency. This login module is useful as it's easy to retrieve roles associated with the authenticated user.
2.2) Validating a Kerberos token

Kerberos tokens can be validated via:
  • com.sun.security.auth.module.Krb5LoginModule: Example here.
2.3) Apache Karaf specific LoginModules

Apache Karaf contains some LoginModules that can be used when deploying your application in Karaf:
  • org.apache.karaf.jaas.modules.properties.PropertiesLoginModule: Authenticates Username + Passwords and retrieves roles via "etc/users.properties".
  • org.apache.karaf.jaas.modules.properties.PublickeyLoginModule: Authenticates SSH keys and retrieves roles via "etc/keys.properties".
  • org.apache.karaf.jaas.modules.properties.OsgiConfigLoginModule: Authenticates Username + Passwords and retrieves roles via the OSGi Config Admin service.
  • org.apache.karaf.jaas.modules.properties.LDAPLoginModule: Authenticates Username + Passwords and retrieves roles from an LDAP backend.
  • org.apache.karaf.jaas.modules.properties.JDBCLoginModule:  Authenticates Username + Passwords and retrieves roles from a database.
  • org.apache.karaf.jaas.modules.properties.SyncopeLoginModule: Authenticates Username + Passwords and retrieves roles via the Apache Syncope IdM.
See Jean-Baptiste Onofré's excellent blog for a description of how to set up and test the SyncopeLoginModule. Note that it is also possible to use this LoginModule in other containers, see here for an example.

Thursday, October 9, 2014

New Apache WSS4J releases

Apache WSS4J 1.6.17 and 2.0.2 have been released. WSS4J 2.0.2 picks up some bug fixes via Apache Santuario and BouncyCastle dependency upgrades, in particular the latter upgrade fixes some Kerberos issues. Both releases contain some changes to how SAML tokens are processed that will be described in a forthcoming blog post.

I also added a new Security Advisories page to the WSS4J website. For the moment it just contains some links and information on downstream security advisories that might be relevant to users of WSS4J.

Wednesday, October 8, 2014

Some recent WS-Trust client topics in Apache CXF

There are a number of minor new features and changes in recent versions of Apache CXF with respect to the client side of WS-Trust, which will be documented in this post.

1) STSClient configuration

CXF's STSClient is responsible for communicating with a Security Token Service (STS) via the WS-Trust protocol, in order to issue/validate/renew/etc. a security token. To support WS-Trust on the client side in CXF, it is necessary to construct an STSClient instance, and then reference it via the JAX-WS property key "ws-security.sts.client". Here is a typical example in spring.

However, there are some alternatives to configuring an STSClient per JAX-WS client object (see the CXF documentation for additional information). Strictly speaking these alternatives have been available in previous versions of CXF, however some bugs were fixed in the latest releases to enable them to work properly:

a) If no STSClient is directly configured on the JAX-WS client, then the CXF runtime will look for an STSClient bean with a name that corresponds to the Endpoint name with the suffix ".sts-client". Here is an example:

<bean id="stsClient" class="org.apache.cxf.ws.security.trust.STSClient"
    name="{http://www.example.org/contract/DoubleIt}DoubleItTransportSAML1Port.sts-client"
    abstract="true"
>

b) If no STSClient is configured either directly on the client, or else via the approach given in (a) above, then the security runtime tries to fall back to a "default" client. All that is required here is that the name of the STSClient bean should be "default.sts-client". Here is an example:

<bean id="stsClient" class="org.apache.cxf.ws.security.trust.STSClient"
    name="default.sts-client"
    abstract="true"
>

2) Falling back to Issue after a failed Renew

When a cached SecurityToken is expired, the STSClient tries to renew the token. However, not all STS instances support the renewal binding of WS-Trust. Therefore a new configuration parameter was introduced:
  • SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW ("ws-security.issue.after.failed.renew") -  Whether to fall back to calling "issue" after failing to renew an expired token. The default is "true".
 3) Renewing security tokens that are "about to" expire

There is a potential issue when a cached security token is "about to" expire. The CXF client will retrieve the cached token + check to see whether the token is expired or not. If it is expired, then it renews the token. If the token is valid, then it uses it in the service request. However, if the security token expires "en route" to the service, then the service will reject the token, and the service invocation will fail.

In CXF 2.7.13 and 3.0.2, support has been added to forcibly renew tokens that are about to expire, rather than risk letting them expire en route. A new configuration parameter has been introduced:
  • SecurityConstants.STS_TOKEN_IMMINENT_EXPIRY_VALUE ("ws-security.sts.token.imminent-expiry-value") - The value in seconds within which a token is considered to be expired by the client, i.e. it is considered to be expired if it will expire in a time less than the value specified by this tag.
The default value for this parameter for CXF 3.0.2 is "10", meaning that if a security token will expire in less than 10 seconds, it will be renewed by the client. For CXF 2.7.13, the default value is "0" for backwards compatibility reasons, meaning that this functionality is disabled.

Tuesday, October 7, 2014

Apache CXF Authentication and Authorization test-cases III

This is the third in a series of posts on authentication and authorization test-cases for web services using Apache CXF. The first post focused on authenticating and authorizing web service requests that included a username and password (WS-Security UsernameToken and HTTP/BA). The second article looked at more sophisticated ways of performing authentication and authorization, such as using X.509 certificates, using a SecurityTokenService (STS), using XACML and using Kerberos. This article will build on the previous articles to show how to perform Single Sign On (SSO) with Apache CXF.

The projects are as follows:
  • cxf-shiro: This project uses Apache Shiro for authenticating and authorizating a UsernameToken, as covered in the first article. However, it also now includes an SSOTest, which shows how to use WS-SecureConversation for SSO. In this scenario an STS is co-located with the endpoint. The client sends the UsernameToken to the STS for authentication using Apache Shiro. The STS returns a token and a secret key to the client. The client then makes the service request including the token and using the secret key to sign a portion of the request, thus proving proof-of-possession. The client can then make repeated invocations without having to re-authenticate the UsernameToken credentials.
  • cxf-sts:  This project shows how to use the CXF SecurityTokenService (STS) for authentication and authorization, as covered in the second article. It now includes an SSOTest to show how to achieve SSO with the STS. It demonstrates how the client caches the token after the initial invocation, and how it can make repeated invocations without having to re-authenticate itself to the STS.
  • cxf-saml-sso: This project shows how to leverage SAML SSO with Apache CXF to achieve SSO for a JAX-RS service. CXF supports the POST + redirect bindings of SAML SSO for JAX-RS endpoints. As part of this demo, a mock CXF-based IdP is provided which authenticates a client using HTTP/BA and issues a SAML token using the CXF STS. Authorization is also demonstrated using roles embedded in the issued SAML token. 
  • cxf-fediz-federation-sso: This project shows how to use the new CXF plugin of Apache Fediz 1.2.0 to authenticate and authorize clients of a JAX-RS service using WS-Federation. This feature will be documented more extensively at a future date, and is considered experimental for now. Please play around with it and provide feedback to the CXF users list.

Thursday, September 25, 2014

Apache Santuario - XML Security for Java 2.0.2 release

Apache Santuario - XML Security for Java 2.0.2 has been released. This is a minor release that fixes a couple of bugs with the streaming code and contains a few dependency upgrades.

Thursday, July 3, 2014

New Apache Santuario releases

Two new versions of the Apache Santuario - XML Security for Java project have been released. Version 2.0.1 (release notes) adds support for a number of previously unsupported algorithms, such as RSA with SHA-224, the RIPE-MD160 digest algorithm, and the RSASSA-PSS signature scheme. It also fixes a performance regression when evaluating signatures, a UTF-8 encoding issue with certain characters, an issue with using GCM algorithms with JDK 8, and a race condition in the streaming decryption code. Version 1.5.7 (release notes) contains the UTF-8, GCM and signature performance fixes, along with a number of other minor changes.

Friday, June 20, 2014

Apache CXF Fediz 1.1.1 released

Apache CXF Fediz 1.1.1 and 1.0.4 have been released. Fediz is a subproject of Apache CXF which implements the WS-Federation Passive Requestor Profile. It allows you to secure web applications using Single Sign-On (SSO) and Claims Based Access Control (CBAC), by redirecting users to an IdP (Identity Provider) for authentication, which in turn leverages the CXF STS (SecurityTokenService). Plugins are provided for the most popular web application containers, such as Apache Tomcat, Jetty, Spring, etc.

The 1.0.4 release  upgrades the underlying CXF dependency from 2.6.6 to 2.6.14, and the 1.1.1 release upgrades CXF from 2.7.7 to 2.7.11, thus picking up important bug fixes. Fediz 1.0.4 adds support for the wauth + whr parameters, while Fediz 1.1.1 adds support for wreq (see section 1.d below) and the older WS-Policy namespace, along with a few other bug fixes. See the Fediz JIRA for more information.

1) Fediz example

In a previous post introducing Apache CXF Fediz I gave instructions about how to deploy one of the Fediz 1.0.x examples to Apache Tomcat. In this section, I will update the deployment instructions for Fediz 1.1.1, as the examples have changed slightly since 1.0.x. In addition, I will give a simple example about how to use the new support for the "wreq" parameter added in Fediz 1.1.1 as part of FEDIZ-84 to request a SAML 1.1 token from the IdP.

Download the latest Apache CXF Fediz release (currently 1.1.1) here, and extract it to a new directory (${fediz.home}). It ships with two examples, 'simpleWebapp' and 'wsclientWebapp'. We will cover the former as part of this tutorial. We will use a Apache Tomcat 7 container to host both the Idp/STS and service application - this is not recommended, but is an easy way to get the example to work. Please see the associated README.txt of the simpleWebapp example for more information about how to deploy the example properly. Most of the deployment information in this section is based on the Fediz Tomcat documentation, which I recommend reading for a more in-depth treatment of deploying Fediz to Tomcat.

a) Deploying the IdP/STS

To deploy the Idp/STS to Tomcat:
  • Create a new directory: ${catalina.home}/lib/fediz
  • Edit ${catalina.home}/conf/catalina.properties and append ',${catalina.home}/lib/fediz/*.jar' to the 'common.loader' property.
  • Copy ${fediz.home}/plugins/tomcat/lib/* to ${catalina.home}/lib/fediz
  • Copy ${fediz.home}/idp/war/* to ${catalina.home}/webapps
Now we need to set up TLS:
  • Copy ${fediz.home}/examples/samplekeys/idp-ssl-server.jks to ${catalina.home}.
  • Edit the TLS Connector in ${catalina.home}/conf/server.xml', e.g.: <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" keystoreFile="idp-ssl-server.jks" keystorePass="tompass" clientAuth="false" sslProtocol="TLS" URIEncoding="UTF-8"  />
Now start Tomcat, and check that the STS is live by opening the STS WSDL in a web browser: 'https://localhost:8443/fediz-idp-sts/REALMA/STSServiceTransport?wsdl'

b) Deploying the service

To deploy the service to Tomcat:
  • Copy ${fediz.home}/examples/samplekeys/rp-ssl-server.jks and ${fediz.home}/examples/samplekeys/ststrust.jks to ${catalina.home}.
  • Copy ${fediz.home}/examples/simpleWebapp/src/main/config/fediz_config.xml to ${catalina.home}/conf/
  • Edit ${catalina.home}/conf/fediz_config.xml and replace '9443' with '8443'.
  • Do a "mvn clean install" in ${fediz.home}/examples/simpleWebapp
  • Copy ${fediz.home}/examples/simpleWebapp/target/fedizhelloworld.war to ${catalina.home}/webapps.
c) Testing the service

To test the service navigate to:
  • https://localhost:8443/fedizhelloworld/  (this is not secured) 
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
With the latter URL, the browser is redirected to the IDP (select realm "A") and is prompted for a username and password. Enter "alice/ecila" or "bob/bob" or "ted/det" to test the various roles that are associated with these username/password pairs.

Finally, you can see the metadata of the service via the standard URL:
  • https://localhost:8443/fedizhelloworld/FederationMetadata/2007-06/FederationMetadata.xml 
d) Obtaining a SAML 1.1 token via wreq

Let's assume that the Service Provider can only handle SAML 1.1 tokens. Fediz 1.1.1 supports this by allowing the service provider to configure a "request" parameter to send a WS-Trust RequestSecurityToken Element to the IdP containing a desired TokenType. To update the example above to obtain a SAML 1.1 token instead of a SAML 2.0 token do the following:
  • Update ${catalina.home}/conf/fediz_config.xml + add the following to the "protocol" section: <request type="String">&lt;RequestSecurityToken xmlns=&quot;http://docs.oasis-open.org/ws-sx/ws-trust/200512&quot;&gt;&lt;TokenType&gt;http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1&lt;/TokenType&gt;&lt;/RequestSecurityToken&gt;</request>
Now simply follow the same steps as before in accessing 'fedizhelloworld/secure/fedservlet' in a browser. You will see that the Bootstrap token that appears on the final screen is now a SAML 1.1 token.