2 Replies Latest reply on Oct 24, 2002 5:55 AM by bratseth

    Problems using JBoss/JAAS from a Swing client

    bratseth

      I am using JAAS and the JBoss ClientLoginModule from a Swing client, by hardcoding a login configuration in a
      javax.security.auth.login.LoginConfiguration subclass.

      I am experiencing some probelms with this which, as far as I can understand must be a JBoss bug:
      Some times a user logging in will have no roles, and some times it will have the correct roles (theres is only one role in my system, which all users are assigned by a UsersRolesLoginModule).

      The error I get when no roles are incorrectly assigned is
      java.lang.SecurityException: Insufficient method permissions, principal=test2, method=create, interface=HOME, requiredRoles=[editor], principalRoles=null
      at org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssociation(SecurityInterceptor.java:228)
      at org.jboss.ejb.plugins.SecurityInterceptor.invokeHome(SecurityInterceptor.java:94)
      at org.jboss.ejb.plugins.LogInterceptor.invokeHome(LogInterceptor.java:129)
      at org.jboss.ejb.StatelessSessionContainer.invokeHome(StatelessSessionContainer.java:300)
      at org.jboss.ejb.Container.invoke(Container.java:730)
      at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:517)
      at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:381)
      at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:324)
      at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:261)
      at sun.rmi.transport.Transport$1.run(Transport.java:148)
      at java.security.AccessController.doPrivileged(Native Method)
      at sun.rmi.transport.Transport.serviceCall(Transport.java:144)
      at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)
      at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)
      at java.lang.Thread.run(Thread.java:536)


      As you can see (at least by reading the code) is that the RealmMapping of the SecurityInterceptor is answering null to getUserRoles(principal). Now as I only have one, statically assigned role, this must be a JBoss bug, right?

      Another funny thing about this is that the error is sometimes transient and sometimes non-transient (requires server restart) for a particular login. The frequency of the error is increasing from almost never to almost always as the network latency increases, which seems to me to indicate some sort of race condition.

      Any help in solving this would be greatly apreciated.

      The error is manifest on both 3.0 and 3.0.3.

      Thanks. Jon S Bratseth.

        • 1. Re: Problems using JBoss/JAAS from a Swing client
          bratseth

          The problem is that JaasSecurityManager.getUserRoles
          returns null when it should have returned the pricipals roles:

          public Set getUserRoles(Principal principal)
          {
          HashSet userRoles = null;
          Subject subject = getActiveSubject();
          if( subject != null )
          {
          DomainInfo info = getCacheInfo(principal, false);
          Group roles = null;
          if( info != null )
          roles = info.roles;
          if( roles != null )
          {
          userRoles = new HashSet();
          Enumeration members = roles.members();
          while( members.hasMoreElements() )
          {
          Principal role = (Principal) members.nextElement();
          userRoles.add(role);
          }
          }
          }
          return userRoles;
          }

          This is an obfuscated way of saying
          if theres cached roles ( getCacheInfo(..).roles ),
          return them
          else
          return null

          And when getCacheInfo is called with parameter false, it will peek() the cache, and thus not fetch the object if it's not present.
          Thus, if there's no cached roles, the roles returned for the principal is null.

          This can't be what is intended, but how to correct it?
          I could simply pass true instead of false to switch to get() instead of peek(), but the JavaDoc of getCacheInfo warns about an error on getCacheInfo(..,true) which seesms to be to be the error one would get on sending false:

          /** An accessor method that synchronizes access on the domainCache
          to avoid a race condition that can occur when the cache entry expires
          in the presence of multi-threaded access. The allowRefresh flag should
          be true for authentication accesses and false for authorization accesses.
          If it were to be true for an authorization access a previously authenticated
          user could be seen to not have their expected permissions due to a cache
          expiration.

          @param principal, the caller identity whose cached credentials are to
          be accessed.
          @param allowRefresh, a flag indicating if the cache access should flush
          any expired entries.
          */
          private DomainInfo getCacheInfo(Principal principal, boolean allowRefresh)
          {
          if( domainCache == null )
          return null;

          DomainInfo cacheInfo = null;
          synchronized( domainCache )
          {
          if( allowRefresh == true )
          cacheInfo = (DomainInfo) domainCache.get(principal);
          else
          cacheInfo = (DomainInfo) domainCache.peek(principal);
          }
          return cacheInfo;
          }

          Is the problem simply that the cases which should allow refresh and thos which should have been mixed up?



          • 2. Re: Problems using JBoss/JAAS from a Swing client
            bratseth

            (Reposting the reply because I'm not able to view it. The forum says one reply, but doesn't show it.)

            The problem is that JaasSecurityManager.getUserRoles
            returns null when it should have returned the pricipals roles:

            public Set getUserRoles(Principal principal)
            {
            HashSet userRoles = null;
            Subject subject = getActiveSubject();
            if( subject != null )
            {
            DomainInfo info = getCacheInfo(principal, false);
            Group roles = null;
            if( info != null )
            roles = info.roles;
            if( roles != null )
            {
            userRoles = new HashSet();
            Enumeration members = roles.members();
            while( members.hasMoreElements() )
            {
            Principal role = (Principal) members.nextElement();
            userRoles.add(role);
            }
            }
            }
            return userRoles;
            }

            This is an obfuscated way of saying
            if theres cached roles ( getCacheInfo(..).roles ),
            return them
            else
            return null

            And when getCacheInfo is called with parameter false, it will peek() the cache, and thus not fetch the object if it's not present.
            Thus, if there's no cached roles, the roles returned for the principal is null.

            This can't be what is intended, but how to correct it?
            I could simply pass true instead of false to switch to get() instead of peek(), but the JavaDoc of getCacheInfo warns about an error on getCacheInfo(..,true) which seesms to be to be the error one would get on sending false:

            /** An accessor method that synchronizes access on the domainCache
            to avoid a race condition that can occur when the cache entry expires
            in the presence of multi-threaded access. The allowRefresh flag should
            be true for authentication accesses and false for authorization accesses.
            If it were to be true for an authorization access a previously authenticated
            user could be seen to not have their expected permissions due to a cache
            expiration.

            @param principal, the caller identity whose cached credentials are to
            be accessed.
            @param allowRefresh, a flag indicating if the cache access should flush
            any expired entries.
            */
            private DomainInfo getCacheInfo(Principal principal, boolean allowRefresh)
            {
            if( domainCache == null )
            return null;

            DomainInfo cacheInfo = null;
            synchronized( domainCache )
            {
            if( allowRefresh == true )
            cacheInfo = (DomainInfo) domainCache.get(principal);
            else
            cacheInfo = (DomainInfo) domainCache.peek(principal);
            }
            return cacheInfo;
            }

            Is the problem simply that the cases which should allow refresh and thos which should have been mixed up?