1 2 Previous Next 19 Replies Latest reply on Mar 21, 2006 7:20 AM by nigelwhite

    getting Custom Principal in EJBContext.getCallerPrincipal()

    nithila

      Hi all

      I am writing custom login module which extends UsernamePasswordLoginModule, in getRoleSets() method i have added two Groups, 'Roles' and 'CallerPrincipal'. In 'CallerPrincipal' i have added object of my own customPrincipal ("OurPrincipal").

      In EJB method, when i do context.getCallerPrincipal() i am only getting org.jboss.security.SimplePrincipal and not "ourPrincipal".

      what should i do to get that? do i have to place my OurPrincipal.class file somewhere?do i have specify anything anywhere? Please help me. I have been trying this for past two days now.

        • 1. Re: getting Custom Principal in EJBContext.getCallerPrincipa
          tang

          I have also this problem and I checked my Subject was correctly filled. Is there a solution?? Or could you at least say me if it is not possible as I have been searching the solution for a while now.

          My commit method is like this:

          public boolean commit() throws LoginException {
          if(subject != null)
          {
          Set principals = subject.getPrincipals();
          if(principals != null)
          {
          principals.add(caller);
          Group callerPrincipal = new SimpleGroup("CallerPrincipal");
          callerPrincipal.addMember(caller);
          principals.add(callerPrincipal);
          // Set the roles for this principal in the 'Roles' group
          Group group = new SimpleGroup("Roles");
          group.addMember(new SimplePrincipal("JBossAdmin"));
          principals.add(group);

          return true;
          }

          }
          return false;

          }

          caller is a TestPrincipal created in the login method if it succeeded. This is only a test that's why I don't look for the roles of the user and I declare him as a JBossAdmin. Is that a problem? I know there is a lot of post about this porblem but none could help me.

          Thank you

          • 2. Re: getting Custom Principal in EJBContext.getCallerPrincipa
            phantom

            Hello

            I have the same problem. Please, anybody - answer! This quite important question in my view.

            Thank you

            • 3. Re: getting Custom Principal in EJBContext.getCallerPrincipa
              starksm64

              This works fine for me. I have updated the UsernamePasswordLoginModule baseclass to support an external Principal implementation and added a testcase that uses a custom principal class and this is seen as the ejb getCallerPrincipal type:

              public class CustomPrincipalBean implements SessionBean
              {
              ...
               public boolean validateCallerPrincipal(Class type)
               {
               ClassLoader typeLoader = type.getClassLoader();
               log.info("validateCallerPrincipal, type="+type+", loader="+typeLoader);
               Principal caller = ctx.getCallerPrincipal();
               log.info("caller="+caller+", class="+caller.getClass());
               boolean isType = true;
               if( caller.getClass().isAssignableFrom(type) == false )
               {
               log.error("type of caller is not: "+type);
               isType = false;
               }
              ...
              


              This produces output like:

              22:31:21,497 INFO [CustomPrincipalBean] validateCallerPrincipal, type=class org.jboss.test.security.ejb.CustomPrincipalImpl, loader=org.jboss.mx.loading.UnifiedClassLoader3@161f888{ url=file:/C:/cvs/JBoss3.2/jboss-3.2/build/output/jboss-3.
              2.4RC1/server/default/tmp/deploy/tmp52272security-jaas.jar ,addedOrder=37}
              22:31:21,497 INFO [CustomPrincipalBean] caller=callerJduke, class=class org.jboss.test.security.ejb.CustomPrincipalImpl


              • 4. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                phantom

                Let me explain error:

                in MyLoginModule commit method:

                Set principals = subject.getPrincipals();
                 principals.add(new UserPrincipal(name));
                
                 for (Iterator it = principals.iterator(); it.hasNext();)
                 {
                 Principal principal = (Principal) it.next();
                
                 }
                
                 Role role = new Role("Roles");
                 role.addMember(userPrincipal);
                 principals.add(role);
                

                UserPrincipal difined as
                public class UserPrincipal extends SimplePrincipal

                Role defined as
                public class Role extends SimpleGroup

                test.jsp has such code
                <%="principal: "+request.getUserPrincipal()%><br>
                <%="class: "+request.getUserPrincipal().getClass().getName()%><br>
                

                After logining a have such lines in test.jsp output:
                principal: qwe
                class: org.jboss.security.SimplePrincipal
                

                I use JBOSS+tomcat but if check principals in EJB - result is the same...:(

                Please help me to find out a mistake!:)

                • 5. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                  tang

                  Normally, to get the right CallerPricipal via the ejb getCallerPrincipal method or via the Servlet getUserPrincipal, you have to fill the subject like I did in my post earlier in this thread (look at my commit method).
                  It is to say you got to fill it with your CallerPrincipal (you did) with a group containing the roles (you did) and also with a group called CallerPrincipal containing your UserPrincipal. The getCallerPrincipal method is supposed to return the Principal contained by the group called "CallerPrincipal". Maybe you did it but I didn't see it in your commit method.

                  But, I did that and it still doesn't work. For most people's problem it seems to be the solution, but not for mine. starksm, I suppose my commit method is fine, and when I check my subject I get this:

                  TestPrincipal: Name--> Tang class: securite.TestPrincipal
                  CallerPrincipal (members:TestPrincipal: Name--> Tang) class: org.jboss.security.SimpleGroup
                  Roles (members:JBossAdmin) class: org.jboss.security.SimpleGroup

                  So my subject seems to be successfully filled. Do you have an other idea why I have this problem??

                  Excuse my english!

                  • 6. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                    starksm64

                    Look at the jboss codebase for the org.jboss.security.auth.spiUsersRolesLoginModule and its base class org.jboss.security.auth.spi.UsernamePasswordLoginModule in the jboss-3.2/security/src/main tree for the commit behavior used with the example testcase. It will take 24 hours for this code to be available via anonymous cvs, try it at that time.

                    • 7. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                      phantom

                      Thank you.
                      I'll test changes...
                      But could you explain some interesting lines from sources?

                       ClassLoader loader = Thread.currentThread().getContextClassLoader();
                       Class clazz = loader.loadClass(identityClassName);
                       Class[] ctorSig = {String.class};
                       Constructor ctor = clazz.getConstructor(ctorSig);
                       Object[] ctorArgs = {username};
                       p = (Principal) ctor.newInstance(ctorArgs);
                      

                      Why i can't do like this?
                       Class clazz = Class.forName(...);
                       Constructor ctor = clazz.getConstructor(new Class[]{String.class});
                       p = (Principal) ctor.newInstance(new Object[]{username});
                      

                      Why I must use class loader to load a class?

                      Thank you a lot...

                      • 8. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                        phantom

                        Let me add some information. It may be helpful.

                        We used some time ago weblogic and now we are "translating" our code to JBOSS. And there is one important point - SECURITY. We are tring to remake security using JAAS tchnology.... And we used java.security.LoginModule to create new LoginModule for JBOSS but not UsernamePasswordLoginModule (May be we are on a wrong way?). And this is our LoginModule:

                        package XXXXXX.security;
                        
                        import org.jboss.logging.Logger;
                        import org.jboss.security.NestableGroup;
                        
                        import javax.security.auth.login.LoginException;
                        import javax.security.auth.Subject;
                        import javax.security.auth.spi.LoginModule;
                        import javax.security.auth.callback.*;
                        import java.util.Map;
                        import java.util.Set;
                        import java.util.Iterator;
                        import java.io.IOException;
                        import java.security.acl.Group;
                        import java.security.Principal;
                        
                        public class XXXXXXLoginModule implements LoginModule
                        {
                         private Subject subject = null;
                         private CallbackHandler callbackHandler = null;
                         private Map sharedState=null;
                         private Map options=null;
                         private boolean useFirstPass = false;
                         private boolean loginOK = false;
                        
                         private UserPrincipal userPrincipal = null;
                        
                         private static final Logger log = Logger.getLogger(XXXXXXLoginModule.class);
                        
                         public void initialize(Subject subject, CallbackHandler callbackHandler,
                         Map sharedState, Map options)
                         {
                         this.subject = subject;
                         this.callbackHandler = callbackHandler;
                         this.sharedState = sharedState;
                         this.options = options;
                         String passwordStacking = (String) options.get("password-stacking");
                         if( passwordStacking != null && passwordStacking.equalsIgnoreCase("useFirstPass") )
                         useFirstPass = true;
                        
                         log.debug("initialized! caller = "+callbackHandler.getClass().getName());
                         log.debug("subject = "+subject.getClass().getName());
                         }
                        
                         public boolean login() throws LoginException
                         {
                         String[] info = getUserAndPassword();
                         userPrincipal = new UserPrincipal(info[0]);
                         loginOK = info[0]==null?false:info[0].equals(info[1]);
                         log.debug("loginOK="+loginOK);
                         return loginOK;
                         }
                        
                         public boolean abort() throws LoginException
                         {
                         return true;
                         }
                        
                         public boolean commit() throws LoginException
                         {
                         if(loginOK)
                         {
                         Set principals = subject.getPrincipals();
                         principals.add(userPrincipal);
                        
                         for (Iterator it = principals.iterator(); it.hasNext();)
                         {
                         Principal principal = (Principal) it.next();
                        
                         }
                        
                         Role role = new Role("Roles");
                         role.addMember(userPrincipal);
                         principals.add(role);
                         log.debug("Added "+userPrincipal+" class: "+userPrincipal.getClass().getName()+" to group "+role.getName());
                         return true;
                         }
                         else
                         {
                         return false;
                         }
                         }
                        
                         public boolean logout() throws LoginException
                         {
                         subject.getPrincipals(UserPrincipal.class).remove(userPrincipal);
                         return true;
                         }
                        
                         private String[] getUserAndPassword() throws LoginException
                         {
                         String[] ret = new String[2];
                         if(callbackHandler==null)
                         {
                         throw new LoginException("Callback handler = null");
                         }
                         NameCallback nameCallback = new NameCallback("Name:","guest");
                         PasswordCallback passwordCallback = new PasswordCallback("Password:",false);
                         try
                         {
                         callbackHandler.handle(new Callback[]{nameCallback,passwordCallback});
                         String name = nameCallback.getName();
                         String password = null;
                         char[] tmpPassword = passwordCallback.getPassword();
                         char[] tmpPassword2 = new char[tmpPassword.length];
                         System.arraycopy(tmpPassword,0,tmpPassword2,0,tmpPassword.length);
                         password=new String(tmpPassword2);
                         ret[0]=name;
                         ret[1]=password;
                         }
                         catch (IOException e)
                         {
                         throw new LoginException("Can't handle callbacks: "+e);
                         }
                         catch (UnsupportedCallbackException e)
                         {
                         throw new LoginException("Can't handle callbacks: "+e);
                         }
                         return ret;
                         }
                        
                         protected Group createGroup(String name, Set principals)
                         {
                         Group roles = null;
                         Iterator iter = principals.iterator();
                         while( iter.hasNext() )
                         {
                         Object next = iter.next();
                         if( (next instanceof Group) == false )
                         continue;
                         Group grp = (Group) next;
                         if( grp.getName().equals(name) )
                         {
                         roles = grp;
                         break;
                         }
                         }
                         // If we did not find a group create one
                         if( roles == null )
                         {
                         roles = new Role(name);
                         principals.add(roles);
                         }
                         return roles;
                         }
                        
                        
                        }
                        


                        Subject was created corretly(?). I check this by:
                        <%
                        Subject subject = SecurityAssociation.getSubject();
                        Iterator it = subject.getPrincipals().iterator();
                         out.println("subject!");
                         while (it.hasNext())
                         {
                         Object o = (Object) it.next();
                         out.println("object="+o+" ");
                         out.println("class="+o.getClass().getName()+"<br>");
                         }
                        %>
                        

                        result:
                        subject: object=qwe class=XXXXXX.security.UserPrincipal
                        object=Roles(members) class=XXXXXX.security.Role
                        


                        Where is the problem? Why after "request.getPrincipal()" I get "SimplePrincipal"?

                        P.S. XXXXXX - our packages


                        • 9. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                          phantom

                           

                          "starksm" wrote:
                          Look at the jboss codebase for the org.jboss.security.auth.spiUsersRolesLoginModule and its base class org.jboss.security.auth.spi.UsernamePasswordLoginModule in the jboss-3.2/security/src/main tree for the commit behavior used with the example testcase. It will take 24 hours for this code to be available via anonymous cvs, try it at that time.


                          I tested new code from CVS (UsernameLoginModule). Principals in Subject are correct, but request.getPrincipal() return the same: SimplePrincipal:((

                          Please, help me....

                          • 10. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                            starksm64

                            You have to provide your custom Principal as the "CallerPrincipal" binding in the Subject. The testcase for the custom principal uses a login config of:

                             <application-policy name = "jaas-test">
                             <authentication>
                             <login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule"
                             flag = "required">
                             <module-option name = "unauthenticatedIdentity">anonymous</module-option>
                             <module-option name = "principalClass">org.jboss.test.security.ejb.CustomPrincipalImpl</module-option>
                             </login-module>
                             </authentication>
                             </application-policy>
                            


                            a users.properties:
                            scott=echoman
                            stark=javaman
                            jduke=theduke
                            jdukeman=anotherduke
                            invoker=invoker
                            


                            a roles.properties:
                            scott=Echo
                            jduke=Echo
                            jduke.CallerPrincipal=callerJduke
                            jdukeman=Role2,Role3
                            jdukeman.CallerPrincipal=callerJdukeman
                            


                            The login of jduke with the CallerPrincipal callerJduke will see a CustomPrincipalImpl

                            • 11. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                              tang

                              I still doesn't work... Here is my code and all I did, this is only a test so my LoginModule is quite ridiculous...

                              First my LoginModule:

                              package securite;


                              import....
                              ....


                              public class TestLoginModule extends UsernamePasswordLoginModule
                              {

                              private TestPrincipal caller;

                              public boolean login() throws LoginException {
                              if(super.login()) {
                              caller=new TestPrincipal(getUsername(),getUsersPassword(),"CallerPrincipal");
                              return true;
                              }
                              return false;
                              }

                              public boolean commit() throws LoginException {
                              if(subject != null)
                              {
                              Set principals = subject.getPrincipals();
                              if(principals != null)
                              {
                              principals.add((TestPrincipal) caller);
                              Group callerPrincipal = new SimpleGroup("CallerPrincipal");
                              callerPrincipal.addMember((TestPrincipal) caller);
                              principals.add(callerPrincipal);
                              // Set the roles for this principal in the 'Roles' group
                              Group group = getGroup(principals,"Roles");
                              group.addMember(new SimplePrincipal("JBossAdmin"));
                              principals.add(group);

                              return true;
                              }

                              }
                              return false;

                              }

                              private static SimpleGroup getGroup(Set principals, String groupName) {
                              Iterator it = principals.iterator();
                              while (it.hasNext()) {
                              java.security.Principal principal =
                              (java.security.Principal) it.next();
                              if (principal instanceof SimpleGroup
                              && groupName.equals(principal.getName())) {
                              return (SimpleGroup) principal;
                              }
                              }
                              return new SimpleGroup(groupName);
                              }


                              //I don't use this method but I need it to extend UsernamePasswordLoginModule

                              protected Group[] getRoleSets() throws LoginException {
                              try {
                              String roles = "JBossAdmin";
                              Group[] groups = {new SimpleGroup("Roles")};
                              log.info("Getting roles for user="+getUsername());
                              SimplePrincipal role = new SimplePrincipal(roles);
                              log.info("Found role="+roles);
                              groups[0].addMember(role);
                              return groups;
                              }
                              catch(Exception e)
                              {
                              log.error("Failed to obtain groups for user="+getUsername(), e);
                              System.out.println("error");
                              throw new LoginException(e.toString());
                              }
                              }

                              //to login, the password just have to equals the username
                              protected String getUsersPassword()
                              {
                              String password = getUsername();
                              return password;
                              }

                              }

                              I have also written my Custom Principal called securite.TestPrincipal which is quite like simpleprincipal except the fact there is a name, a password and a comment in it.
                              I put all that in a library which I put in server/default/lib
                              Then I change the login-config.xml file adding:

                              <application-policy name = "essai">

                              <login-module code="securite.TestLoginModule"
                              flag = "required" >
                              <module-option name="principalClass">securite.TestPrincipal</module-option>
                              </login-module>

                              </application-policy>


                              I do my test using a Servlet. To access this servlet I have to login using the basic method. I configured the web.xml and jboss.xml so that the LoginModule used is mine. Then I use the HttpRequest.getUserPrincipal and I get a SimplePrincipal :(. This Servlet is also a client of an ejb which returns the CallerPrincipal (another SimplePrincipal...) and the Subject in order to check it was successfully filled. I also use your validateCallerPrincipal method.
                              I think that's all I do. Is there something I forgot to do? Did I make something wrong? This code is very simple, maybe too simple but I thought it would work.


                              • 12. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                                starksm64

                                You don't appear to be setting the groups correctly. This fixed version works fine with my ejb testcase:

                                package org.jboss.test.security.ejb;
                                
                                import java.security.acl.Group;
                                import javax.security.auth.login.LoginException;
                                import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
                                import org.jboss.security.SimpleGroup;
                                import org.jboss.security.SimplePrincipal;
                                
                                /**
                                 * @author Scott.Stark@jboss.org
                                 * @version $Revision:$
                                 */
                                public class CustomPrincipalLoginModule extends UsernamePasswordLoginModule
                                {
                                
                                 private CustomPrincipalImpl caller;
                                
                                 public boolean login() throws LoginException
                                 {
                                 if (super.login())
                                 {
                                 caller = new CustomPrincipalImpl(getUsername());
                                 return true;
                                 }
                                 return false;
                                 }
                                
                                 protected Group[] getRoleSets() throws LoginException
                                 {
                                 try
                                 {
                                 // The declarative permissions
                                 Group roles = new SimpleGroup("Roles");
                                 // The caller identity
                                 Group callerPrincipal = new SimpleGroup("CallerPrincipal");
                                 Group[] groups = {roles, callerPrincipal};
                                 log.info("Getting roles for user=" + getUsername());
                                 // Add the Echo role
                                 roles.addMember(new SimplePrincipal("Echo"));
                                 // Add the custom principal for the caller
                                 callerPrincipal.addMember(caller);
                                 return groups;
                                 }
                                 catch (Exception e)
                                 {
                                 log.error("Failed to obtain groups for user=" + getUsername(), e);
                                 throw new LoginException(e.toString());
                                 }
                                 }
                                
                                 protected String getUsersPassword()
                                 {
                                 return "theduke";
                                 }
                                
                                }
                                


                                10:23:01,353 INFO [CustomPrincipalLoginModule] Getting roles for user=jduke
                                10:23:01,383 INFO [CustomPrincipalBean] validateCallerPrincipal, type=class org.jboss.test.security.ejb.CustomPrincipalImpl, loader=org.jboss.mx.loading.UnifiedClassLoader3@1280492{ url=file:/C:/cvs/JBoss3.2/jboss-3.2/build/output/jboss-3.2.4RC1/server/default/tmp/deploy/tmp54434security-jaas.jar,addedOrder=37}
                                10:23:01,383 INFO [CustomPrincipalBean] caller=jduke, class=class org.jboss.test.security.ejb.CustomPrincipalImpl


                                • 13. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                                  starksm64

                                  I added a test of getting the user principal from the web request and it did have a problem with returning the customer CallerPrincipal value. This has been fixed for the 3.2.4RC1 release.

                                  The code changed was in the org.jboss.web.tomcat.security.JBossSecurityMgrRealm class.

                                  • 14. Re: getting Custom Principal in EJBContext.getCallerPrincipa
                                    vitto

                                    I have the same problem.

                                    I created my CustomLoginModule which implements LoginModule interface,
                                    CustomPrincipal, CustomGroup (No JBoss Extention).

                                    public boolean commit() throws LoginException
                                    {
                                     this.userPrincipal = new CustomPrincipal("Username");
                                     this.subject.getPrincipals().add(this.userPrincipal);
                                     CustomGroup group = new CustomGroup("Roles");
                                     group.addMember(new CustomPrincipal("EmptyRole"));
                                     this.subject.getPrincipals().add(this.group);
                                    
                                     CustomGroup callerPrincipal = new CustomGroup("CallerPrincipal");
                                     callerPrincipal.addMember(this.userPrincipal);
                                     this.subject.getPrincipals().add(callerPrincipal);
                                    }
                                    



                                    When I called httpRequest.getUserPrincipal() on the Web, I got my CustomPrincipal.

                                    When I called sessionContext.getCallerPrincipal() in the EJB, I got SimplePrincipal, but should my CustomPrincipal.

                                    What is wrong????

                                    Thanks.



                                    1 2 Previous Next