CXF already supports a wide range of authentication and authorization approaches. Unfortunately they are all configured differently and do not integrate well with each other.
So the idea is to create one standardized authentication / authorization flow in CXF where the modules can then fit in. There are a lot of security frameworks out there that could be used as a basis for this. The problem is though that each framework (like Shiro or Spring Security) uses its own mechanisms which are not standardized. So by choosing one framework we would force our users to depend on this.
The best standardized security framework in java is JAAS. It is already included in Java and most security frameworks can be hooked into it. So let´s investigate what we could do with JAAS.
Authentication using JAAS
JAAS authentication is done by creating a LoginContext and doing a login on it. Things to configure is the name of the login config and the Callback Handlers. So CXF needs mechanisms for the user to set the config name and needs to provide CallBackHandlers to supply credentials.
CXF needs to supply different data to identify the users depending on the chosen authentication variant.
Basic Auth: username and password from HTTP header
WS-Security UserNameToken: Username and password from SOAP header
Spnego: Kerberos token from HTTP header
HTTPS client cert: Certificate information
We could simply detect what information is provided and configure the Callbackhandlers for each variant.
The JAAS configuration is supplied differently depending on the runtime CXF runs in.
Standalone: For standalone usage the JAAS config can simply come from a file.
Servlet Container: Not sure. Is there a standard approach for this?
Apache Karaf: Karaf already provides a JAAS integration so we just have to configure the JAAS config name and supply a suitable config in karaf
Supplying Role and User information
JAAS stores identity information in the JAAS subject. The method getPrincipals returns Principal objects which can be users, roles or even other identity information. To differentiate between roles and users there are two common approaches.
- different Classes like a UserPrincipal or RolePrincipal. Unfortunately there are no standard interfaces
- prefixes. So for example roles start with role- . Again there is no standard
Authorization has very diverse requirements. So we need to make sure we integrate well with different approaches.
Generally the idea is to base the Authorization on the JAAS login data. After a JAAS login the JAAS subject can be retrieved in a standard way:
AccessControlContext acc = AccesController.getContext();
Subject subject = Subject.getSubject(acc);
So the idea is that we provide certain default authorization variants that rely on the above to retrieve authentication information in a standardized way. So authorization is nicely decoupled from authentication and fully standards based.
This then also provides a nice interface for users or other frameworks to access authentication information and provide custom authorization variants.
Default Authorization Variants
Java EE provides some standard annotations like @RolesAllowed. We can provide an interceptor that reads the annotations of serivce impls and provides authorization like in a JEE container.
An XACML policy enforcement point can retrieve the JAAS login data and do authorization against an XACML Policy Decision Point (PDP).
Karaf role based OSGi service Authorization
Karaf 3 already supports authorization on the OSGi service level and uses JAAS for authentication. So if we do a JAAS login in CXF and the service impl code calls an OSGi service then the Karaf role based securtiy should already work out of the box.
Ideally we should integrate the new authentication / authorization model in a way that enable the user to switch on authentication for the karaf server without specific configurations in the user bundles that implement the services.
So we could have a config setting for the CXF OSGi servlet to enable JAAS authentication and set a JAAS config. This would then enable authentication for all services using the named JAAS config from karaf. We could then also switch on the annotaion based authorization. So users could leverage this for their service by just supplying the annotations and doing no other configs on the service level.
A further approach would be to let the user configure named features on the CXF servlet level (which are then retrieved as OSGi services). So the user can even attach his own extensions on the server level like for ecxample integrating a custom XACML PEP.
Doing a full JAAS login requires to use subject.doAs to populate the AcessControlContext. This is not possible in a CXF interceptor as the interceptor only works on a message but can not call the next interceptor for doAs. So the question is where to do the JAAS login and the doAs?