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:


2 comments:

  1. Hi,

    Can we extend above example like

    import org.apache.shiro.authz.annotation.RequiresPermissions;

    @RequiresPermissions("my:create:numbers")
    public int doubleIt(int numberToDouble) {
    return numberToDouble * 2;
    }

    ReplyDelete
  2. In the example above, no, as the Shiro authentication takes place in the Camel route before the CXF endpoint. To get it to work as above, you will need to configure authentication for the CXF endpoint somehow.

    ReplyDelete