Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-5484

JAASAuthenticationFilter cannot separate 3rdParty java.security.Principals based on user/role

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 2.7.8
    • Fix Version/s: 2.6.12, 2.7.9, 3.0.0-milestone2
    • Component/s: JAX-RS
    • Labels:
      None
    • Environment:

      Embedded in Karaf

    • Estimated Complexity:
      Moderate

      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...

        Attachments

          Activity

            People

            • Assignee:
              ffang Freeman Yue Fang
              Reporter:
              adamspe Paul Adams
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: