8 Replies Latest reply on Sep 21, 2007 8:07 PM by D D

    Custom JAAS login module

    Carlos Augusto Grahl Newbie

      Hello,

      I'm new to JBoss Portal, and i'm need to authenticate using my own user database. For testing purposes, i made a very simple Jaas login module. It so simple that it not even authenticates! :-) The login() method always returns true.
      I'm using it just to learn what configuration must be done on the portal to use it.

      Here is my code:

      public class TestLoginModule implements LoginModule {
      
       private Subject subject;
      
       private CallbackHandler callbackHandler;
      
       private Map sharedState;
      
       private Map options;
      
       private String username = null;
      
       private boolean loginOk = false;
      
       private SimplePrincipal usernamePrincipal;
      
       private Object password;
      
       public boolean abort() throws LoginException {
       // TODO Auto-generated method stub
       return false;
       }
      
       public boolean commit() throws LoginException {
       System.out.println("commit()");
       if (!loginOk)
       return false;
      
       usernamePrincipal = new SimplePrincipal(username);
       password = new String("idontusethis");
      
       subject.getPrincipals().add(usernamePrincipal);
       subject.getPublicCredentials().add(password);
      
       this.username = null;
       return true;
       }
      
       public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
       System.out.println("initialize(). CallbackHandler: " + callbackHandler.toString());
       this.subject = subject;
       this.callbackHandler = callbackHandler;
       this.sharedState = sharedState;
       this.options = options;
       }
      
       public boolean login() throws LoginException {
       System.out.println("login()");
       NameCallback namecallback = new NameCallback("Enter username");
       PasswordCallback passwordcallback = new PasswordCallback("Enter password", false);
      
       try {
       callbackHandler.handle(new Callback[] { namecallback, passwordcallback });
      
       username = namecallback.getName();
       password = new String(passwordcallback.getPassword());
      
       System.out.println("TODO\t" + this.getClass().getName() + ": Call Authentication Code.");
       System.out.println("Username: " + username + " password: " + password);
      
       loginOk = true;
       return true;
       } catch (UnsupportedCallbackException e) {
       } catch (java.io.IOException e) {
       } finally {
       }
      
       return false;
       }
      
       public boolean logout() throws LoginException {
       // TODO Auto-generated method stub
       return false;
       }
      
      }
      


      I changed the login-config.xml as follows:
      <login-module code="com.senior.security.jaas.TestLoginModule" flag="required">
       <module-option name="unauthenticatedIdentity">guest</module-option>
       <module-option name="userModuleJNDIName">java:/portal/UserModule</module-option>
       <module-option name="roleModuleJNDIName">java:/portal/RoleModule</module-option>
       <module-option name="userProfileModuleJNDIName">java:/portal/UserProfileModule</module-option>
       <module-option name="membershipModuleJNDIName">java:/portal/MembershipModule</module-option>
       <module-option name="additionalRole">Authenticated</module-option>
       <module-option name="password-stacking">useFirstPass</module-option>
       </login-module>
      


      When i try to login, using admin/admin or user/user, the console shows the corret username/password pair. But the browser shows the "HTTP Status 403 - Access to the requested resource has been denied" error page.
      I press the "back" button on the browser, and the user shows logged in (on the upper right corner of the screen). But I can't go to my dashboard.

      Did I miss some configuration step?

      What I must do to configure my own login module?

      Thank you

        • 1. Re: Custom JAAS login module
          Carlos Augusto Grahl Newbie

          Hello,

          I changed my code as below:

          public class TestLoginModule extends AbstractServerLoginModule {
          
           private String username = null;
          
           private Principal identity;
          
           private Object password;
          
          
           public boolean login() throws LoginException {
           System.out.println("login()");
           NameCallback namecallback = new NameCallback("Enter username");
           PasswordCallback passwordcallback = new PasswordCallback("Enter password", false);
          
           try {
           callbackHandler.handle(new Callback[] { namecallback, passwordcallback });
          
           username = namecallback.getName();
           password = new String(passwordcallback.getPassword());
          
           System.out.println("Username: " + username + " password: " + password);
          
           identity = new SimplePrincipal(username);
           loginOk = true;
           System.out.println("criou a identidade");
           return true;
           } catch (UnsupportedCallbackException e) {
           } catch (java.io.IOException e) {
           }
           return false;
          
           }
          
          
          @Override
           protected Principal getIdentity() {
           System.out.println("getIdentity()");
           return identity;
           }
          
          @Override
           protected Group[] getRoleSets() throws LoginException {
           System.out.println("getRolesSets()");
           Group rolesGroup = new SimpleGroup("Roles");
           rolesGroup.addMember(new SimplePrincipal("Authenticated"));
           rolesGroup.addMember(new SimplePrincipal("Administrators"));
           rolesGroup.addMember(new SimplePrincipal("Users"));
           rolesGroup.addMember(identity);
          
           return new Group[] { rolesGroup };
           }
          
          
          }


          Now I can authenticate Ok. But my admin/admin user is not on the admin role. How can i set that? As you can see above, i tried to set the "Administrators" role to the logged user, but it not worked. How to solve that?

          Thank you in advance

          • 2. Re: Custom JAAS login module
            Denis Marzadro Novice

            if not changed from 2.4 you have to add the "Admin" role not "administrator"

            • 3. Re: Custom JAAS login module
              Thomas Heute Master

              den74 you beated me ;)
              Correct, it's Admin still in 2.6

              • 4. Re: Custom JAAS login module
                Carlos Augusto Grahl Newbie

                That solve the problem! Thank you very much!

                • 5. Re: Custom JAAS login module
                  Brendan Farragher Newbie

                  For those who are experimenting with this for the first time - the login user (identity in the example above) must be created as a portal user account prior to login.

                  • 6. Re: Custom JAAS login module
                    D D Newbie

                    I guess this is a lot of work to authenticate. There are far simpler was to accomplish this. See some of the recent posts in regard to JAAS, also I do not believe you can get authorization this way. You have to use the j_security_check valve or hack on the code to make it work.

                    • 7. Re: Custom JAAS login module
                      shilpa K Newbie

                      Hi cgrahl,

                      Your first implementation of loginmodule looks correct. Then why did u replace that implementation with extending AbstractServerLoginModule? Whats wrong with the first code? Any particular reason for that?

                      Thanks
                      Shilpa

                      • 8. Re: Custom JAAS login module
                        D D Newbie

                        Here is some test code I hacked for creating a LoginModule using hibernate driven by my database. Obviously, this could be extended many ways.

                        Hope this gets you further along.

                        Creative


                        import java.util.*;

                        import javax.security.auth.*;
                        import javax.security.auth.spi.*;
                        import javax.security.auth.login.*;
                        import javax.security.auth.callback.*;
                        import com.xxxx.dao.jaas.Users;
                        import org.hibernate.*;
                        import javax.naming.*;

                        public class LoginModule implements LoginModule{

                        // initial state
                        private Subject subject;
                        private CallbackHandler callbackHandler;
                        private Map sharedState;
                        private Map options;

                        // configurable option
                        private boolean debug = false;

                        // username and password
                        private String username;
                        private String password;

                        //authentication status
                        boolean auth_success = true;
                        boolean commit_success = false;
                        boolean password_mismatch= false;
                        boolean invalid_user= false;

                        //User Credentials
                        private String _lastname = null;
                        private String _firstname = null;
                        private String _email = null;
                        private String _userid = null;

                        private MyEmailPrincipal emailPrincipal = null;
                        private MyFirstnamePrincipal fnamePrincipal = null;
                        private MyLastnamePrincipal lnamePrincipal = null;
                        private MyUserIdPrincipal userIdPrincipal = null;

                        /**
                        * Initialize this LoginModule.
                        *
                        *
                        *
                        * @param subject the Subject to be authenticated.
                        *
                        * @param callbackHandler a CallbackHandler for communicating
                        * with the end user (prompting for user names and
                        * passwords, for example).
                        *
                        * @param sharedState shared LoginModule state.
                        *
                        * @param options options specified in the login
                        * Configuration for this particular
                        * LoginModule.
                        */


                        public void initialize(Subject subject, CallbackHandler callbackHandler,
                        Map sharedState, Map options) {

                        System.out.println("MyJdbcLoginModule:InitMethod");

                        this.subject = subject;
                        this.callbackHandler = callbackHandler;
                        this.sharedState = sharedState;
                        this.options = options;


                        }

                        /**
                        * Authenticate the user by prompting for a user name and password.
                        *
                        *
                        *
                        * @return true in all cases since this LoginModule
                        * should not be ignored.
                        *
                        * @exception FailedLoginException if the authentication fails.
                        *
                        * @exception LoginException if this LoginModule
                        * is unable to perform the authentication.
                        */
                        public boolean login() throws LoginException {

                        System.out.println("MyJdbcLoginModule:login()");
                        // get the callback handler with the user name and password
                        if (callbackHandler == null)
                        throw new LoginException("MyJdbcLoginModule: No CallbackHandler Available");

                        Callback[] callbacks = new Callback[2];
                        callbacks[0] = new NameCallback("Username");
                        callbacks[1] = new PasswordCallback("Password: ", false);

                        try {
                        callbackHandler.handle(callbacks);
                        username = ((NameCallback)callbacks[0]).getName();
                        password = new String(((PasswordCallback)callbacks[1]).getPassword());

                        auth_success = validateUser(username, password);

                        if(!auth_success){
                        if(password_mismatch){
                        throw new LoginException("Invalid Password");
                        }else if(invalid_user){
                        throw new LoginException("Invalid Username");
                        }
                        }
                        return true;
                        } catch (java.io.IOException ioe) {
                        throw new LoginException(ioe.toString());
                        } catch (UnsupportedCallbackException use) {
                        throw new LoginException("MyJdbcLoginModule: Not Supported"+ use.getCallback().toString() );
                        }
                        }

                        /**
                        * This method is called if the LoginContext's
                        * overall authentication succeeded
                        * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
                        * succeeded).
                        *
                        *
                        * @exception LoginException if the commit fails.
                        *
                        * @return true if this LoginModule's own login and commit
                        * attempts succeeded, or false otherwise.
                        */
                        public boolean commit() throws LoginException {
                        System.out.println("MyJdbcLoginModule:commit()");
                        System.out.println(auth_success);

                        if (auth_success) {
                        commit_success= true;
                        fnamePrincipal = new MyFirstnamePrincipal(_firstname);
                        lnamePrincipal = new MyLastnamePrincipal(_lastname);
                        emailPrincipal = new MyEmailPrincipal(_email);
                        userIdPrincipal = new MyUserIdPrincipal(_userid);

                        System.out.println("Adding principals");

                        subject.getPrincipals().add(fnamePrincipal);
                        subject.getPrincipals().add(lnamePrincipal);
                        subject.getPrincipals().add(emailPrincipal);
                        subject.getPrincipals().add(userIdPrincipal);

                        } else {
                        commit_success = false;
                        }
                        return commit_success;
                        }

                        /**
                        * This method is called if the LoginContext's
                        * overall authentication failed.
                        * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
                        * did not succeed).
                        *
                        * If this LoginModule's own authentication attempt
                        * succeeded (checked by retrieving the private state saved by the
                        * login and commit methods),
                        * then this method cleans up any state that was originally saved.
                        *
                        *
                        *
                        * @exception LoginException if the abort fails.
                        *
                        * @return false if this LoginModule's own login and/or commit attempts
                        * failed, and true otherwise.
                        */
                        public boolean abort() throws LoginException {

                        System.out.println("MyJdbcLoginModule:abort()");
                        if (!auth_success) {
                        // authentication failure
                        username = null;
                        password = null;
                        this.subject.getPrincipals().clear();
                        return true;
                        }
                        return false;
                        }

                        /**
                        * Logout the user.
                        *
                        * This method removes the SamplePrincipal
                        * that was added by the commit method.
                        *
                        *
                        * @exception LoginException if the logout fails.
                        *
                        * @return true in all cases since this LoginModule
                        * should not be ignored.
                        */
                        public boolean logout() throws LoginException {
                        System.out.println("MyJdbcLoginModule:logout()");
                        this.username = null;
                        this.password = null;
                        this.subject.getPrincipals().clear();
                        return true;
                        }


                        /**
                        * This method does the actual authentication by validating in the database
                        * if the user exists and if the password matches or not.
                        *
                        */

                        public boolean validateUser(String username, String password){

                        try{

                        Context ctx = new InitialContext();
                        SessionFactory factory = (SessionFactory) ctx.lookup("java:/hibernate/SessionFactory");
                        Session sess = factory.openSession();

                        Query query = sess.createQuery("from Users as users where username = '" + username + "' and password = '" + password + "'");

                        List rList = query.list();

                        String _password = null;
                        System.out.println("Found " + rList.size() + " entrie(s) for this user.");

                        if(rList.size() > 0 ){
                        //the user exists in the database there auth_success=true
                        _password = ((Users)rList.get(0)).getPassword();
                        _lastname = ((Users)rList.get(0)).getLastname();
                        _firstname = ((Users)rList.get(0)).getFirstname();
                        _email = ((Users)rList.get(0)).getEmail();
                        _userid = new Integer(((Users)rList.get(0)).getUserid()).toString();


                        } else {
                        //if no results obtained means the user is not present in the database
                        auth_success = false;
                        invalid_user = true;
                        return auth_success;
                        }

                        //user exists and check if the password matches..

                        System.out.println(password + " equals " + _password);

                        if(!password.equals(_password)){
                        auth_success = false;
                        password_mismatch= true;
                        return auth_success;
                        }

                        }catch(Exception sqx){
                        System.err.println("MyJdbcLoginModule: Exception encountered while retrieving values");
                        System.err.println(sqx);
                        auth_success = false;
                        }finally {

                        }
                        System.out.println(auth_success);
                        return auth_success;
                        }
                        }