Monday, February 1, 2016

An interop demo between Apache CXF Fediz and Keycloak

Last week, I showed how to use the Apache CXF Fediz IdP as an identity broker with a real-world SAML SSO IdP based on the Shibboleth IdP (as opposed to an earlier article which used a mocked SAML SSO IdP). In this post, I will give similar instructions to configure the Fediz IdP to act as an identity broker with Keycloak.

1) Install and configure Keycloak

Download and install the latest Keycloak distribution (tested with 1.8.0). Start keycloak in standalone mode by running 'sh bin/standalone.sh'.

1.1) Create users in Keycloak

First we need to create an admin user by navigating to the following URL, and entering a password:
  • http://localhost:8080/auth/
Click on the "Administration Console" link, logging on using the admin user credentials. You will see the configuration details of the "Master" realm. For the purposes of this demo, we will create a new realm. Hover the mouse pointer over "Master" in the top left-hand corner, and click on "Add realm". Create a new realm called "realmb". Now we will create a new user in this realm. Click on "Users" and select "Add User", specifying "alice" as the username. Click "save" and then go to the "Credentials" tab for "alice", and specify a password, unselecting the "Temporary" checkbox, and reset the password.

1.2) Create a new client application in Keycloak

Now we will create a new client application for the Fediz IdP in Keycloak. Select "Clients" in the left-hand menu, and click on "Create". Specify the following values:
  • Client ID: urn:org:apache:cxf:fediz:idp:realm-A
  • Client protocol: saml
  • Client SAML Endpoint: https://localhost:8443/fediz-idp/federation
Once the client is created you will see more configuration options:
  • Select "Sign Assertions"
  • Select "Force Name ID Format".
  • Valid Redirect URIs: https://localhost:8443/*
Now go to the "SAML Keys" tab of the newly created client. Here we will have to import the certificate of the Fediz IdP so that Keycloak can validate the signed SAML requests. Click "Import" and specify:
  • Archive Format: JKS
  • Key Alias: realma
  • Store password: storepass
  • Import file: stsrealm_a.jks
1.3) Export the Keycloak signing certificate

Finally, we need to export the Keycloak signing certificate so that the Fediz IdP can validate the signed SAML Response from Keycloak. Select "Realm Settings" (for "realmb") and click on the "Keys" tab. Copy and save the value specified in the "Certificate" textfield.

2) Install and configure the Apache CXF Fediz IdP and sample Webapp

Follow a previous tutorial to deploy the latest Fediz IdP + STS to Apache Tomcat, as well as the "simpleWebapp". Test that the "simpleWebapp" is working correctly by navigating to the following URL (selecting "realm A" at the IdP, and authenticating as "alice/ecila"):
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
2.1) Configure the Fediz IdP to communicate with Keycloak

Now we will configure the Fediz IdP to authenticate the user in "realm B" by using the SAML SSO protocol. 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 "http://localhost:8080/auth/realms/realmb/protocol/saml".
  • Change the "protocol" value to "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".
  • Change the "certificate" value to "keycloak.cert".
2.2) Configure Fediz to use the Keycloak signing certificate

Copy 'webapps/fediz-idp/WEB-INF/classes/realmb.cert' to a new file called 'webapps/fediz-idp/WEB-INF/classes/keycloak.cert'. Edit this file + delete the content between the "-----BEGIN CERTIFICATE----- / -----END CERTIFICATE-----" tags, pasting instead the Keycloak signing certificate as retrieved in step "1.3" above.

The STS also needs to trust the Keycloak signing certificate. Copy keycloak.cert into 'webapps/fediz-idp-sts/WEB-INF/classes". In this directory import the keycloak.cert into the STS truststore via:
  • keytool -keystore ststrust.jks -import -file keycloak.cert -storepass storepass -alias keycloak
Restart Fediz to pick up the changes (you may need to remove the persistent storage first).

3) Testing the service

To test the service navigate to:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
Select "realm B". You should be redirected to the Keycloak authentication page. Enter the user credentials you have created. You will be redirected to Fediz, where it converts the received SAML token to a token in the realm of Fediz (realm A) and redirects to the web application.


Tuesday, January 26, 2016

An interop demo between Apache CXF Fediz and Shibboleth

Apache CXF Fediz is an open source implementation of the WS-Federation Passive Requestor Profile for SSO. It allows you to configure SSO for your web application via a container plugin, which redirects the user to authenticate at an IdP (Fediz or another WS-Federation based IdP). The Fediz IdP also supports the ability to act as an identity broker to a remote IdP, if the user is to be authenticated in a different realm. Last year, this blog covered a new feature of Apache CXF Fediz 1.2.0, which was the ability to act as an identity broker with a remote SAML SSO IdP. In this post, we will look at extending the demo to work with the Shibboleth IdP.

1) Install and configure the Apache CXF Fediz IdP and sample Webapp

Firstly, follow a previous tutorial to deploy the latest Fediz IdP + STS to Apache Tomcat, as well as the "simpleWebapp". Test that the "simpleWebapp" is working correctly by navigating to the following URL (selecting "realm A" at the IdP, and authenticating as "alice/ecila"):
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
Now we will configure the Fediz IdP to authenticate the user in "realm B", by using the SAML SSO protocol with a Shibboleth IdP instance. 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 "http://localhost:9080/idp/profile/SAML2/Redirect/SSO".
  • Change the "protocol" value to "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".
  • Add the following property: <property name="parameters"><util:map><entry key="require.known.issuer" value="false" /></util:map></property>
Restart Fediz to pick up the changes (you may need to remove the persistent storage first).

2) Install and configure Shibboleth

This is a reasonable complex task, so let's break it down into various sections.

2.1) Install Shibboleth and deploy to Tomcat

Download and extract the latest Shibboleth Identity Provider (tested with 3.2.1). Install Shibboleth by running the "install.sh" script in the bin directory. Install Shibboleth to "$SHIB_HOME" and use the default values that are prompted as part of the installation process, entering a random password for the keystore (we won't be using it). Download and extract an Apache Tomcat 7 instance, and follow these steps:
  • Copy '$SHIB_HOME/war/idp.war' into the Tomcat webapps directory.
  • Configure Shibboleth to find the IDP by defining: export JAVA_OPTS="-Xmx512M -Didp.home=$SHIB_HOME".
  • Next you need to download the jstl jar (https://repo1.maven.org/maven2/jstl/jstl/1.2/) + put it in the lib directory of Tomcat.
  • Edit conf/server.xml + change the ports to avoid conflict with the Tomcat instance that the Fediz IdP is running in. (e.g. use 9080 instead of 8080, etc.).
  • Now start Tomcat + check that everything is working by navigating to: http://localhost:9080/idp/profile/status
2.2) Configure the RP provider in Shibboleth

Next we need to configure the Fediz IdP as a RP (relying party) in Shibboleth. The Fediz IdP has the ability to generate metadata (either WS-Federation or SAML SSO) for a trusted IdP. Navigate to the following URL in a browser and save the metadata to a local file "fediz-metadata.xml":
  • https://localhost:8443/fediz-idp/metadata/urn:org:apache:cxf:fediz:idp:realm-B
Edit '$SHIB_HOME/conf/metadata-providers.xml' and add the following configuration to pick up this metadata file:

<MetadataProvider id="FedizMetadata"  xsi:type="FilesystemMetadataProvider" metadataFile="$METADATA_PATH/fediz-metadata.xml"/>

As we won't be encrypting the SAML response in this demo, edit the '$SHIB_HOME/idp.properties' file and uncomment the "idp.encryption.optional = false" line, changing "false" to "true".

2.3) Configuring the Signing Keys in Shibboleth

