7 Replies Latest reply on Mar 3, 2004 11:59 AM by meera13

    Serious login problem

    rza

      Hi,

      I'm working with JAAS and I have the following problem.

      I have two MBeans started. Each of them starts the thread running in the loop (T1 and T2). One thread connects to remote server A and the second to server B. Each server uses JAAS as a security manager with DatabaseServerLoginModule.

      I have made a test which proofs that it is likely to call EJB by T1 (T2) with security associations set by T2 (T1).

      Because login() method sets security associations, so there is possibility that when each thread creates its own LoginContext and calls login() method, we don't know with what security associations the EJB is called by any of the thread.

      Let's assume that each thread creates its own LoginContext with different username in callback object and then calls EJB on remote server (username used in T1 exists only on server A and the one used in T2 exists only on server B). In addition there is no synchronization between both threads, so we don't know if EJB from remote server A is called by T1 before T2 calls login() method or after.
      If before, there is no problem. if after the username is taken from T2 and he doesn't exist on server A -> login fails :(.

      How to avoid this problem and be sure that security associations are properly set before calling EJB??
      Maybe it is possible to create LoginContext for each thread separately and call EJB with proper for specified remote server security associations??


      Many thanks,
      Robert

        • 1. Re: Serious login problem
          starksm64

          Its not clear where you are doing the JAAS login and how the security context associated with the login is propagated to the thread making the ejb call. Post the testcase which demonstrates the crossed up calls.

          • 2. Re: Serious login problem
            rza

            The sample scenario is the following:

            Server A and B uses JAAS as a security manager, so that there are 2 statements (one for server-side and second for client-side purpose) in their login-config.xml file:

            <application-policy name="MY_SERVER_POLICY">

            <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
            <module-option name="dsJndiName">
            java:/MyDS
            </module-option>
            <module-option name="principalsQuery">
            select password from users where name=?
            </module-option>
            <module-option name="rolesQuery">
            select r.name, 'Roles' from roles r,users u,users_roles ur where u.user_id=ur.user_id_fk and r.role_id=ur.role_id_fk and u.name=?
            </module-option>
            </login-module>

            </application-policy>

            <application-policy name = "MY_CLIENT_POLICY">

            <login-module code = "org.jboss.security.ClientLoginModule"
            flag = "required">
            </login-module>

            </application-policy>



            There are 2 threads (T1,T2) started on server A from MBean (they can be started from one MBean).
            MY_CLIENT_POLICY is necessery because when T1 or T2 calls EJB as a client and it requires authentication because JAAS is used.
            In addition let's assume that USER_A exists on server A and USER_B on server B.

            I have my callback handler class similar to UsernamePasswordCallbackHandler and there is no need to show its implementation.

            The threads are the following:

            For T1:

            public void run() {
            try {
            Properties props = new Properties();
            props.setProperty("java.naming.provider.url","jnp://"+SERVER_A+":1099");
            props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
            props.setProperty("java.naming.factory.url.pkgs","org.jnp.interfaces");
            LoginContext lc = new LoginContext("MY_CLIENT_POLICY", new MyCallbackHandler("USER_A","PASS_A".toCharArray()));
            lc.login();

            MyBean mb = MyBeanUtil.getHome(props).create();
            mb.callMethod();
            } catch(Exception e) {
            e.printStackTrace();
            }
            }


            For T2:
            public void run() {
            try {
            Properties props = new Properties();
            props.setProperty("java.naming.provider.url","jnp://"+SERVER_B+":1099");
            props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
            props.setProperty("java.naming.factory.url.pkgs","org.jnp.interfaces");
            LoginContext lc = new LoginContext("MY_CLIENT_POLICY", new MyCallbackHandler("USER_B","PASS_B".toCharArray()));
            lc.login();

            MyBean mb = MyBeanUtil.getHome(props).create();
            mb.callMethod();
            } catch(Exception e) {
            e.printStackTrace();
            }
            }



            Threada T1 and T2 are started from MBean:

            ...
            ...
            public void start() throws Exception {
            T1 t1 = new T1();
            T2 t2 = new T2();
            t1.start();
            t2.start();
            }
            ...
            ...


            Because the EJB calls are executed from within the thread we don't know whether mb.callMethod() from T1 will be executed after the call lc.login() from T1 or T2.
            If the scenario is the following:
            - (T1) lc.login();
            - (T2) lc.login();
            - (T1) mb.callMethod();

            ... is this possible that lc.login() in T2 can overwrite security associations used in T1??
            What is the scope of LoginContext when is created inside the container??


            I need comprehensive infomation about LoginContext functionality because my real application is much more complicated that the example above and I have to control the system.

            I have made many tests and I found that in the above scenario EJBs have been called properly with the LoginContext set in each thread separately.
            But I'm not sure whether it is the rule or a fluke?


            On the other hand when I made another test the result was different, e.g:
            I started 2 MBeans (MBean1 and MBean2) and in each of them I called EJB mb.callMethod() on the server A. MBean1 was started before MBean2.
            In MBean1 I called lc.login() before mb.callMethod() but in MBean2 I didn't do it.
            There was no exception thrown in MBean2, why??
            It looks like MBean2 used security associations set in MBean1.


            Another example with self-coded login module:
            The login module extends DatabaseServerLoginModule because some additional functionality had to be added.
            In the implementation of login() method of the modul there is EJB called. EJB needs to be authorized, so lc.login() is called with the special user 'internal' for internal loging purposes (there is no endless loop in login module login() method because when this special user is logging the method returns true and authentication success).

            ...
            public boolean login() throws LoginException {
            boolean b = false;
            ...
            lc.login();
            ...
            mb.callSomeMethod();
            ...
            return b;
            }
            ...


            When I made tests with this login module I found that is some cases mb.callMethod() has been called by principal 'internal' instead of USER_A or USER_B. Why??

            I think my description is clear enough.
            Many thanks for any help.
            Regards,
            Robert

            • 3. Re: Serious login problem
              starksm64

              The behavior of the LoginContext is strictly a function of the login modules in the configuration used by the LoginContext. If your using the org.jboss.security.ClientLoginModule, this will associated the principal/credentials with the current thread using the org.jboss.security.SecurityAssociation. Unless you logout or clear the association, this context can propagate to other threads.

              In a multi-threaded envrionment you need to establish the security context using a login at the thread entry point, and clear it on exit. This behavior is automatic in the ejb and web tiers that have a well defined security contract. Its undefined for MBeans which have to security contract.

              • 4. Re: Serious login problem
                rza

                You wrote: "Unless you logout or clear the association, this context can propagate to other threads".

                The question is 'can' or really propagates??


                When ClientLoginModule calls logout() method, the clear() method from SecurityAssociation is called:

                public static void clear() {
                SecurityManager sm = System.getSecurityManager();
                if( sm != null )
                sm.checkPermission(setPrincipalInfoPermission);
                if( server == true ) {
                threadPrincipal.set(null);
                threadCredential.set(null);
                threadSubject.set(null);
                } else {
                SecurityAssociation.principal = null;
                SecurityAssociation.credential = null;
                SecurityAssociation.subject = null;
                }
                }


                But I couldn't find what the method set(null) from ThreadLocal really do?? There is no info in doc.

                Maybe I misunderstood what ThreadLocal do, but it seems that the class keeps the copy of the variable for each thread separately.
                So that, why clearing is propagated to another threads??

                You wrote: "This behavior is automatic in the ejb and web tiers that have a well defined security contract."

                According to this let's assume that two different methods from one EJB (or some methods from two different EJB) are called and they try to call remote servers (each method connects to different server) by executing the following code:
                ...
                Properties props = new Properties();
                props.setProperty("java.naming.provider.url","jnp://"+SERVER+":1099");
                props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
                props.setProperty("java.naming.factory.url.pkgs","org.jnp.interfaces");
                LoginContext lc = new LoginContext("MY_CLIENT_POLICY", new MyCallbackHandler("USER","PASS".toCharArray()));
                lc.login();
                MyBean mb = MyBeanUtil.getHome(props).create();
                mb.callMethod();
                lc.logout();
                ...


                Does your sentence means that both method calls are treated independent without mutual influence of setting and clearing security associations??


                During the tests I did, I found that when I didn't start any thread inside MBean, it looked like MBeans code was executed in one thread. Is this true??
                When there were two MBeans starting on the trot, it was enough to login in the first starting MBean without doing it in the second one.

                • 5. Re: Serious login problem
                  meera13

                  Were you able to solve it ? I have the same problem I know the problem but do not know how to clear the info stored in the login module that it uses (..explicitly)... Could you elaborate...

                  • 6. Re: Serious login problem
                    starksm64


                    The question is 'can' or really propagates??

                    Its depends on whether a thread pool is used and if the entry
                    point resets the security associated based on the caller.

                    But I couldn't find what the method set(null) from ThreadLocal really do?? There is no info in doc.

                    TL.set(null) removes the binding for the thread.

                    Does your sentence means that both method calls are treated independent without mutual influence of setting and clearing security associations??

                    The scope of the login is isolated to the request thread in the jboss server. If the calls are done in the same thread the security association exists on the thread until cleared or changed.

                    Whether or not MBean calls are done on the same thread is an implementation detail. Today there is no thread pool, tomorrow there may be.


                    • 7. Re: Serious login problem
                      meera13

                      Thanks a lot!