8 Replies Latest reply on Jun 7, 2006 12:33 PM by j2ee_junkie

    LoginModule.login() passed null principal/credential from SL

    lost_traveller

      JaasSecurityManager.isValid(Principal principal, Object credential, Subject activeSubject) is being passed a null principal and credential, this in turn calls my LoginModule.login() method with a null username and password.

      This only happens when the call to JaasSecurityManager.isValid() is made to check the security assoication on a stateless session bean, when JaasSecurityManager.logon() is called from my client loginContext.login(); call it works fine.

      So my question is, how do you get a EJB to pass the same credential and principal that was previously passed by the client?

      Heres my client code:

       SecurityAssociationHandler handler = new SecurityAssociationHandler();
       Principal user = new MyPrincipal("username");
       handler.setSecurityInfo(user, "password".toCharArray());
       LoginContext loginContext = new LoginContext("other", handler);
       loginContext.login();
       Subject subject = loginContext.getSubject();
       Set principals = subject.getPrincipals();
       principals.add(user);
      


      Heres my LoginModule code, this is called once by the code above (and works fine) and then a bit later on by JBoss to check the security on an SLSB call:
      public boolean login() throws LoginException
       {
       NameCallback name = new NameCallback("User name");
       PasswordCallback pwc = new PasswordCallback("Password",
       false);
      
       callbackHandler.handle(new Callback[]{name, pwc});
      // user is null when called from SSLB, but populated when called from client code above
       String user = name.getName();
       String pw = new String(pwc.getPassword());
      ...
       }
      


      I am really stuck and have googled for answers with no luck, the mosst help I could find was http://docs.jboss.org/jbossas/jboss4guide/r2/html/ch8.chapter.html#ch8.ejbsecrole.fig, thanks in advance for your help.

        • 1. Re: LoginModule.login() passed null principal/credential fro
          j2ee_junkie

          Hello, n_bigglewort

          First, maybe you could provide some more detail other than it does not work. And please clarify what you mean by

          when JaasSecurityManager.logon() is called from my client loginContext.login();
          . Finally, provide some configuration details. Such as, how is "other" security-domain configured, what security-domain is your SLSB using, etc..

          thanks, cgriffith

          • 2. Re: LoginModule.login() passed null principal/credential fro
            lost_traveller

            Hi

            Well the client code exists in a Logon Servlet, which retreives the username and password from the user, the client code I posted before is then called in this servlet, to log the user onto the system, debugging this I can see the username and password being correctly passed to the LoginModule implementation inside the PasswordCallback and NameCallback and thus the user logs on correctly. Then, inside the same servelt I do a lookup on an EJB home:

            InitialContextSingleton initContextFinder = InitialContextSingleton.getInstance();
             InitialContext initialContext = initContextFinder.getContext()
            MyEJBHome ejbHome = initialContext.lookup("java:/comp/env/ejb/MyEJBHome");
            ejbHome.create();
            

            At the point where ejbHome.create() is called JBoss invokes the JaasSecurityManager which in turn invokes the logon() method in MyLoginModule (which extends UsernamePasswordLoginModule). At this point the JBoss EJB layer has "forgotten" the username and password used previously.

            I have found one solution which seems to be to use

            Hashtable env = new Hashtable();
            env.put(Context.SECURITY_PRINCIPAL, "myusername");
            env.put(Context.SECURITY_CREDENTIALS, "mypassword");
            Context ctx = new InitialContext(env);
            ctx.lookup("java:/comp/env/ejb/MyEJBHome");
            


            However, our InitialContext is a singleton and cannot be changed, and from what I can work out this way of doing things is out-of-date and no longer fits with the JAAS model.

            In my login-config.xml:

            <application-policy name = "other">
             <authentication>
            <!-- com.me.MyLoginModule simply extends UsernamePasswordLoginModule -->
             <login-module code = "com.me.MyLoginModule"
             flag = "required" >
            
             </login-module>
             </authentication>
             </application-policy>


            jobss.xml for the EJB in the session-ejb.jar:

            <jboss>
             <security-domain>java:/jaas/other</security-domain>
            </jboss>
            

            The ejb-jar.xml simply contains roles:
            ...
             <security-role>
             <description>View Address Details</description>
             <role-name>role.address.me.view</role-name>
             </security-role>
             <method-permission>
             <role-name>everyone</role-name>
             <method>
             <description>Remote Method: *</description>
             <ejb-name>AddressSession</ejb-name>
             <method-intf>Remote</method-intf>
             <method-name>*</method-name>
             </method>
             <method>
             <description>Home Method: *</description>
             <ejb-name>AddressSession</ejb-name>
             <method-intf>Home</method-intf>
             <method-name>*</method-name>
             </method>
             </method-permission>
            ...
            


            • 3. Re: LoginModule.login() passed null principal/credential fro
              j2ee_junkie

              Thanks lost_traveler for more detail. Well right off the bat, I can see a problem with your security domain. You read chapter 8 right? Well the "other" security domain really only needs one Login Module. That would be JBoss' ClientLoginModule. Then create another security domain and put your MyLoginModule in it. Then secure your ejb with the new security domain. Forget about setting env variables. After calling your EJB do a logout of context.

              Also note that this login is only good for your Logon Servlet.

              Hope this is all helpfull, cgriffith



              • 4. Re: LoginModule.login() passed null principal/credential fro
                lost_traveller

                Thanks for your replay, yeah I've been using chapter 8 as a guide.

                I'm not sure I'm with you though, there is only one login module defined in the "other" domain.
                If I modify my code to reflect the following it should work?

                public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
                 {
                 // get front end parameters
                 String username = request.getParameter("username");
                 String password = request.getParameter("password");
                 Principal user = null;
                 try
                 {
                 SecurityAssociationHandler handler = new SecurityAssociationHandler();
                 user = new MyPrincipal(username);
                 handler.setSecurityInfo(user, password.toCharArray());
                 LoginContext loginContext = new LoginContext("client-login", handler);
                 loginContext.login();
                 Subject subject = loginContext.getSubject();
                 Set principals = subject.getPrincipals();
                 principals.add(user);
                ...
                 InitialContextSingleton initContextFinder = InitialContextSingleton.getInstance();
                 InitialContext initialContext = initContextFinder.getContext()
                
                 AddressSessionHome addressHome = (AddressSessionHome)initialContext.lookup("java:/comp/env/ejb/AddressSessionHome");
                 AddressSSession addressBean = addressHome.create();
                ...
                 loginContext.logout();
                 }
                 catch(Exception e)
                 {
                ...
                 }
                 }


                where "client-login" is defined in login-cnfig.xml as:

                <policy>
                 <!-- Used by clients within the application server VM such as
                 mbeans and servlets that access EJBs.
                 -->
                 <application-policy name = "client-login">
                 <authentication>
                 <login-module code = "org.jboss.security.ClientLoginModule"
                 flag = "required">
                 <!-- Any existing security context will be restored on logout -->
                 <module-option name="restore-login-identity">true</module-option>
                 </login-module>
                 </authentication>
                 </application-policy>
                ...
                </policy>


                and jboss.xml should point to a new "ejb-domain", defined as:
                <application-policy name = "ejb-domain">
                 <authentication>
                <!-- com.me.MyLoginModule simply extends UsernamePasswordLoginModule -->
                 <login-module code = "com.me.MyLoginModule"
                 flag = "required" >
                 </login-module>
                 </authentication>
                 </application-policy>
                



                I'm new to JAAS, so how would I then go about keeping a user logged in for an entire session and for authorisation to work for say, session bean to session bean calls?

                many thanks.

                • 5. Re: LoginModule.login() passed null principal/credential fro
                  lost_traveller

                  ok thanks, still not entirely sure why but changing the LoginContext to use "client-login", worked! My mistake seemed to be to use the same domain for client and server, they should be different one with a client login module and one with a server login module as described in section 8.4.1.

                  thanks again.

                  • 6. Re: LoginModule.login() passed null principal/credential fro
                    j2ee_junkie

                    Sorry, I got sidetracked and could not respond quick enough. Yes what you have set up is correct and was what I described. Using "client-login" security domain is a better option than modifing "other". And you added "ejb-domain" as I described.

                    As mentioned before, the login context you have set up can only be used to authenticate/authorizae(A/A) calls to JBoss in the same thread. This works fine in your scenario to allow your servlet to access an EJB. Since web applications are multi-threaded, with threads being reused from pools, this mechanism should not be used to provide (A/A) for users. In such a case, you would need to create this login context/login/logout for every servlet. The best way to provide user A/A is to use container managed authentication as described in chapter 8.

                    enjoy, cgriffith

                    • 7. Re: LoginModule.login() passed null principal/credential fro
                      lost_traveller

                      Well I've been running the secure EJB's with J2EE roles fine now, but like you say it only works for one thread and therefore the login information is lost after that HTTP request/thread dies.

                      I'm not sure where in chapter 8 is the container managed authentication that you describe? Do you mean securing my servlets by using the <security-constraint> element in web.xml? If so, how does this propagate to the EJB security? Would this mean doing away with using the ClientLoginModule and ServerLoginModules and using a Realm Implementation instead?

                      Thanks again, I'm working on a very large app and trying to retrofit JBoss complient A/A so that we can use JBoss in the future!

                      • 8. Re: LoginModule.login() passed null principal/credential fro
                        j2ee_junkie

                        lost_traveller,

                        Yes, securing your servlets with a security-constraint. As well as configuring an security domain for your servlets. If you use the same security domain for your servlets as your ejb's then security is propagated by the JBossSecurityMgrRealm. In that domain you could use your MyLoginModule. You would not have to use the ClientLoginModule at all. Don't forget to check the wiki pages http://wiki.jboss.org/ and search forums for more help.

                        cgriffith