Monday, December 7, 2015

Javascript Object Signing and Encryption (JOSE) support in Apache CXF - part III

This is the third article in a series of posts on support for Javascript Object Signing and Encryption (JOSE) in Apache CXF. The previous article described how to encrypt content using the JSON Web Encryption specification. This post covers support for JSON Web Tokens (JWT) in Apache CXF. The JWT spec is not strictly part of the JOSE specification set, but it makes sense to cover it in this series of posts, as it is a natural extension of the JOSE specs to convey claims.

1) Test Cases:

As before, let's start by looking at some practical unit tests on github:
  • cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
These tests mostly follow the same basic format. The web service configuration defines a number of endpoints that map to the same web service implementation (a simple DoubleItService, which allows a user to POST a number and receive the doubled amount, where both the request and response are encoded via JSON). The client test code first constructs a JWT Token and then includes it in the message payload by adding a specific provider. The JWT Token is then processed by a provider on the receiving side. We will cover the individual tests in more detail below.

2) Constructing JWT Tokens

Apache CXF provides an easy to use API to create JWT Tokens. Let's look at how this is done in one of the tests - the JWTAuthenticationTest. The tests construct a JwtClaims Object, which has convenient set/get methods for the standard JWT Claims. For example:


The JwtClaims Object can be passed through to the constructor of a JwtToken Object. To serialize the JwtToken in the request simply add the JwtAuthenticationClientFilter to the client provider list, and specify the JwtToken Object as a message property under "jwt.token". Alternatively, the JwtClaims Object can be passed without having to construct a JwtToken via the property "jwt.claims". On the receiving side, a JWTToken can be processed by the JwtAuthenticationFilter provider.

3) Authentication and Authorization using signed JWT Tokens

By default, the JwtAuthenticationClientFilter signs the JWT Token. The signature configuration is the exact same as that used for JWS as covered in the first article. On the receiving side, the JwtAuthenticationFilter will set up a security context for the authenticated client, assuming that a public key signature algorithm was used to sign the token. The "sub" (Subject) claim from the token gets mapped to the principal of the security context.

As the JWT Token can convey arbitrary claims, it can be used for RBAC authorization. This is demonstrated in the JWTAuthorizationTest. A role called "boss" is inserted into the token. On the receiving side, the JwtAuthenticationFilter is configured to use the "role" claim in the token to extract roles for the authenticated principal and to populate the security context with them. As part of the test-case, CXF's SimpleAuthorizingInterceptor is used to require that a client must have a role of "boss" to invoke on the web service method in question.

4) Encrypting JWT Tokens

It is very easy to encrypt JWT Tokens (as well as both sign and encrypt) them in CXF. The JwtAuthenticationClientFilter needs to be configured to also encrypt the token, and the same configuration is used as for JWE in the previous article. Similarly, on the receiving side the JwtAuthenticationFilter must have the property "jweRequired" set to "true" to decrypt incoming encrypted tokens. See the JWTEncryptedTest test for some examples. 

5) Token validation

On receiving a JAX-RS request containing a JWT token, the
JwtAuthenticationFilter will first parse the token, and then verify the signature (if present) and decrypt the token (if encrypted). It then performs some quality of service validation on the token claims, which I'll detail here. This validation can be easily modified by overriding the protected "validateToken" method in JwtAuthenticationFilter.
  • The "exp" (Expiration Time) claim is validated if present. If the expiry value is before the current date/time, then the token is rejected. 
  • The "nbf" (Not Before) claim is validated if present. If the not before value is after the current date/time, then the token is rejected. 
  • The "iat" (Issued At) claim is validated if present. To validate the "iat" claim, a "ttl" property must be set on the JwtAuthenticationFilter.
  • Either an "iat" or "exp" claim must be present in the token, as otherwise we have no way of enforcing an expiry on a token.
  • A clockskew value can also be configured on the JwtAuthenticationFilter via the "clockOffset" property.
  • The "aud" (Audience) claim is validated. This claim must contain at least one audience value which matches the endpoint address of the recipient.

Wednesday, December 2, 2015

Javascript Object Signing and Encryption (JOSE) support in Apache CXF - part II

This is the second in a series of blog posts on the support for the Javascript Object Signing and Encryption (JOSE) specifications in Apache CXF. The first article covered how to sign content using the JSON Web Signature (JWS) specification. In this post we will look at how to encrypt content using the JSON Web Encryption (JWE) specification.

1) Test Cases:

As before, let's start by looking at some practical unit tests on github:
  • cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
For now let's look at the tests contained in JWETest. These tests mostly follow the same basic format. The web service configuration defines a number of endpoints that map to the same web service implementation (a simple DoubleItService, which allows a user to POST a number and receive the doubled amount, where both the request and response are encoded via JSON). The client test code uses the CXF WebClient API to encrypt the message payload by adding a specific provider. The message in turn is decrypted by a provider on the receiving side. You can run the test via the command line "mvn test -Dtest=JWETest", and the message requests and responses will appear in the console.

2) Compact vs. JSON Serialization

Just like the JWS specification, there are two different ways of serializing JWE structures. Compact serialization is a URL-safe representation that is convenient to use when you only have a single encrypting entity. JSON serialization respresents the JWE structures as JSON objects. As of the time of publishing this post, CXF only has interceptors for the compact approach. However I'm told the JSON serialization case will be supported very soon :-)

The providers to use for the compact case on both the client + receiving sides are:
  • Compact: JweWriterInterceptor (out) + JweContainerRequestFilter (in)
3) Security Configuration

As well as adding the desired providers, it is also necessary to specify the security configuration to set the appropriate algorithms, keys, etc. to use. The CXF wiki has an extensive list of all of the different security configuration properties. For encryption, we need to first load the encrypting key (either a JKS keystore or else a JSON Web Key (JWK) is supported).

As well as defining the encryption key, we also need to configure the algorithms to encrypt the content as well as to encrypt the key. The list of acceptable encryption algorithms for JWE is defined by the JSON Web Algorithms (JWA) spec. For content encryption, the supported algorithms are all based on AES (CBC/GCM mode) with different key sizes. For key encryption, various schemes based on RSA, AES KeyWrap/GCM, Elliptic Curve Diffie-Hellman, PBES2 are supported, as well as a symmetric encryption option.

For example, the tests use the following configuration to load a public key from a Java KeyStore, and to use the RSA-OAEP key encryption algorithm, as well as a 128-bit AES content encryption algorithm in CBC mode, using HMAC-SHA256 to generate the authentication code:
The service side configuration is largely the same, apart from the fact that we need to specify the "rs.security.key.password" configuration tag to load the private key. The encryption algorithms must also be specified to impose a constraint on the desired algorithms.

4) Encrypting XML payload

