5 Replies Latest reply on Apr 25, 2006 11:12 AM by Scott Stark

    JACC:EJBContext.isCallerInRole

    Anil Saldanha Master

      http://jira.jboss.com/jira/browse/JBAS-2661

      When JACC is installed, the SecurityInterceptor is replaced with a JaasAuthenticationInterceptor as well as a JaccAuthorizationInterceptor.

      But in EnterpriseContext.isCallerInRole call will always ask the container.getRealmMapping returned object (which is the JaasSecurityManager) to check if the caller is in Role.

      I am thinking that this can be fixed by the JaccAuthorizationInterceptor adding its own RealmMapping implementation into the container when Jacc provider is enabled.

      container.setRealmMapping(new RealmMapping()
       {
       public Principal getPrincipal(Principal principal)
       {
       throw new IllegalStateException("Method is unimplemented");
       }
      
       public boolean doesUserHaveRole(Principal principal, Set roles)
       {
       if(roles == null || roles.size() == 0)
       throw new IllegalArgumentException("Roles is either null or empty");
       SimplePrincipal sp = (SimplePrincipal)(roles.iterator().next());
       String rolename = sp.getName();
       //This has to be the EJBRoleRefPermission
       EJBRoleRefPermission ejbRoleRefPerm = new EJBRoleRefPermission(ejbName,rolename);
       //Get the caller
       Subject caller;
       try
       {
       caller = SecurityActions.getContextSubject();
       }
       catch (PolicyContextException e)
       {
       throw new RuntimeException(e);
       }
       Principal[] principals = null;
       if( caller != null )
       {
       // Get the caller principals
       Set principalsSet = caller.getPrincipals();
       principals = new Principal[principalsSet.size()];
       principalsSet.toArray(principals);
       }
       ProtectionDomain pd = new ProtectionDomain (ejbCS, null, null, principals);
       return policy.implies(pd, ejbRoleRefPerm);
       }
      
       public Set getUserRoles(Principal principal)
       {
       throw new IllegalStateException("Method is unimplemented");
       }
       });
      


      Any objections/problems/better alternatives?

        • 1. Re: JACC:EJBContext.isCallerInRole
          Anil Saldanha Master

          Summary is that the JaccAuthorizationInterceptor will plugin a custom RealmMapping implementation, with the getPrincipal and getUserRoles being handled by the previous RealmMapping implementation existing in the Container (in this case, JaasSecurityManager). Only the doesUserHaveRole will be performed by the plugged in RM impl.

          • 2. Re: JACC:EJBContext.isCallerInRole
            Anil Saldanha Master

            Given the following DD:

            <ejb-jar>
             <display-name>CallerInRole Tests</display-name>
             <enterprise-beans>
             <session>
             ....
             <security-role-ref>
             <role-name>NiceUser</role-name>
             <role-link>GoodRole</role-link>
             </security-role-ref>
             </session>
             </enterprise-beans>
             <assembly-descriptor>
             <security-role>
             <description>Good Role to invoke</description>
             <role-name>GoodRole</role-name>
             </security-role>
             <method-permission>
             <role-name>GoodRole</role-name>
             <method>
             <ejb-name>UsefulStatelessSessionBean</ejb-name>
             <method-name>*</method-name>
             </method>
             </method-permission>
             </assembly-descriptor>
            </ejb-jar>


            The EJBModule class builds up the PolicyConfiguration as follows:
            - a EJBRoleRefPermission is created for ejbname=UsefulStatelessSessionBean and actions=NiceUser.

            But when the EJBContext.isCallerInRole("NiceUser") or EJBContext.isCallerInRole("GoodRole") call comes in, the EnterpriseClass then always follows the role-link element to make a check for
            RealmMapping.doesUserHaveRole(principal, "GoodRole"). This is bound to fail because the PC is storing a EJBRefPerm to "NiceUser".

            The jacc-1.0 spec says the following:
            3.1.5.3 Translating EJB security-role-ref Elements
            For each security-role-ref element appearing in the deployment
            descriptor, a corresponding EJBRoleRefPermission must be created. The name of each
            EJBRoleRefPermission must be obtained as described for
            EJBMethodPermission objects. The actions used to construct the permission must be the value of the
            role-name (that is the reference), appearing in the security-role-ref. The deployment tools must
            call the addToRole method on the PolicyConfiguration object to add a policy statement corresponding to the EJBRoleRefPermission to the role identified in the rolelink appearing in the
            security-role-ref.


            So the PC construction is consistent. But the isCallerInRole check is not consistent.

            Scott, what are your thoughts on this?

            • 3. Re: JACC:EJBContext.isCallerInRole
              Scott Stark Master

              There is an attempt to map the incoming role name ("NiceUser") to the linked to name ("GoodRole"):

               Iterator it = getContainer().getBeanMetaData().getSecurityRoleReferences();
               boolean matchFound = false;
              
               while (it.hasNext())
               {
               SecurityRoleRefMetaData meta = (SecurityRoleRefMetaData) it.next();
               if (meta.getName().equals(roleName))
               {
               roleName = meta.getLink();
               matchFound = true;
               break;
               }
               }
              


              For the configuration shown, the permission check would be against EJBRoleRefPermission("NiceUser", "GoodRole"), so this should work. The problem is where to put this check. It cannot be in the doesUserHaveRole method as this is used for both method permissions and isCallerInRole. We just need to refactor the current EnterpriseContext.isCallerInRole into a jacc/non-jacc version and add a container configuration flag that causes the jacc version to be used. We could do this implicitly based on the existence of the JaccAuthorizationInterceptor in the configuration, that is a coupling of externali configuration to implementation details in code.


              • 4. Re: JACC:EJBContext.isCallerInRole
                Anil Saldanha Master

                A better approach would be to have a flag on the container that whether JACC is installed or not.

                Since there is a call on the JaccAuthorizationInterceptor to set the container, it can enable the flag.

                From the configuration I showed, theoretically, both the checks on "NiceUser" and "GoodRole" should pass. But the jacc spec block I pasted earlier, seems to be saying that the EJBRoleRefPermission should contain just "NiceUser" in the PolicyConfiguration. There will be no EJBRoleRefPerm for "GoodRole". Is this correct, Scott?

                • 5. Re: JACC:EJBContext.isCallerInRole
                  Scott Stark Master

                  This is the same issue as in the web container. There has to be a role-link for every security-role-ref:


                  If the Bean Provider has declared any security role references using the security-role-ref elements, the Application Assembler must link all the security role references listed in the security-role-ref elements to the security roles defined in the security-role elements. This is described in more detail in subsection 21.3.3.


                  There should never be an isCallerInRole("GoodRole") call as this has not been declared. That would require:

                   <session>
                   ....
                   <security-role-ref>
                   <role-name>GoodRole</role-name>
                   <role-link>GoodRole</role-link>
                   </security-role-ref>
                   </session