[ 
https://issues.apache.org/jira/browse/CXF-5484?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul Adams updated CXF-5484:
----------------------------

    Description: 
This is an obscure issue but 
org.apache.cxf.jaxrs.security.JAASAuthenticationFilter internally uses an 
instance of org.apache.cxf.interceptor.security.JAASLoginInterceptor to handle 
authentication for it.  It simply over-rides the "getCallbackHandler" method to 
provide credentials gathered via HTTP to the interceptor.  There are a few 
setters that allow conditioning of the underlying interceptor but there are no 
setters for roleClassifier/roleClassifierType.
e.g.
public void setRoleClassifier(String rc) { interceptor.setRoleClassifier(rc); }
public void setRoleClassifierType(String rct) { 
interceptor.setRoleClassifierType(rct);}

In my specific use I'm embedded CXF JAX-RS services in Jetty within Apache 
Karaf and I need to gain access to the appropriate java.security.Principal 
representing the user that authenticated for a given resource.

The LoginModule that represents the realm is an instance of 
org.apache.karaf.jaas.modules.ldap.LDAPLoginModule.  This LoginModule produces 
a Subject populated with two types of Principals
org.apache.karaf.jaas.modules.RolePrincipal abd
org.apache.karaf.jaas.modules.UserPrincipal


The former represents the roles (groups) a user is in and the latter obviously 
represents the actual user principal.  In this situation however the existing 
JAASAuthenticationFilter has no means of separating out the two since it cannot 
be conditioned to determine which is which and as a result when consulting the 
results of javax.ws.rs.core.SecurityContext.getUserPrincipal(); it's 
undetermined which Principal will be returned and it's almost always the wrong 
one (a RolePrincipal rather than the UserPrincipal).

The only way I could deal with this and get access to the correct Principal was 
to sub-class JAASAuthenticationFilter, duplicate some of its code, and 
condition the interceptor how I needed (I hard coded but setters obviously 
would have been more appropriate).

E.g.
public class JAASAuthenticationFilter extends
        org.apache.cxf.jaxrs.security.JAASAuthenticationFilter {

    private JAASLoginInterceptor interceptor = new JAASLoginInterceptor() {
        protected CallbackHandler getCallbackHandler(String name,String 
password) {
            return 
JAASAuthenticationFilter.this.getCallbackHandler(name,password);
        }
    };

    public void setContextName(String name) {
        interceptor.setContextName(name);
    }

    public void setLoginConfig(Configuration config) {
        interceptor.setLoginConfig(config);
    }

    @Override
    public Response handleRequest(Message m, ClassResourceInfo cri) {
        try {
                interceptor.setRoleClassifierType("classname");
                interceptor.setRoleClassifier("RolePrincipal");
            interceptor.handleMessage(m);
            return null;
        } catch (AuthenticationException ex) {
            return handleAuthenticationException(ex, m);
        } catch (SecurityException ex) {
            return handleAuthenticationException(ex, m);
        }
    }

}

And then at config time.
    <!-- bean id="authenticationFilter" 
class="org.apache.cxf.jaxrs.security.JAASAuthenticationFilter"-->
    <bean id="authenticationFilter" 
class="cxf.workaround.JAASAuthenticationFilter">
        <property name="contextName" value="..."/>
        <property name="realmName" value="..."/>
    </bean>

If the two setters existed on 
org.apache.cxf.jaxrs.security.JAASAuthenticationFilter then I could have simply 
added:
<property name="roleClassifierType" value="classname" />
<property name="roleClassifier" value="RolePrincipal" />

And things would have worked properly.

Interestingly JAASAuthentication filter DOES implement a deprecated method that 
I could use to deal with this, setRoleClassifier, which calls through to the 
same deprecated method on the interceptor.  I'll probably switch to doing this 
but it seems that setRolePrefix has been replaced by the setRoleClassifier/Type 
methods so it also seems JAASAuthenticationFilter should mimic these methods.

I take it back setRolePrefix is not an acceptable workaround because it doesn't 
compare to the classname of the Principal it compares it against the actual 
name meaning that Roles/Groups must be named by some convention that allows 
them to be separated from users which is why the method has been deprecated...



  was:
This is an obscure issue but 
org.apache.cxf.jaxrs.security.JAASAuthenticationFilter internally uses an 
instance of org.apache.cxf.interceptor.security.JAASLoginInterceptor to handle 
authentication for it.  It simply over-rides the "getCallbackHandler" method to 
provide credentials gathered via HTTP to the interceptor.  There are a few 
setters that allow conditioning of the underlying interceptor but there are no 
setters for roleClassifier/roleClassifierType.
e.g.
public void setRoleClassifier(String rc) { interceptor.setRoleClassifier(rc); }
public void setRoleClassifierType(String rct) { 
interceptor.setRoleClassifierType(rct);}

In my specific use I'm embedded CXF JAX-RS services in Jetty within Apache 
Karaf and I need to gain access to the appropriate java.security.Principal 
representing the user that authenticated for a given resource.

The LoginModule that represents the realm is an instance of 
org.apache.karaf.jaas.modules.ldap.LDAPLoginModule.  This LoginModule produces 
a Subject populated with two types of Principals
org.apache.karaf.jaas.modules.RolePrincipal abd
org.apache.karaf.jaas.modules.UserPrincipal


The former represents the roles (groups) a user is in and the latter obviously 
represents the actual user principal.  In this situation however the existing 
JAASAuthenticationFilter has no means of separating out the two since it cannot 
be conditioned to determine which is which and as a result when consulting the 
results of javax.ws.rs.core.SecurityContext.getUserPrincipal(); it's 
undetermined which Principal will be returned and it's almost always the wrong 
one (a RolePrincipal rather than the UserPrincipal).

The only way I could deal with this and get access to the correct Principal was 
to sub-class JAASAuthenticationFilter, duplicate some of its code, and 
condition the interceptor how I needed (I hard coded but setters obviously 
would have been more appropriate).

E.g.
public class JAASAuthenticationFilter extends
        org.apache.cxf.jaxrs.security.JAASAuthenticationFilter {

    private JAASLoginInterceptor interceptor = new JAASLoginInterceptor() {
        protected CallbackHandler getCallbackHandler(String name,String 
password) {
            return 
JAASAuthenticationFilter.this.getCallbackHandler(name,password);
        }
    };

    public void setContextName(String name) {
        interceptor.setContextName(name);
    }

    public void setLoginConfig(Configuration config) {
        interceptor.setLoginConfig(config);
    }

    @Override
    public Response handleRequest(Message m, ClassResourceInfo cri) {
        try {
                interceptor.setRoleClassifierType("classname");
                interceptor.setRoleClassifier("RolePrincipal");
            interceptor.handleMessage(m);
            return null;
        } catch (AuthenticationException ex) {
            return handleAuthenticationException(ex, m);
        } catch (SecurityException ex) {
            return handleAuthenticationException(ex, m);
        }
    }

}

And then at config time.
    <!-- bean id="authenticationFilter" 
class="org.apache.cxf.jaxrs.security.JAASAuthenticationFilter"-->
    <bean id="authenticationFilter" 
class="cxf.workaround.JAASAuthenticationFilter">
        <property name="contextName" value="..."/>
        <property name="realmName" value="..."/>
    </bean>

If the two setters existed on 
org.apache.cxf.jaxrs.security.JAASAuthenticationFilter then I could have simply 
added:
<property name="roleClassifierType" value="classname" />
<property name="roleClassifier" value="RolePrincipal" />

And things would have worked properly.

Interestingly JAASAuthentication filter DOES implement a deprecated method that 
I could use to deal with this, setRoleClassifier, which calls through to the 
same deprecated method on the interceptor.  I'll probably switch to doing this 
but it seems that setRolePrefix has been replaced by the setRoleClassifier/Type 
methods so it also seems JAASAuthenticationFilter should mimic these methods.




> JAASAuthenticationFilter cannot separate 3rdParty java.security.Principals 
> based on user/role
> ---------------------------------------------------------------------------------------------
>
>                 Key: CXF-5484
>                 URL: https://issues.apache.org/jira/browse/CXF-5484
>             Project: CXF
>          Issue Type: Bug
>          Components: JAX-RS
>    Affects Versions: 2.7.8
>         Environment: Embedded in Karaf
>            Reporter: Paul Adams
>            Priority: Minor
>
> This is an obscure issue but 
> org.apache.cxf.jaxrs.security.JAASAuthenticationFilter internally uses an 
> instance of org.apache.cxf.interceptor.security.JAASLoginInterceptor to 
> handle authentication for it.  It simply over-rides the "getCallbackHandler" 
> method to provide credentials gathered via HTTP to the interceptor.  There 
> are a few setters that allow conditioning of the underlying interceptor but 
> there are no setters for roleClassifier/roleClassifierType.
> e.g.
> public void setRoleClassifier(String rc) { interceptor.setRoleClassifier(rc); 
> }
> public void setRoleClassifierType(String rct) { 
> interceptor.setRoleClassifierType(rct);}
> In my specific use I'm embedded CXF JAX-RS services in Jetty within Apache 
> Karaf and I need to gain access to the appropriate java.security.Principal 
> representing the user that authenticated for a given resource.
> The LoginModule that represents the realm is an instance of 
> org.apache.karaf.jaas.modules.ldap.LDAPLoginModule.  This LoginModule 
> produces a Subject populated with two types of Principals
> org.apache.karaf.jaas.modules.RolePrincipal abd
> org.apache.karaf.jaas.modules.UserPrincipal
> The former represents the roles (groups) a user is in and the latter 
> obviously represents the actual user principal.  In this situation however 
> the existing JAASAuthenticationFilter has no means of separating out the two 
> since it cannot be conditioned to determine which is which and as a result 
> when consulting the results of 
> javax.ws.rs.core.SecurityContext.getUserPrincipal(); it's undetermined which 
> Principal will be returned and it's almost always the wrong one (a 
> RolePrincipal rather than the UserPrincipal).
> The only way I could deal with this and get access to the correct Principal 
> was to sub-class JAASAuthenticationFilter, duplicate some of its code, and 
> condition the interceptor how I needed (I hard coded but setters obviously 
> would have been more appropriate).
> E.g.
> public class JAASAuthenticationFilter extends
>         org.apache.cxf.jaxrs.security.JAASAuthenticationFilter {
>     private JAASLoginInterceptor interceptor = new JAASLoginInterceptor() {
>         protected CallbackHandler getCallbackHandler(String name,String 
> password) {
>             return 
> JAASAuthenticationFilter.this.getCallbackHandler(name,password);
>         }
>     };
>     public void setContextName(String name) {
>         interceptor.setContextName(name);
>     }
>     public void setLoginConfig(Configuration config) {
>         interceptor.setLoginConfig(config);
>     }
>     @Override
>     public Response handleRequest(Message m, ClassResourceInfo cri) {
>         try {
>               interceptor.setRoleClassifierType("classname");
>               interceptor.setRoleClassifier("RolePrincipal");
>             interceptor.handleMessage(m);
>             return null;
>         } catch (AuthenticationException ex) {
>             return handleAuthenticationException(ex, m);
>         } catch (SecurityException ex) {
>             return handleAuthenticationException(ex, m);
>         }
>     }
> }
> And then at config time.
>     <!-- bean id="authenticationFilter" 
> class="org.apache.cxf.jaxrs.security.JAASAuthenticationFilter"-->
>     <bean id="authenticationFilter" 
> class="cxf.workaround.JAASAuthenticationFilter">
>         <property name="contextName" value="..."/>
>         <property name="realmName" value="..."/>
>     </bean>
> If the two setters existed on 
> org.apache.cxf.jaxrs.security.JAASAuthenticationFilter then I could have 
> simply added:
> <property name="roleClassifierType" value="classname" />
> <property name="roleClassifier" value="RolePrincipal" />
> And things would have worked properly.
> Interestingly JAASAuthentication filter DOES implement a deprecated method 
> that I could use to deal with this, setRoleClassifier, which calls through to 
> the same deprecated method on the interceptor.  I'll probably switch to doing 
> this but it seems that setRolePrefix has been replaced by the 
> setRoleClassifier/Type methods so it also seems JAASAuthenticationFilter 
> should mimic these methods.
> I take it back setRolePrefix is not an acceptable workaround because it 
> doesn't compare to the classname of the Principal it compares it against the 
> actual name meaning that Roles/Groups must be named by some convention that 
> allows them to be separated from users which is why the method has been 
> deprecated...



--
This message was sent by Atlassian JIRA
(v6.1.5#6160)

Reply via email to