Similar to the signature case, it is possible to use JWE to encrypt an XML message, and not just a JSON message. An example is included in JWETest ("testEncryptingXMLPayload").  The configuration is exactly the same as for the JSON case. 

5) Including the encrypting key

It is possible to include the encrypting certificate/key in the JWE header by setting one of the following properties:
  • rs.security.encryption.include.public.key - Include the JWK public key for encryption in the "jwk" header.
  • rs.security.encryption.include.cert - Include the X.509 certificate for encryption in the "x5c" header.
  • rs.security.encryption.include.key.id - Include the JWK key id for encryption in the "kid" header.
  • rs.security.encryption.include.cert.sha1 - Include the X.509 certificate SHA-1 digest for encryption in the "x5t" header.
It could be useful to include the encrypting certificate/key if the recipient has multiple decryption keys and doesn't know which one to use to decrypt the request.

6) Signing + encrypting a message

It is possible to both sign and encrypt a message by combining the JWS + JWE interceptors. For example, simply adding the JweWriterInterceptor and JwsWriterInterceptor providers on the client side will both sign and encrypt the request. An example is included in the github project above (JWEJWSTest). 

Monday, November 30, 2015

Javascript Object Signing and Encryption (JOSE) support in Apache CXF - part I

The Javascript Object Signing and Encryption (JOSE) specifications cover how to sign and encrypt data using JSON. Apache CXF has excellent support for all of the JOSE specifications (see the documentation here), thanks largely to the work done by my colleague Sergey Beryozkin. This is the first in a series of blog posts describing how to use and implement JOSE for your web services using Apache CXF. In this post, we will cover how to sign content using the JSON Web Signature (JWS) specification.

1) Test Cases:

Let's start by looking at some practical unit tests on github:
  • cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
For now let's look at the JWSSignatureTest. These tests mostly follow the same basic format. The web service configuration defines a number of endpoints that map to the same web service implementation (a simple DoubleItService, which allows a user to POST a number and receive the doubled amount, where both the request and response are encoded via JSON). The client test code uses the CXF WebClient API to sign the message payload by adding a specific provider. The message in turn is validated by a provider on the receiving side. You can run the test via the command line "mvn test -Dtest=JWSSignatureTest", and the message requests and responses will appear in the console.

For example, here is the output of the "testSignatureCompact" request. The Payload consists of the concatenated (+ separated by a '.') BASE-64 URL encoded JWS header (e.g. containing the signature algorithm, amongst other values), the BASE-64 URL encoded message payload, and the BASE-64 URL encoded signature value.


2) Compact vs. JSON Serialization

The JWS specification defines two different ways of serializing the signatures. Compact serialization is a URL-safe representation that is convenient to use when you only have a single signing entity. JSON serialization resprents the JWS structures as JSON objects, and allows multiple signatures to be included in the request as a result. The JWSSignatureTest includes both examples ("testSignatureListProperties" and "testSignatureCompact"). It's very easy to experiment with both approaches, as you only have to use different providers on both the client + receiving sides:
  • JSON Serialization: JwsJsonWriterInterceptor (out) + JwsJsonContainerRequestFilter (in)
  • Compact: JwsWriterInterceptor (out) + JwsContainerRequestFilter (in)
3) Security Configuration

As well as adding the desired providers, it is also necessary to specify the security configuration to set the appropriate algorithms, keys, etc. to use. The CXF wiki has an extensive list of all of the different security configuration properties. For signature, we need to first load the signing key (either a JKS keystore or else a JSON Web Key (JWK) is supported).

As well as defining a signing key, we also need to configure the signing algorithm. The list of acceptable signing algorithms for JWS is defined by the JSON Web Algorithms (JWA) spec. For signature, this boils down to a public key signature scheme based on either RSA or EC-DSA, or a symmetric scheme using HMAC.

For example, the tests use the following configuration to load a private key from a Java KeyStore, and to use the signature scheme of RSASSA-PKCS1-v1_5 using SHA-256:
The service side configuration is largely the same, apart from the fact that we don't need to specify the "rs.security.key.password" configuration tag, as we don't need to load the private key. The signature algorithm must be specified to impose a constraint on the acceptable signature algorithm.

4) Signing XML payload

The JWS payload (the content to be signed) can be any binary content and not just a JSON Object. This means that we can use JWS to sign an XML message. This is a really cool feature of the specification in my opinion, as it essentially removes the need to use XML Signature to sign XML payload. An example of this is included in the JWSSignatureTest. The configuration is exactly the same as for the JSON case.

5) Including the signing key

It is possible to include the signing certificate/key in the JWS header by setting one of the following properties:
  • rs.security.signature.include.public.key -  Include the JWK public key for signature in the "jwk" header.
  • rs.security.signature.include.cert - Include the X.509 certificate for signature in the "x5c" header.
  • rs.security.signature.include.key.id - Include the JWK key id for signature in the "kid" header.
  • rs.security.signature.include.cert.sha1- Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.
One advantage of including the entire certificate is that the service doesn't need to store the client certificate locally, but only the issuing certificate.

Monday, November 16, 2015

New security advisory for Apache CXF

A new security advisory has been released for Apache CXF, which is fixed in the 3.1.3, 3.0.7 and 2.7.18 releases.
  • CVE-2015-5253: Apache CXF SAML SSO processing is vulnerable to a wrapping attack
Apache CXF supports the SAML SSO protocol with JAX-RS web service endpoints. It is possible for a malicious user to construct a SAML Response (the response from the SAML SSO IdP to the endpoint) via a so-called "wrapping attack", to allow that user to log in instead of the authenticated user associated with the signed SAML Assertion.

Please see the Apache CXF security advisories page for more information.

Wednesday, November 11, 2015

Testing Kerberos with Web Services using Apache Kerby

The previous blog post described how to use Apache Directory to easily create a KDC via Java annotations for kerberos integration testing. In this post, we will look at an alternative way of setting up a KDC for integration testing using Apache Kerby.

Apache Kerby is a new subproject of Apache Directory that aims to provide a complete Kerberos solution in Java. Version 1.0.0-RC1 has recently been released and is available for testing. Apache Kerby consists of both a KDC as well as a client API, that is completely independent of the GSS API that comes with Java. A key selling point of Apache Kerby is that it is very easy and fast to setup and deploy a KDC. It is possible to set up a KDC completely in code, without having to edit any configuration files or configure any system properties.

Let's see how this is done by looking at a project I created on github:
  • cxf-kerberos-kerby: This project contains a number of tests that show how to use Kerberos with Apache CXF, where the KDC used in the tests is based on Apache Kerby.
The KDC is launched in the test-code, and is pretty much as straightfoward as the following code snippet:

