6 Replies Latest reply on Jun 9, 2006 9:01 AM by Scott Stark

    Principal does not get pass to JBoss server

    Muhammad Umar Newbie

      I am NEW to JBOSS so please help !
      I am writting a custom Server Login Module called "CustomServerLoginModule". In its login method I am trying to getPrincipal from SecurityAssociation but it returns null.

      Any Help will be much appreciated !

      Here are the steps I took.

      1- Client Side - auth.conf

      adviceDomain {
       // jBoss LoginModule
       org.jboss.security.ClientLoginModule required
       ;
      
       // Put your login modules that need jBoss here
      };


      According to my understanding, ClientLoginModule takes the username and password and puts them in the org.jboss.security.SecurityAssociation class. AM I Correct ?

      2- Server Side - CustomServerLoginModule

      public class CustomServerLoginModule extends AbstractServerLoginModule
      {
       private Principal identity;
      
       public Principal getIdentity(){
       return identity;
       }
       public Group[] getRoleSets(){
       Group rolesGroup = new SimpleGroup( "Roles" );
       rolesGroup.addMember( new SimplePrincipal( "AdvisorRole" ) );
       return new Group[]{ rolesGroup };
       }
       public boolean login() throws LoginException {
       //It returns null here
       identity = org.jboss.security.SecurityAssociation.getPrincipal();
       if ( identity == null ){
       throw new LoginException( "The principal was not found in the SecurityAssociation." );
       }
      
       loginOk = true;
       return true;
       }
      
      };
      
      


      3- When I run this, I get the following error:
      javax.security.auth.login.LoginException: The principal was not found in the SecurityAssociation.

      AM I MISSING any step?
      Hint:
      Before on server side I was using UsersRolesLoginModule then it was working fine. I did not touch client and when I wrote CustomServerLoginModule, It is going to this login() method but getPrincipal() is returning null.

      Any help will be much appreciated ....... Thanks a lot.........

        • 1. Re: Principal does not get pass to JBoss server
          chris griffith Expert

          Your login module needs to follow JAAS standard and get the username and password from the CallbackHandler. The SecurityAssociation class is an internal class that should only be used by JBoss packages.

          let me know if have more questions, cgriffith

          • 2. Re: Principal does not get pass to JBoss server
            Muhammad Umar Newbie

            Thanks Chris for your Input. Can you please give me an idea how can I get Principal object which I am calling "identity" in my login() function of CustomServerLoginModule.

            I have created a CustomCallbackHandler on client side

            public class CustomCallbackHandler
             implements javax.security.auth.callback.CallbackHandler
            {
             private String username = null;
             private char[] password = null;
            
             public CustomCallbackHandler(String uname, char[] pass)
             {
             username=uname;
             password=pass;
             }
            
             public void handle(Callback[] callbacks)
             throws IOException, UnsupportedCallbackException
             {
             for ( int i = 0; i < callbacks.length; i++ )
             {
             Callback callback = callbacks;
            
             if ( callback instanceof NameCallback )
             {
             NameCallback ncb = (NameCallback) callback;
             ncb.setName( username );
             }
             else if ( callback instanceof PasswordCallback )
             {
             PasswordCallback pcb = (PasswordCallback) callback;
             pcb.setPassword( password );
             }
             else
             {
             System.out.println(
             "Unsupported callback: " +
             callback.getClass().getName() );
             throw new UnsupportedCallbackException( callback );
             }
             }
             }
             }


            This is How my Client Looks:

            public class AdviceClient
            {
             public static void main(String[] args)
             {
             String securityDomain= "adviceDomain";
             String username="advisor";
             char[] password="password".toCharArray();
            
             try{
             CallbackHandler callbackHandler = new CustomCallbackHandler(username,password);
             LoginContext lc=new LoginContext(securityDomain, callbackHandler);
             System.out.println("Created Login Context");
             lc.login();
             }catch(LoginException le){
             System.out.println("Login Failed");
             le.printStackTrace();
             }
            
             try
             {
            
             // Get a naming context
             InitialContext jndiContext = new InitialContext();
             System.out.println("Got context");
            
             // Get a reference to the Interest Bean
             Object ref = jndiContext.lookup("ejb/AdviceBean");
             System.out.println("Got reference");
            
             // Get a reference from this to the Bean's Home interface
             AdviceHome home = (AdviceHome)
             PortableRemoteObject.narrow(ref, AdviceHome.class);
             System.out.println("Got reference to Bean's Home Interface");
            
             // Create an Advice object from the Home interface
             Advice advisor = home.create();
             System.out.println("Got reference to Bean's Componenet Interface");
             // call the getMessage() method to get an Advice
             for(int i=0; i<4;i++){
             System.out.println("Advice is:");
             System.out.println(advisor.getMessage());
             }
             advisor.remove();
             }
             catch(Exception e)
             {
             System.out.println(e.toString());
             }
             }
            }
            

            I will be very thankful to you for your help....

            Thanks a lot......


            • 3. Re: Principal does not get pass to JBoss server
              chris griffith Expert

              Read the JBoss server guide chapter 8 at http://docs.jboss.org/jbossas/jboss4guide/r4/html/ch8.chapter.html and Java's JAAS stuff at http://java.sun.com/j2se/1.5.0/docs/guide/security/index.html. The short answer is you ask the CallbackHandler to handle (for example) the NameCallback and the PasswordCallback.

              This is basic JAAS stuff, so get a good grasp of that. Let us know when you need more help, cgriffith

              • 4. Re: Principal does not get pass to JBoss server
                lost traveller Newbie

                Ok thanks. Well I have remove the client login code from the servlet, and I have setup a realm using <security-constraint>. All seems to be working ok except that we use a custom principal.

                I have made the change as described ont eh wiki: http://wiki.jboss.org/wiki/Wiki.jsp?page=UsingCustomPrincpalsWith and all seems to work except that JBossSecurityMgrRealm creates an instance of SimplePrincipal which is then propagated to the context of the session beans. So it would appear you have to write a custom realm?
                There appears to be two approaches to using a custom principal with a realm 1) specify a custom principal in the config for org.apache.catalina.realm.JAASRealm 2) override JBossSecurityMgrRealm:
                I have tried both approaches to use our custom principal in the realm and neither seem to work correctly:

                1) create a new realm of org.apache.catalina.realm.JAASRealm and specify in the realm configuration to use MyPrincipal. However this does not work as because of this bug --> http://jira.jboss.com/jira/browse/JBWEB-36 and please see http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3897413

                2) create a new realm which extends org.jboss.web.tomcat.security.JBossSecurityMgrRealm and override the authenticate() method to use an instance of MyPrincipal() instead of SimplePrincipal(), however this does not work as the line of code

                SecurityAssociationActions.setPrincipalInfo(principal, digest, subject);

                seems to do some magic to remember the login details, but this is a protected class so you can't do that.

                So have i got this right? how do you use a custom principal in your realm?

                • 5. Re: Principal does not get pass to JBoss server
                  lost traveller Newbie

                  Ok I've fixed the problem, in JBossSecurityMgrRealm there is a protected method called getPrincipal(String) but it does not appear to be used when it should have. I have tested the following code and it fixes my problem, so it would appear to be a bug in JBoss, how do I get this checked in, i.e. fixed?
                  It is a fairly minor change and only one line to change, this is what it currectly in JBossSecurityMgrRealm:

                  public Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String qop, String realm,
                   String md5a2)
                   {
                  ....
                  /* 410*/ principal = new SimplePrincipal(username);
                  ...
                  }


                  this is my proposed fix:

                  public Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String qop, String realm,
                   String md5a2)
                   {
                  ....
                  /* 410*/ principal = getPrincipal(username);
                  ...
                  }