[ 
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)

Reply via email to