The first block of code configures the host, realm, transports and ports, while the second creates the client, service and TGT principals that are used in the tests. No configuration files required! As well as showing how to use Apache CXF to authenticate using both Kerberos and Spnego for a JAX-WS service, the AuthenticationTest also includes unit tests for getting a service ticket from the Kerby KDC using the Java GSS API as well as the Kerby client API. Using the Kerby client API is as simple as this:


Have fun playing around with Apache Kerby and please join and contribute to the project if you are interested!

Monday, October 26, 2015

Testing Kerberos with Web Services using Apache Directory

Apache CXF supports Kerberos for web services both via the Kerberos Token Profile of WS-Security, where the kerberos ticket is conveyed as a BinarySecurityToken in the security header of the client request, and over HTTP via the Negotiate authentication scheme. If you are developing kerberos-enabled web services using a framework like Apache CXF, a natural question to ask is how to set up a Kerberos KDC to test your web services prior to deployment. This is the first of two blog posts that shows two different ways to easily set up a KDC using open source projects for kerberos integration testing.

At ApacheCon EU 2014 in Budapest, I attended a great talk by Emmanuel Lécharny entitled "Testing LDAP Implementations". The talk covered how the Apache Directory project can be used to easily deploy Kerberos and LDAP servers in your test-code via annotations. This was music to my ears, as I had written a bunch of tests in Apache CXF for both LDAP and kerberos that were not run as part of the normal build, as they required a local KDC to run successfully. After this talk I got involved in the Apache Directory project, and converted the tests in Apache CXF to use Apache Directory instead, so they could be run as part of the normal build cycle. I also made some small improvements which I'll describe as part of this post.

I've created a project in github that shows how to use Apache Directory to set up a KDC, and how to use Apache CXF to authenticate to a web service using Kerberos, for both JAX-RS and JAX-WS:
  • cxf-kerberos: This project contains a number of tests that show how to use Kerberos with Apache CXF.
Both test-cases use an annotation to load a kerberos.ldif file, containing the information required to set up Kerberos principals in the KDC for testing:


 Another annotation sets up the Directory Service:

Finally, an annotation adds a KDC server:

The "KRB" protocol was added as part of DIRSERVER-2031 in the 2.0.0-M20 release. Previously, you could specify either "TCP" or "UDP" for the protocol attribute when testing Kerberos. However, this meant that they could not share the same port. The "KRB" protocol generates both TCP and UDP transports on the port provided, or otherwise on a random port. Previously, the random port generation was not working, as it always defaulted to 1024. Random port generation is an essential feature for testing as part of a build cycle, as hard-coded ports tend to cause problems on continuous integration platforms. Using a random port also means that the krb5.conf file used by the CXF clients must be read in, and the random port substituted into the file before writing it out again, as otherwise the clients would have no way of knowing the port the KDC was running on.

Friday, October 23, 2015

A certificate revocation security vulnerability in Java

A few days ago, Oracle released a Critical Patch Update containing fixes for various security vulnerabilities. In particular, the update contained fixes for 25 security vulnerabilities in Java itself. One of them, CVE-2015-4868, was discovered by me and duly disclosed to Oracle earlier this year. This issue has now been fixed in this Critical Patch Update (and included in Java 1.8.0_65), and so I am free to describe it.

1) Background

I first noticed this issue in the context of signature validation of SOAP web service requests. A signed SOAP request involves using XML Signature to sign some part of the request, where the resulting Signature structure is inserted into the security header of the request. The Signature contains a KeyInfo Element, which references the (public) key to use to validate the request. The recipient must resolve the appropriate public key, establish trust in it, and use it to validate the signature.

A common use-case is when the certificate used to validate the signature is included directly in the request, by BASE-64 encoding it in the security header. Optionally, the full certificate chain can be included instead. The recipient must take the certificates and establish a trust chain using a CA certificate stored in a local truststore, which is then validated.

However, what if the signing certificate has been revoked by the issuing CA? In this case, we can specify a Certificate Revocation List, and include it as part of the validation of the trust chain.

2) The vulnerability

Now to the vulnerability. Under the more usual use-case of just including the signing certificate in the security header, and establishing a trust-chain using a local truststore and CRL file, everything was working fine. Namely, if the signing certificate was trusted, but revoked, then the CertPath validation failed. However, if the issuing certificate of the signing certificate was also included in the security header, then CRL validation was not failing! This vulnerability exists in a range of JDK 8 versions prior to 1.8.0_65. It does not exist prior to JDK 8.

To see how this works using the Java CertPathValidator API, I created a simple maven-based unit test in github:
  • java.crls - A testcase that show how to include a CRL when validating the certificate path of a certificate.
The test has a JUnit failure assertion that asserts that the CertPathValidator validation should fail (as the signing certificate has been revoked). However, this failure assertion is not met when run locally with Java 1.8.0_51. With a Java version post-1.8.0_65 the failure assertion is met, and the test passes.

Friday, September 18, 2015

Support for Jetty 9 in Apache CXF Fediz 1.3.0

Yesterday I gave a tutorial on how to deploy the Apache CXF Fediz simpleWebapp example to Jetty 8 using Fediz 1.2.1. Apache CXF Fediz 1.3.0 will ship with a new plugin to support Jetty 9. In this post I will cover how to deploy the simpleWebapp example to Jetty 9 using this new plugin.

1) Deploying the 1.2.0 Fediz IdP in Apache Tomcat