Next we need to copy the keys that Fediz has defined for "realm B" to Shibboleth. Copy the signing certificate "realmb.cert" from the Fediz source and rename it as '$SHIB_HOME/credentials/idp-sigining.crt'. Next we need to extract the private key from the keystore and save it as a plaintext private key. Download the realmb keystore. Extract the private key via:
  • keytool -importkeystore -srckeystore stsrealm_b.jks -destkeystore stsrealmb.p12 -deststoretype PKCS12 -srcalias realmb -deststorepass storepass -srcstorepass storepass -srckeypass realmb -destkeypass realmb
  • openssl pkcs12 -in stsrealmb.p12  -nodes -nocerts -out idp-signing.key
  • Edit idp-signing.key to remove any additional information before the "BEGIN PRIVATE KEY" part.
  • cp idp-signing.key $SHIB_HOME/credentials
2.4) Configure Shibboleth to authenticate users

Next we need to configure Shibboleth to authenticate users. If you have a configured KDC or LDAP installation on your machine, then it is easiest to use this, if you configure some test users there. If not then, in this section we will configure Shibboleth to use JAAS to authenticate users via Kerberos. Edit '$SHIB_HOME/conf/authn/password-authn-config.xml' + comment out the ldap import, instead uncommenting the "jaas-authn-config.xml" import. Next edit '$SHIB_HOME/conf/authn/jaas.config' and replace the contents with:

 ShibUserPassAuth {
    com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useKeyTab=false;
};

Now we will set up and configure a test KDC. Assuming you are running this demo on linux, edit '/etc/krb5.conf' and change the "default_realm" to "service.ws.apache.org" + add the following to the realms section:

        service.ws.apache.org = {
                kdc = localhost:12345
        }

Now we will look at altering a test-case I wrote that uses Apache Kerby as a test-kdc. Clone my testcases github repo and go to the "cxf-kerberos-kerby" test-case, which is part of the top level "cxf" projects. Edit the AuthenticationTest
and change the values for KDC_PORT + KDC_UDP_PORT to "12345". Next remove the @org.junit.Ignore annotation from the "launchKDCTest()" method to just launch the KDC + sleep for a few minutes. Launch the test on the command line via "mvn test -Dtest=AuthenticationTest".

2.5) Configure Shibboleth to include the authenticated principal in the SAML Subject

For the purposes of our demo scenario, the Fediz IdP expects the authenticated principal in the SAML Subject it gets back from Shibboleth. Edit '$SHIB_HOME/conf/attribute-filter.xml' and add the following:

    <AttributeFilterPolicy id="releasePersistentIdToAnyone">
        <PolicyRequirementRule xsi:type="ANY"/>

        <AttributeRule attributeID="persistentId">
            <PermitValueRule xsi:type="ANY"/>
        </AttributeRule>
    </AttributeFilterPolicy>

Edit '$SHIB_HOME/conf/attribute-resolver.xml' and add the following:

<resolver:AttributeDefinition id="persistentId" xsi:type="ad:PrincipalName">
      <resolver:AttributeEncoder xsi:type="enc:SAML1StringNameIdentifier" nameFormat="urn:mace:shibboleth:1.0:nameIdentifier"/>
      <resolver:AttributeEncoder xsi:type="enc:SAML2StringNameID" nameFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
</resolver:AttributeDefinition>

Edit '$SHIB_HOME/conf/saml-nameid.xml' and comment out any beans listed in the "shibboleth.SAML2NameIDGenerators" list. Finally, edit '$SHIB_HOME/conf/saml-nameid.properties' and uncomment the legacy Generator:

idp.nameid.saml2.legacyGenerator = shibboleth.LegacySAML2NameIDGenerator

That will enable Shibboleth to process the "persistent" attribute using the Principal Name. (Re)start the Tomcat instance we we should be ready to go.

3) Testing the service

To test the service navigate to:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
Select "realm B". You should be redirected to the Shibboleth authentication page. Enter "alice/alice" as the username/password. You will be redirected to Fediz, where it converts the received SAML token to a token in the realm of Fediz (realm A) and redirects to the web application.




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!