[ https://issues.apache.org/jira/browse/CXF-5118?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Piotr Klimczak updated CXF-5118: -------------------------------- Comment: was deleted (was: Done refactoring. Finished just few tests so it is not final yest but let's say beta (functionality frozen). Just for review and get some more complaints :) Finally haven't used CallbackHandlerProvider as it causes additional problems with handling already authenticated message. So code is available here: https://github.com/PiotrKlimczak/cxf/commits/2.7.x-fixes but is messed up with 3 commits. Final idea is as follows: Introduced: 1. TLSCertificateInterceptor 2. TLSCertificateMapper 3. TLSUserToken TLSCertificateInterceptor uses TLSCertificateMapper to do: {code} TLSUserToken toTLSUserToken(String subjectDN, String username, X509Certificate[] certificateChain); {code} Default implementation for TLSCertificateMapper is provided, doing just simple mapping and expecting to work for example with JAASLoginInterceptor without password. TLSUserToken has: {code} private String subjectDN; private String username; private String password; private List<String> roles; private X509Certificate[] certificateChain; private boolean authenticated; {code} JAASLoginInterceptor changes {code} AuthorizationPolicy policy = message.get(AuthorizationPolicy.class); if (policy != null) { name = policy.getUserName(); password = policy.getPassword(); } else { // try the UsernameToken SecurityToken token = message.get(SecurityToken.class); if (token != null && token.getTokenType() == TokenType.UsernameToken) { UsernameToken ut = (UsernameToken)token; name = ut.getName(); password = ut.getPassword(); } } Subject subject; try { if (name != null && password != null) { subject = doJAASLogin(name, password); } else if (message.get(TLSUserToken.class) != null) { //If not authenticated with name/password, then check if //message is TLS Authenticated TLSUserToken token = message.get(TLSUserToken.class); if (token.isAuthenticated()) { subject = getSecuritySubject(token.getUsername(), token.getRoles()); } else { subject = doJAASLogin(token.getUsername(), token.getPassword()); } } else { throw new AuthenticationException("Authentication required but no user or password was supplied"); } message.put(SecurityContext.class, createSecurityContext(name, subject)); // Run the further chain in the context of this subject. // This allows other code to retrieve the subject using pure JAAS if (useDoAs) { Subject.doAs(subject, new PrivilegedAction<Void>() { @Override public Void run() { InterceptorChain chain = message.getInterceptorChain(); if (chain != null) { chain.doIntercept(message); } return null; } }); } } {code} Example certificate mapper: {code} public class MyCertificateMapper implements TLSCertificateMapper { @Override public TLSUserToken toTLSUserToken(String subjectDN, String username, X509Certificate[] certificateChain) { TLSUserToken token = new TLSUserToken(subjectDN, certificateChain); token.setUsername(username); List<String> roles = new ArrayList<String>(); roles.add("A"); roles.add("V"); token.setRoles(roles); return token; } } {code} Tested with: {code} <camel-cxf:cxfEndpoint id="helloWorld" address="https://localhost:8143/HelloWorld" serviceClass="com.wmpromus.soap.mutual.HelloWorldImpl"> <camel-cxf:inInterceptors> <bean id="authenticationInterceptor" class="org.apache.cxf.interceptor.security.TLSCertificateInterceptor"> <property name="userNameKey" value="EMAILADDRESS"/> <property name="reportFault" value="true" /> <property name="certificateMapper" ref="tlsHandler" /> </bean> <bean id="authenticationInterceptor" class="org.apache.cxf.interceptor.security.JAASLoginInterceptor"> <property name="contextName" value="ldap-mail"/> <property name="reportFault" value="true" /> </bean> <ref bean="authorizationInterceptor" /> </camel-cxf:inInterceptors> </camel-cxf:cxfEndpoint> <bean id="authorizationInterceptor" class="org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor"> <property name="securedObject" ref="helloWorldImpl"/> </bean> <bean id="helloWorldImpl" class="com.wmpromus.soap.mutual.HelloWorldImpl" /> <bean id="tlsHandler" class="com.wmpromus.soap.mutual.MyCertificateMapper"></bean> {code} To make configuration easier, feature might be introduced. All problems are solved with this code. Open for any scenerio. The only disadvantage is quite lot of changes.) > Create CXF interceptor which will use HTTPS client certificates to create > JAAS SecurityContext > ----------------------------------------------------------------------------------------------- > > Key: CXF-5118 > URL: https://issues.apache.org/jira/browse/CXF-5118 > Project: CXF > Issue Type: New Feature > Components: Core > Reporter: Sergey Beryozkin > Assignee: Christian Schneider > > Use case: > The user authenticates against the webservice using an X509 client > certificate. In case of successful authentication the JAAS security context > should be populated with a Subject that stores the user name and the roles of > the user. This is necessary to support Authorization at a later stage. > Design ideas > The SSL transport will be configured to only accept certain client > certificates. So we can assume that the interceptor does not have to do a > real authentication. Instead it has to map from the subjectDN of the > certificate to the user name and then lookup the roles of that user. Both > then has to be stored in the subject's principles. > The mapping could be done inside a JAASLoginModule or before. Inside will > give the user more flexibility. > The next step to retrieve the roles should be done in one of the standard > JAASLoginModules as the source of the roles can be quite diverse. So for > example the LdapLoginModule allows to retrieve the roles from Ldap. At the > moment these modules require the password of the user though which is not > available when doing a cert based auth. > So I see two variants to retrieve the roles: > 1. Change the loginmodules like the LDAP one to be configureable to use a > fixed ldap user for the ldap connect and not require the user password. So > the module would have two modes: a) normal authentication and group gathering > b) use a fixed user to just retrieve roles for a given user > 2. Store the user password somewhere (e.g. in the mapping file). In this case > the existing LDAPLoginModule could be used but the user password would be > openly in a text file > 3. Create new LoginModules with the desired behaviour (fixed user and only > lookup of roles) -- This message was sent by Atlassian JIRA (v6.2#6252)