As per the previous tutorial on deploying to Tomcat, we will deploy the IdP and STS in Apache Tomcat. Download Fediz and extract it to a new directory (${fediz.home}). To deploy the IdP to Tomcat:

  • Copy ${fediz.home}/idp/war/* to ${catalina.home}/webapps
  • Download and copy the hsqldb jar (e.g. hsqldb-1.8.0.10.jar) to ${catalina.home}/lib
  • Copy idp-ssl-key.jks and idp-ssl-trust.jks from ${fediz.home}/examples/samplekeys to ${catalina.home}.
  • Edit ${catalina.home}/conf/server.xml and change the ports from 8080 -> 9080 + 8443 -> 9443 so as not to conflict with Jetty.
  • Edit the TLS Connector in ${catalina.home}/conf/server.xml' as well, e.g.: <Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="want" sslProtocol="TLS" keystoreFile="idp-ssl-key.jks" keystorePass="tompass" keyPass="tompass" truststoreFile="idp-ssl-trust.jks" truststorePass="ispass" />
Now start Tomcat, and check that the IdP is live by opening the STS WSDL in a web browser: 'https://localhost:9443/fediz-idp-sts/REALMA/STSServiceTransport?wsdl'

2) Deploying the simpleWebapp in Jetty 9

Download Jetty 9 and extract it to a new directory (${jetty.home}). First let's set up TLS:
  • Copy ${fediz.home}/examples/samplekeys/rp-ssl-key.jks to ${jetty.home}/etc
  • Copy ${fediz.home}/examples/samplekeys/ststrust.jks to ${jetty.home} *and* to ${jetty.home}/etc
  • Edit ${jetty.home}/start.ini to include the ssl, https and fediz modules, and set up the TLS configuration as follows:
  •  The "fediz" module referred to above must be placed in ${jetty.home}/modules/fediz.mod with content:
Now we will deploy the simpleWebapp:
  • Copy ${fediz.home}/examples/simpleWebapp/src/main/config/fediz_config.xml to ${jetty.home}/etc
  • Do a "mvn clean install" in ${fediz.home}/examples/simpleWebapp
  • Copy ${fediz.home}/examples/simpleWebapp/target/fedizhelloworld.war to ${jetty.home}/webapps
  • Create a new directory: ${jetty.home}/lib/fediz
  • Copy ${fediz.home}/plugins/jetty9/lib/* to ${jetty.home}/lib/fediz (note you may want to copy in a slf4j logging binding in here to see logging output, e.g. slf4j-jdk14-1.7.12.jar).
  • Create a new file in ${jetty.home}/webapps called "fedizhelloworld.xml" with content as follows, and then start Jetty as normal: 

3) 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.

Thursday, September 17, 2015

Deploying the Apache CXF Fediz simpleWebapp to Jetty

On previous tutorials about Apache CXF Fediz, I have always described deploying the simpleWebapp example that ships with Fediz in Apache Tomcat. However, Fediz also supports deploying secured applications in Jetty (7 and 8 as of yet, support for Jetty 9 is forthcoming). As it can be somewhat confusing setting up the security requirements correctly, I will cover briefly how to deploy the simpleWebapp in Jetty 8 in this blog post (see the Fediz wiki for a dedicated page on deploying to Jetty).

1) Deploying the 1.2.0 Fediz IdP in Apache Tomcat

As per the previous tutorial on deploying to Tomcat, we will deploy the IdP and STS in Apache Tomcat. Download Fediz 1.2.1 and extract it to a new directory (${fediz.home}). To deploy the IdP to Tomcat:
  • Copy ${fediz.home}/idp/war/* to ${catalina.home}/webapps
  • Download and copy the hsqldb jar (e.g. hsqldb-1.8.0.10.jar) to ${catalina.home}/lib
  • Copy idp-ssl-key.jks and idp-ssl-trust.jks from ${fediz.home}/examples/samplekeys to ${catalina.home}.
  • Edit ${catalina.home}/conf/server.xml and change the ports from 8080 -> 9080 + 8443 -> 9443 so as not to conflict with Jetty.
  • Edit the TLS Connector in ${catalina.home}/conf/server.xml' as well, e.g.: <Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="want" sslProtocol="TLS" keystoreFile="idp-ssl-key.jks" keystorePass="tompass" keyPass="tompass" truststoreFile="idp-ssl-trust.jks" truststorePass="ispass" />
Now start Tomcat, and check that the IdP is live by opening the STS WSDL in a web browser: 'https://localhost:9443/fediz-idp-sts/REALMA/STSServiceTransport?wsdl'

2) Deploying the simpleWebapp in Jetty 8

Download Jetty 8 and extract it to a new directory (${jetty.home}). First let's set up TLS:
  • Copy ${fediz.home}/examples/samplekeys/rp-ssl-key.jks to ${jetty.home}/etc
  • Copy ${fediz.home}/examples/samplekeys/ststrust.jks to ${jetty.home} *and* to ${jetty.home}/etc
  • Edit ${jetty.home}/start.ini and make sure that 'etc/jetty-ssl.xml' is included.
  • Edit ${jetty.home}/etc/jetty-ssl.xml and configure the TLS keys, e.g.:


Now we will deploy the simpleWebapp:
  • Copy ${fediz.home}/examples/simpleWebapp/src/main/config/fediz_config.xml to ${jetty.home}/etc
  • Do a "mvn clean install" in ${fediz.home}/examples/simpleWebapp
  • Copy ${fediz.home}/examples/simpleWebapp/target/fedizhelloworld.war to ${jetty.home}/webapps
  • Create a new directory: ${jetty.home}/lib/fediz
  • Copy ${fediz.home}/plugins/jetty/lib/* to ${jetty.home}/lib/fediz (note you may want to copy in a slf4j logging binding in here to see logging output, e.g. slf4j-jdk14-1.7.12.jar).
  • Edit ${jetty.home}/start.ini and add "fediz" to "OPTIONS".
  • Create a new file in ${jetty.home}/contexts called "fedizhelloworld.xml" with content as follows, and then start Jetty as normal:

3) 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.

Tuesday, September 8, 2015

Authorization for web services using XACML 3.0

In a blog post last year, I covered some authentication and authorization test-cases for Apache CXF-based web services that I uploaded to github. In particular, the cxf-sts-xacml demo showed how a CXF service can use XACML to authorize a web service request, by sending a XACML request to a Policy Decision Point (PDP) and then by enforcing the authorization decision. This demo only covered XACML 2.0 (provided by OpenSAML). In this post we will give an example of how to use XACML 3.0 via Apache OpenAz to make and enforce authorization requests for Apache CXF based services.

1) Introducing Apache OpenAz

The XACML functionality in Apache CXF is based on OpenSAML, which provides support for XACML 2.0. However, XACML 3.0 is an OASIS standard as of January, 2013. A new project in the Apache Incubator called Apache OpenAz addresses this gap. The source code is broken down into the following modules:
  • openaz-xacml - API + common functionality.
  • openaz-xacml-rest - Some common functionality used by the RESTful API interfaces
  • openaz-xacml-pdp - A PDP implementation
  • openaz-xacml-pdp-rest - An implementation of the XACML 3.0 RESTful Interface for the PDP
  • openaz-xacml-pap-rest - An implementation of the XACML 3.0 RESTful Interface for the PAP
  • openaz-xacml-test - Some testsuites
  • openax-pep -  The PEP (Policy Enforcement Point) implementation.
2) Integrating Apache OpenAz with Apache CXF

The testcases are available here:
  • cxf-sts-xacml: This project contains a number of tests that show how to use XACML with CXF to authorize a client request. It contains both XACML 2.0 tests and XACML 3.0 tests.
In both cases, the client obtains a SAML Token from the STS with the roles of the client embedded in the token. The service provider extracts the roles, and creates a XACML request. For the XACML 2.0 case, OpenSAML is used to create a XML XACML 2.0 request. This is then sent to a mocked PDP JAX-RS service. However, let's focus on the XACML 3.0 case. In this test, the OpenAz API (via the openaz-xacml module as covered above) is used to create a JSON XACML 3.0 request. This is evaluated by a OpenAz-based PDP which is co-located with the service. After evaluating the request, the PDP response is then enforced at the service side.

The service endpoint is configured in Spring as follows, registering a XACML3AuthorizingInterceptor (which in turn contains a reference to the co-located PDP):

The XACML3AuthorizingInterceptor is configured with a implementation to create a XACML 3.0 request using the SAML 2.0 profile of XACML 3.0, which is subsequently converted into JSON + sent to the PDP. The PDP is configured with "root" and "reference" policies, that state that a user of role "boss" has permission to "execute" the Web Service Operation "{http://www.example.org/contract/DoubleIt}DoubleItService#DoubleIt". For example:
A sample authorization request looks like:
If you are interested in XACML 3.0 please get involved with the Apache OpenAz project! Once the project gets more mature, the PEP code in my project will probably make it over to Apache CXF so that users have the option of supporting XACML 2.0 or 3.0 (and XML or JSON) with their web services.

Thursday, August 27, 2015

Apache CXF Fediz 1.2.1 and 1.1.3 released

Apache CXF Fediz 1.2.1 and 1.1.3 have been released. Both releases contain updates to the underlying CXF dependency, as well as a number of minor bug-fixes and improvements. However the most important enhancement is a fix for a recent security advisory:
  • CVE-2015-5175: Apache CXF Fediz application plugins are vulnerable to Denial of Service (DoS) attacks
Apache CXF Fediz is a subproject of Apache CXF which implements the WS-Federation Passive Requestor Profile for SSO specification. It provides a number of container based plugins to enable SSO for Relying Party applications. These plugins are potentially vulnerable to DoS attacks due to the fact that support for Document Type Declarations (DTDs) is not disabled when parsing the response from the Identity Provider (IdP).

Tuesday, August 25, 2015

Apache CXF Fediz 1.2.0 tutorial - part VII

This is the seventh and final blog post on a series of new features introduced in Apache CXF Fediz 1.2.0. The previous post looked at the new REST API of the IdP. Up to now, we have only covered the basic scenario where the application and the IdP are in the same realm. However, a more sophisticated example is when the application is in a different realm. In this case, the IdP must redirect the user to the home IdP of the application for authentication. The IdP has supported this functionality up to now using WS-Federation only. However, the 1.2.0 IdP supports the ability to redirect to a SAML SSO IdP, thus acting as an identity broker between the two protocols. We will cover this functionality in this tutorial.

1) Setup simpleWebapp + SAML SSO IdP

As with previous tutorials, please follow the first tutorial to deploy the Fediz IdP + STS to Apache Tomcat, as well as the "simpleWebapp. However, this time the "simpleWebapp" is going to be deployed in a different realm. Edit 'conf/fediz_config.xml' and add the following under the "protocol" section:
  • <homeRealm type="String">urn:org:apache:cxf:fediz:idp:realm-B</homeRealm>
This tells the IdP that the application is to be authenticated in "realm-B".

The next thing we are going to do is to set up a SAML SSO IdP which will authenticate users who want to access "simpleWebapp". In this tutorial we will just use a mocked SAML SSO IdP in the Fediz system tests for convenience. Build the war as in the following steps + deploy to Tomcat:
2) Configure the Fediz IdP

Next we need to take a look at configuring the Fediz IdP so that it knows where to find the SAML SSO IdP associated with "realm B" and how to communicate with it. Edit 'webapps/fediz-idp/WEB-INF/classes/entities-realma.xml':

In the 'idp-realmA' bean:
  • Change the port in "idpUrl" to "8443". 
In the 'trusted-idp-realmB' bean:
  • Change the "url" value to "https://localhost:8443/samlssoidp/samlsso".
  • Change the "protocol" value to "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".
  • Add the following: <property name="parameters"><util:map><entry key="support.deflate.encoding" value="true" /></util:map></property>
The "parameters" map above is a way to provide SAML SSO specific configuration options to the Fediz IdP. The following options can be configured:
  • sign.request - Whether to sign the request or not. The default is "true".
  • require.keyinfo - Whether to require a KeyInfo or not when processing a (signed) Response. The default is "true".
  • require.signed.assertions - Whether the assertions contained in the Response must be signed or not. The default is "true".
  • require.known.issuer - Whether we have to "know" the issuer of the SAML Response or not. The default is "true".
  • support.base64.encoding - Whether we BASE-64 decode the response or not. The default is "true".
  • support.deflate.encoding - Whether we support Deflate encoding or not. The default is "false".
Redeploy the Fediz IdP + navigate to the following URL in a browser:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
You will see that the Fediz IdP will redirect the browser to the mocked SAML SSO IdP for authentication (authenticate with "ALICE/ECILA") and then back to the Fediz IdP and eventually back to the client application.


Wednesday, August 19, 2015

Apache CXF Fediz 1.2.0 tutorial - part VI

This is the sixth in a series of posts on the new features of Apache CXF Fediz 1.2.0. The previous post looked at Single Sign Out support in Fediz. In this article we will briefly cover the new REST API of the Fediz IdP. Prior to the 1.2.0 release all of the IdP configuration was done in a static way using Spring. If the IdP administrator wished to change the claims for a particular application, then the change would necessitate restarting the IdP. In contrast, the Fediz 1.2.0 IdP persists the configuration to a database using JPA. In addition, it allows access to this configuration via a REST API powered by Apache CXF.

To get started, please follow step 1 of the first tutorial to deploy the Fediz IdP to Apache Tomcat. The REST API is described by a WADL document available at the following URL:
  • https://localhost:8443/fediz-idp/services/rs?_wadl
The WADL document describes the following resource URIs:
  • services/rs/idps - An IdP for a given realm. 
  • services/rs/claims - The claims that are available in the IdP.
  • services/rs/applications - The applications that are defined in the IdP.
  • services/rs/trusted-idps - The trusted IdPs that are defined in the IdP.
  • services/rs/roles - The roles associated with the REST API.
By using the standard HTTP verbs in the usual way you can retrieve, store, modify and remove items from the IdP configuration. For example, to see (GET) the configuration associated with the IdP for "realm A" navigate to the following URL in a browser:
  • https://localhost:8443/fediz-idp/services/rs/idps/urn:org:apache:cxf:fediz:idp:realm-A
The user credentials are defined in "webapps/fediz-idp/WEB-INF/classes/users.properties". You can use "admin/password" by default to access the API. Here you can see the protocols supported, the token types offered, the different ways of authenticating to the IdP, the claim types offered, the applications supported, etc. Note that by default the information returned in a GET request is in XML format. You can return it in JSON format just by appending ".json" to the URL:
For much more information on how to use the new REST API, please see Oliver Wulff's blog on this topic.

Friday, August 7, 2015

Apache CXF Fediz 1.2.0 tutorial - part V

This is the fifth in a series of posts on the new features available in Apache CXF Fediz 1.2.0. The previous article described a new container-independent Relying Party (RP) plugin available in Fediz 1.2.0 based on Apache CXF. In this post we will take a look at two new features, support for Single Sign Out and the ability to publish metadata for both RP plugins and the IdP.

1) Single Sign Out support in Fediz

An important new feature in Fediz 1.2.0 is the ability to perform Single Sign Out both at the RP and IdP. The user can log out at either the RP or IdP by adding "?wa=wsignout1.0" to the relevant URL. Alternatively, two new configuration options are added for the RP:
  • logoutURL - The logout URL to trigger federated logout
  • logoutRedirectTo - URL landing-page after successful logout.
To see how this works in practice, follow the first tutorial to set up the hello world demo in Tomcat, and log on via:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
After successful authentication, you will see a basic webpage detailing the User principal, roles, and the underlying SAML Assertion. Now what if you want to log out from the application? From Fediz 1.2.0 it's simple. Navigate to the following URL:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet?wa=wsignout1.0
The browser will be redirected to the logout page for the IdP:

Click "Logout" and you see a page confirming that Logout was successful (in both the RP + IdP). To confirm this, navigate again to the application URL, and you will see that you are redirected back to the IdP for authentication. The user can also logout directly at the IdP by navigating to:
  • https://localhost:8443/fediz-idp/federation?wa=wsignout1.0
2) Metadata Support in Fediz

It has been possible since Fediz 1.0.0 to publish the Metadata document associated with a Relying Party using the Tomcat plugin. This Metadata document is built dynamically using the Fediz configuration values and is published at the standard URL. Here is a screenshot of a request using the "fedizhelloworld" demo:

This document describes the endpoint address of the service, the realm of the service, and the claims (both required and optional). The metadata document can also be signed by specifying a "signingKey" in the Fediz configuration.

So what's new in Fediz 1.2.0? The first thing is that it was only possible previously to publish the metadata document when using the Tomcat plugin. In Fediz 1.2.0, this has been extended to cover the other plugins, i.e. Jetty, Spring, etc. In addition, the forthcoming Fediz 1.2.1 release adds support for Metadata to the IdP. The Metadata is available at the same standard URL as for the RP, e.g.:

This signed document describes the URL of the STS, as well as that of the IdP itself, and the claims that are offered by the IdP.

Friday, July 17, 2015

(Slightly) Faster WS-Security using MTOM in Apache CXF 3.1.2

A recent issue was reported at Apache CXF to do with the inability to process certain WS-Security requests that were generated by Metro or .NET when MTOM was enabled. In this case, Metro and .NET avoid BASE-64 encoding bytes and inserting them directly into the message (e.g. for BinarySecurityTokens or the CipherValue data associated with EncryptedData or EncryptedKey Elements). Instead the raw bytes are stored in a message attachment, and referred to in the message via xop:Include. Support for processing these types of requests has been added for WSS4J 2.0.5 and 2.1.2.

In addition, CXF 3.1.2 now has the ability to avoid the BASE-64 encoding step when creating requests when MTOM is enabled, something that we will look at in this post. The advantage of this is that is marginally more efficient due to avoiding BASE-64 encoding at the sending side, and BASE-64 decoding on the receiving side.

1) Storing message bytes in attachments in WSS4J

A new WSS4J configuration property has been added in WSS4J 2.0.5/2.1.2 to support storing message bytes in attachments. This property is used when configuring WS-Security via the "action" based approach in CXF:
  • storeBytesInAttachment: Whether to store bytes (CipherData or BinarySecurityToken) in an attachment. The default is false, meaning that bytes are BASE-64 encoded and "inlined" in the message.
WSS4J is stack-neutral, meaning that it has no concept of what a message attachment actually is. So for this to work, a CallbackHandler must be set on the RequestData Object, that knows how to retrieve attachments, as well as write modified/new attachments out. If you are using Apache CXF then this is taken care for you automatically.

There is another configuration property that is of interest on the receiving side:
  • expandXOPIncludeForSignature: Whether to expand xop:Include Elements encountered when verifying a Signature. The default is true, meaning that the relevant attachment bytes are BASE-64 encoded and inserted into the Element. This ensures that the actual bytes are signed, and not just the reference.
So for example, if an encrypted SOAP Body is signed, the default behaviour is to expand the xop:Include Element to make sure that we are verifying the signature on the SOAP Body. On the sending side, we must have a signature action *before* an encryption action, for this same reason. If we encrypt before signing, then WSS4J will turn off the "storeBytesInAttachment" property, to make sure that we are not signing a reference.

2) Storing message bytes in attachments with WS-SecurityPolicy

A new security configuration property is also available in Apache CXF to control the ability to store message bytes in attachments with WS-Security when WS-SecurityPolicy is used:
  • ws-security.store.bytes.in.attachment: Whether to store bytes (CipherData or BinarySecurityToken) in an attachment. The default is true if MTOM is enabled.
This property is also available in CXF 3.0.6, but is it is "false" by default. Similar to the action case, CXF will turn off this property by default in either of the following policy cases:
  • If sp:EncryptBeforeSigning is present
  • If sp:ProtectTokens is present. In this case, the signing cert is itself signed, and again we want to avoid signing a reference rather than the certificate bytes.
3) Tests

To see this new functionality in action, take a look at the MTOMSecurityTest in CXF's ws-security systests module. It has three methods that test storing bytes in attachments with a symmetric binding, asymmetric binding + an "action based" approach to configuring WS-Security. Enable logging to see the requests and responses. The encrypted SOAP Body now contains a CipherValue that does not include the BASE-64 encoded bytes any more:

The referenced attachment looks like:


Finally, I wrote a blog post some time back about using Apache JMeter to load-test security-enabled CXF-based web services. I decided to modify the standard symmetric and asymmetric tests, so that the CXF service was MTOM enabled, so that the ability to store message bytes in the attachments was switched on with CXF 3.1.2. The results for both test-cases showed that throughput was around 1% higher when message bytes were stored in attachments. Bear in mind that the change just measures the service creation change, the client request was still non-MTOM aware as it is just pasted into JMeter. So one would expect up to a 4% improvement for a fully MTOM-aware client + service invocation:


Thursday, July 16, 2015

Apache CXF Fediz 1.2.0 tutorial - part IV

This is the fourth in a series of blog posts on the new features and changes in Apache CXF Fediz 1.2.0. The last two articles focused on how clients can authenticate to the IdP in Fediz 1.2.0 using Kerberos and TLS client authentication. In this post we will divert our attention from the IdP for the time being, and look at a new container-independent Relying Party (RP) plugin available in Fediz 1.2.0 based on Apache CXF.

1) RP plugins in Fediz

Apache Fediz ships with a number of RP plugins to secure your web application. These plugins are container-dependent, meaning that if your web app is deployed in say Apache Tomcat, you need to use the Tomcat plugin in Fediz. The following plugins were available prior to Fediz 1.2.0:
The CXF plugin referred to here was not a full WS-Federation RP plugin as in the other modules. Instead, it consisted of a mechanism that allows the SSO (SAML) token retrieved as part of the WS-Federation process to be used by CXF client code, if the web application needed to obtain another token "on behalf of" the other token when making some subsequent web services call.

2) CXF RP plugin in Fediz 1.2.0

In Fediz 1.2.0, the CXF plugin mentioned above now contains a fully fledged WS-Federation RP implementation that can be used to secure a JAX-RS service, rather than using one of the container dependent plugins. Lets see how this works using a test-case:
  • 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.
The test-case consists of two modules. The first is a web application which contains a simple JAX-RS service, which has a single GET method to return a doubled number. The method is secured with a @RolesAllowed annotation, meaning that only a user in roles "User", "Admin", or "Manager" can access the service.

This is enforced via CXF's SecureAnnotationsInterceptor. Finally WS-Federation is enabled for the service via the JAX-RS Provider called the FedizRedirectBindingFilter, available in the CXF plugin in Fediz. This takes a "configFile" parameter, which is a link to the standard Fediz plugin configuration file:


It's as easy as this to secure your CXF JAX-RS service using WS-Federation! The remaining module in the test above deploys the IdP + STS from Fediz in Apache Tomcat. It then takes the "double-it" war above and also deployed it in Tomcat.

Finally, it uses Htmlunit to make an invocation on the service, and checks that access is granted to the service. Alternatively, you can comment the @Ignore annotation of the "testInBrowser" method, and copy the printed out URL into a browser to test the service directly (user credentials: "alice/ecila").

Wednesday, July 15, 2015

Apache CXF Fediz 1.2.0 tutorial - part III

This is the third in a series of blog posts on the new features and changes in Apache CXF Fediz 1.2.0. The previous blog entry described how different client authentication mechanisms are supported in the IdP, and how to configure client authentication via an X.509 certificate, a new feature in Fediz 1.2.0. Another new authentication mechanism in Fediz 1.2.0 is the ability to authenticate to the IdP using Kerberos, which we will cover in this article.

1) Kerberos client authentication in the IdP

Recall that the Apache Fediz IdP in 1.2.0 supports different client authentication methods by default using different URL paths. In particular for Kerberos, the URL path is:
  • /federation/krb -> authentication using Kerberos
The default value for the "wauth" parameter added by the service provider to the request to activate this URL path is:
  • http://docs.oasis-open.org/wsfed/authorization/200706/authntypes/SslAndKey
When the IdP receives a request at the URL path configured for Kerberos, it sends back a request for a Negotiate Authorization header if none is present. Otherwise it parses the header and BASE-64 decodes the Kerberos token and dispatches it to the configured authentication provider. Kerberos tokens are authenticated in the IdP via the STSKrbAuthenticationProvider, which is configured in the Spring security-config.xml

2) Authenticating Kerberos tokens in the IdP

The IdP supports two different ways of validating Kerberos tokens:
  • Passthrough Authentication. Here we do not authenticate the Kerberos token at all in the IdP, but pass it through to the STS for authentication. This is similar to what is done for the Username/Password authentication case. The default security binding of the STS for this scenario requires a KerberosToken Supporting Token. This is the default way of authenticating Kerberos tokens in the IdP.
  • Delegation. If delegation is enabled in the IdP, then the received token is validated locally in the IdP. The delegated credential is then used to get a new Kerberos Token to authenticate the STS call "on behalf of" the original user. 
To enable the delegation scenario, simply update the STSKrbAuthenticationProvider bean in the security-config.xml,
set the "requireDelegation" property to "true", and configure the kerberosTokenValidator property to validate the received Kerberos token:

Friday, July 10, 2015

Securing Apache CXF with Apache Camel

The previous post I wrote about how to integrate Apache CXF with Apache Camel. The basic test scenario involved using an Apache CXF proxy service to authenticate clients, and Apache Camel to route the authenticated requests to a backend service, which had different security requirements to the proxy. In this post, we will look at a slightly different scenario, where the duty of authenticating the clients shifts from the proxy service to Apache Camel itself. In addition, we will look at how to authorize the clients via different Apache Camel components.

For a full description of the test scenario see the previous post. The Apache CXF based proxy service receives a WS-Security UsernameToken, which is used to authenticate the client. In the previous scenario, this was done at the proxy by supplying a CallbackHandler instance to verify the given username and password. However, this time we will just configure the proxy to pass the received credentials through to the route instead of authenticating them. This can be done by setting the JAX-WS property "ws-security.validate.token" to "false":

So now it is up to the Camel route to authenticate and authorize the user credentials. Here are two possibilities using Apache Shiro and Spring Security.

1) Apache Shiro

I've covered previously how to use Apache Shiro to authenticate and authorize web service invocations using Apache CXF. Apache Camel ships with a camel-shiro component which allows you to authenticate and authorize Camel routes. The test-case can be downloaded and run here:
  • camel-cxf-proxy-shiro-demo: Some authentication and authorization tests for an Apache CXF proxy service using the Apache Camel Shiro component.
Username, passwords and roles are stored in a file and parsed in a ShiroSecurityPolicy object:

The Camel route is as follows:


Note that the shiroHeaderProcessor bean processes the result from the proxy before applying the Shiro policy. This processor retrieves the client credentials (which are stored as a JAAS Subject in a header on the exchange) and extracts the username and password, storing them in special headers that are used by the Shiro component in Camel to get the username and password for authentication. 

The authorization use-case uses the same route, however the ShiroSecurityPolicy bean enforces that the user must have a role of "boss" to invoke on the backend service:


2) Spring Security 

I've also covered previously how to use Spring Security to authenticate and authorize web service invocations using Apache CXF. Apache Camel ships with a camel-spring-security component which allows you to authenticate and authorize Camel routes. The test-case can be downloaded and run here:
Like the Shiro test-case, username, passwords and roles are stored in a file, which is used to create an authorizationPolicy bean:
The Camel route is exactly the same as in the Shiro example above, except that a different processor implementation is used. The SpringSecurityHeaderProcessor bean used in the tests translates the user credentials into a Spring Security UsernamePasswordAuthenticationToken principal, which is added to the JAAS Subject stored under the Exchange.AUTHENTICATION header. This principal is then used by the Spring Security component to authenticate the request.

To authorize the request, a different authorizationPolicy configuration is required:


Monday, July 6, 2015

Integrating Apache CXF with Apache Camel

Apache Camel provides support for integrating Apache CXF endpoints via the camel-cxf component. A common example of the benefits of using Apache Camel with webservices is when a proxy service is required to translate some client request into a format that is capable of being processed by some backend service. Apache Camel ships with an example where a backend service consumes SOAP over JMS, and a proxy service translates a SOAP over HTTP client request into SOAP over JMS. In this post, we will show an example of how to use this proxy pattern to secure a client invocation to a backend service via a proxy, when the backend service and proxy have different security requirements.

The test scenario is as follows. The backend service is an Apache CXF-based JAX-WS "double-it" service that can only be called by trusted clients. However, we don't want to give the backend service the responsibility to authenticate clients. A CXF-based proxy service will be responsible for authenticating clients, and then routing the authenticated requests to the backend service via Apache Camel. The backend service is secured via TLS with client authentication, meaning that we have direct trust between the proxy service and the backend service. Clients must authenticate to the proxy service via a WS-Security UsernameToken over TLS.

The test-case can be downloaded and run here:
 The CXF proxy is configured as follows:

The CallbackHandler supplies the password to authenticate client passwords. The Camel route is defined as:

The headerFilterStrategy reference is to a CxfHeaderFilterStrategy bean which instructs Camel to drop the message headers (we don't need the security header beyond the proxy, as the proxy is responsible for authenticating the client). Messages are routed to the "doubleItService", which is defined as follows:


Thursday, July 2, 2015

Using SSH/SCP/SFTP with Apache Camel

Apache Camel contains a number of components to make it easy to work with SSH/SCP/SFTP. I've created a new camel-ssh testcase in github to illustrate how to use these various components, continuing on from previous posts describing the security capabilities of Apache Camel:
  • SSHTest: This test-case shows how to use the Apache Camel SSH component. The test fires up an Apache MINA SSHD server, which has been configured to allow authenticated users to execute arbitrary commands (ok not very safe...). Some files that contain unix commands are read in via a Camel route, executed using the SSH component, and the results are stored in target/ssh_results.
  • SCPTest: This test-case shows how to use the Apache Camel JSCH component (which supports SCP using JSCH). An Apache MINA SSHD server is configured that allows SCP. Some XML files are read in via a Camel route, and copied using SCP to a target directory on the server (which maps to target/storage for the purposes of this test).
  • SFTPTest: This test-case shows how to use the Apache Camel FTP component. An Apache MINA SSHD server is configured that allows SFTP. Some XML files are read in via a Camel route, and copied using SFTP to a target directory on the server (target/storage_sftp).

Tuesday, June 30, 2015

An STS JAAS LoginModule for Apache CXF

Last year I blogged about how to use JAAS with Apache CXF, and the different LoginModules that were available. Recently, I wrote another article about using a JDBC LoginModule with CXF. This article will cover a relatively new JAAS LoginModule  added to CXF for the 3.0.3 release. It allows a service to dispatch a Username and Password to a STS (Security Token Service) instance for authentication via the WS-Trust protocol, and also to retrieve the user's roles by extracting them from a SAML token returned by the STS.

1) The STS JAAS LoginModule

The new STS JAAS LoginModule is available in the CXF WS-Security runtime module. It takes a Username and Password from the Callbackhandler passed to the LoginModule, and uses them to create a WS-Security UsernameToken structure. What happens then depends on a configuration setting in the LoginModule.

If the "require.roles" property is set, then the UsernameToken is added to a WS-Trust "Issue" request to the STS, and a "TokenType" attribute is sent in the request (defaults to the standard "SAML2" URI, but can be configured). The client also adds a WS-Trust "Claim" to the request that tells the STS to add the role of the authenticated end user to the request. How the token is added to the WS-Trust request depends on whether the "disable.on.behalf.of" property is set or not. By default, the token is added as an "OnBehalfOf" token in the WS-Trust request. However, if "disable.on.behalf.of" is set to "true", then the credentials are used according to the WS-SecurityPolicy of the STS endpoint. For example, if the policy requires a UsernameToken, then the credentials are added to the security header of the WS-Trust request. If the "require.roles" property is not set, the the UsernameToken is added to a WS-Trust "Validate" request.

The STS validates the received UsernameToken credentials supplied by the end user, and then either creates a token (if the Issue binding was used), or just returns a simple response telling the client whether the validation was successful or not. In the former use-case, the token that is returned is cached meaning that the end user does not have to re-authenticate until the token expires from the cache.

The LoginModule has the following configuration properties:
  • require.roles - If this is defined, then the WS-Trust Issue binding is used, passing the value specified for the "token.type" property as the TokenType, and the "key.type" property for the KeyType. It also adds a Claim to the request for the default "role" URI.
  • disable.on.behalf.of - Whether to disable passing Username + Password credentials via "OnBehalfOf".
  • disable.caching - Whether to disable caching of validated credentials. Default is "false". Only applies when "require.roles" is defined.
  • wsdl.location - The location of the WSDL of the STS
  • service.name - The service QName of the STS
  • endpoint.name - The endpoint QName of the STS
  • key.size - The key size to use (if requesting a SymmetricKey KeyType). Defaults to 256.
  • key.type - The KeyType to use. Defaults to the standard "Bearer" URI.
  • token.type - The TokenType to use. Defaults to the standard "SAML2" URI.
  • ws.trust.namespace - The WS-Trust namespace to use. Defaults to the standard WS-Trust 1.3 namespace.
In addition, any of the standard CXF security configuration tags that start with "ws-security." can be used as documented here. Sometimes it is necessary to set some security configuration depending on the security policy of the WSDL.

Here is an example of the new JAAS LoginModule configuration:



2) A testcase for the new LoginModule

Using an STS via WS-Trust for authentication and authorization can be quite difficult to set up and understand, but the new LoginModule makes it easy. I created a testcase + uploaded it to github:
  • cxf-jaxrs-jaas-sts: This project demonstrates how to use the new STS JAAS LoginModule in CXF to authenticate and authorize a user. It contains a "double-it" module which contains a "double-it" JAX-RS service. It is secured with JAAS at the container level, and requires a role of "boss" to access the service. The "sts" module contains a Apache CXF STS web application which can authenticate users and issue SAML tokens with embedded roles.
To run the test, download Apache Tomcat and do "mvn clean install" in the testcase above. Then copy both wars and the jaas configuration file to the Apache Tomcat install (${catalina.home}):
  • cp double-it/target/cxf-double-it.war ${catalina.home}/webapps
  • cp sts/target/cxf-sts.war ${catalina.home}/webapps
  • cp double-it/src/main/resources/jaas.conf ${catalina.home}/conf
Next set the following system property:
  • export JAVA_OPTS=-Djava.security.auth.login.config=${catalina.home}/conf/jaas.conf
Finally, start Tomcat, open a web browser and navigate to:

http://localhost:8080/cxf-double-it/doubleit/services/100

Use credentials "alice/security" when prompted. The STS JAAS LoginModule takes the username and password, and dispatches them to the STS for validation.