9 Replies Latest reply on Jul 29, 2008 4:13 AM by hedinant

    looking for working example: custom login module extends Use

    anthonykrinsky

      I am looking for **working** sample code that extends UsernamePasswordLoginModule. The module I am trying to write needs to check for JBOSS authentication - if OK, proceed - and also do custom auth against a complex auth scheme which includes checking username, synchronizing users/groups, etc.

      The code that I have written is properly invoked upon login, and I have visibility into the J_USERNAME and J_PASSWORD fields, however, commit is never called and the user is never granted access to my portal.

      I have downloaded many examples from the internet but have been unable to get any of them to **work**. Probably my error, but there's no "cook-book" out there or samples that show how to do this unequivocally and repeatably.

      For demonstration purposes, simply returning "true" from the login() function is sufficient.

      Any help would be greatly appreciated.

      THANKS!

        • 1. Re: looking for working example: custom login module extends
          ragavgomatam

          I have a custom login module that is working fine with jboss 4.2.1 and jboss 5 Beta 3. Caveat is I extend the AbstractServerLoginModule NOT UsernamePasswordLoginModule. But this should not a big issue as UsernamePasswordLoginModule extends AbstractServerLoginModule. So enjoy...

          Code

          package com.jaas.module;
          
          import java.math.BigDecimal;
          import java.security.Principal;
          import java.security.acl.Group;
          import java.sql.SQLException;
          import java.util.Arrays;
          import java.util.Map;
          import java.util.Set;
          
          import javax.naming.Context;
          import javax.naming.InitialContext;
          import javax.naming.NamingException;
          import javax.security.auth.Subject;
          import javax.security.auth.callback.Callback;
          import javax.security.auth.callback.CallbackHandler;
          import javax.security.auth.callback.NameCallback;
          import javax.security.auth.callback.PasswordCallback;
          import javax.security.auth.callback.UnsupportedCallbackException;
          import javax.security.auth.login.LoginException;
          import javax.sql.DataSource;
          
          import org.apache.commons.dbutils.QueryRunner;
          import org.apache.commons.dbutils.handlers.ArrayHandler;
          import org.jboss.security.SimpleGroup;
          import org.jboss.security.SimplePrincipal;
          import org.jboss.security.auth.spi.AbstractServerLoginModule;
          
          public class CustomLoginModule extends AbstractServerLoginModule {
          
           private Principal principal;
          
           private String authSql;
          
           private String rolesSql;
          
           private String name = null;
          
           private String password = null;
          
           @SuppressWarnings("unused")
           private String ssn = null;
          
           public void initialize(Subject subject, CallbackHandler callbackHandler,
           Map sharedState, Map options) {
           super.initialize(subject, callbackHandler, sharedState, options);
           this.authSql = (String) options.get("authSql");
           this.rolesSql = (String) options.get("rolesSql");
           }
          
           public boolean login() throws LoginException {
          
           //this is a protected boolean in Super class
           loginOk = false;
           if (this.callbackHandler == null) {
           throw new LoginException("No callback handler is available");
           }
          
           Callback callbacks[] = new Callback[2];
          
           callbacks[0] = new NameCallback("Name :");
           callbacks[1] = new PasswordCallback("Password :", false);
          
           try {
           this.callbackHandler.handle(callbacks);
           name = ((NameCallback) callbacks[0]).getName().trim();
           password = new String(((PasswordCallback) callbacks[1])
           .getPassword());
          
           Object[] results = (Object[]) getQueryRunner().query(authSql,
           new Object[] { name, password }, new ArrayHandler());
          
           ssn = ((BigDecimal) results[3]).toString();
           principal = new CustomPrincipal((String) results[0],
           (String) results[1], ((BigDecimal) results[2]).toString(),
           ((BigDecimal) results[3]).toString());
          
           loginOk = true;
          
           } catch (java.io.IOException ioe) {
           ioe.printStackTrace();
           throw new LoginException(ioe.toString());
           } catch (UnsupportedCallbackException ce) {
           ce.printStackTrace();
           throw new LoginException("Error: " + ce.getCallback().toString());
           } catch (SQLException ex) {
           ex.printStackTrace();
           }
           return loginOk;
           }
          
           @Override
           protected Principal getIdentity() {
           return this.principal;
           }
          
           @Override
           protected Group[] getRoleSets() {
          
           Group roleGroup = new SimpleGroup("Roles");
           Group callerPrincipal = new SimpleGroup("CallerPrincipal");
           Group[] groups = { roleGroup, callerPrincipal };
          
           try {
           Object[] grps = (Object[]) getQueryRunner().query(rolesSql,
           new Object[] { name }, new ArrayHandler());
           for (int i = 0; i < grps.length; i++) {
           roleGroup.addMember(new SimplePrincipal(((String) grps)
           .trim()));
           }
           } catch (SQLException ex) {
           ex.printStackTrace();
           }
           callerPrincipal.addMember(this.principal);
           return groups;
           }
          
           public boolean commit() throws LoginException {
          
           boolean flag = false;
          
           if (!loginOk) {
           abort();
           throw new LoginException(
           "Error: Username Password failed to authenticate ");
           }
          
           if (loginOk) {
           Set<? super Principal> setOfPrincipals = subject.getPrincipals();
           setOfPrincipals.add(this.principal);
           setOfPrincipals.addAll(Arrays.asList(this.getRoleSets()));
           flag = true;
           } else {
           flag = false;
           }
           return flag;
           }
          
           public boolean logout() {
          
           this.subject.getPrincipals().remove(this.principal);
           subject = null;
           return true;
          
           }
          
           public boolean abort() {
          
           if ((subject != null) && (this.principal != null)) {
           Set setOfPrincipals = subject.getPrincipals();
           setOfPrincipals.remove(this.principal);
           }
           subject = null;
           this.principal = null;
           return true;
          
           }
          
           private Context getContext() throws NamingException {
           return new InitialContext();
           }
          
           private DataSource getDataSource() {
           DataSource ds = null;
           try {
           ds = (DataSource) getContext().lookup("java:jdbc/OracleDS");
           } catch (NamingException ne) {
           ne.printStackTrace();
           }
           return ds;
           }
          
           private QueryRunner getQueryRunner() {
           return new QueryRunner(getDataSource());
           }
          
           }
          
          
          


          My Custom Principal

          Code

          package com.jaas.module;
          
          import java.security.Principal;
          
          public class CustomPrincipal implements Principal {
          
           private String firstName;
          
           private String lastName;
          
           private int age;
          
           private int ssn;
          
           public String getName() {
           String name = "";
           name = this.lastName != null ? this.firstName + " " + this.lastName
           : this.firstName;
           return name;
           }
          
           public String getFirstName() {
           return this.firstName;
           }
          
           public String getLastName() {
           return this.lastName;
           }
          
           public int getAge() {
           return this.age;
           }
          
           private void setFirstName(String firstName) {
           this.firstName = firstName;
           }
          
           private void setLastName(String lastName) {
           this.lastName = lastName;
           }
          
           private void setAge(String age) {
           this.age = Integer.parseInt(age);
           }
          
           public CustomPrincipal(String fName, String lName, String age, String ssn) {
           setFirstName(fName.trim());
           if (lName != null)
           setLastName(lName.trim());
           setAge(age.trim());
           setSsn(ssn.trim());
           }
          
           public CustomPrincipal(String name) {
           setFirstName(name.trim());
           }
          
           public int getSsn() {
           return this.ssn;
           }
          
           public void setSsn(String ssn) {
           this.ssn = Integer.parseInt(ssn);
           }
          
          }
          


          • 2. Re: looking for working example: custom login module extends
            kidda

            How to deploy this custom login module? Which jar file should it become part of? Should it be part of applicartion ear file?

            -Kidda

            • 3. Re: looking for working example: custom login module extends
              ragavgomatam

              Nope...Seperate jar file...Put it in the $JBOSS/server/lib directory OR add it to the classpath in the run.sh/run.bat...It picks ity up from there

              • 4. Re: looking for working example: custom login module extends
                saleem.khan

                Hi Kidda,

                Can you give me the configuration of this login module.
                Where i have to define this login module.

                I am using Jboss federated SSO with two application. when i define say DemoLoginProvider given by Jboss federated SSO it doesn't call this provider for login it searches for users.properties and roles.properties.

                If you give me your congiguration for custom login module this will help me to congigure my login module.


                Thanks
                Saleem


                • 5. Re: looking for working example: custom login module extends
                  rsanka

                  Ragav: Are you able to get ejbContext.getCallerPrincipal to return your CustomPrincipal ?

                  For example:

                  @Stateless
                  public class MyStatelessBean implements IMyStatelessBean
                  {
                   @Resource
                   SessionContext ejbContext;
                  
                   public void testMethod()
                   {
                   MyCustomPrincipal principal = (MyCustomPrincipal) ejbContext.getCallerPrincipal();
                   //I get a class cast exception here
                   }
                  }

                  My login-config.xml does specify a principalClass module-option to my CustomLoginModule.

                  Interestingly though - in a servlet - request.getUserPrincipal() returns the correct MyCustomPrincipal as expected.

                  Thanks

                  Ramakrishna

                  • 6. Re: looking for working example: custom login module extends
                    rsanka

                    I think I found the answer to my problem: (thanks to JBoss test suite!)
                    I was missing a SecurityDomain annotation on my session beans.

                    @Stateless
                    @SecurityDomain("MyCustomSecurityDomain")
                    public class MyStatelessBean implements IMyStatelessBean
                    {
                     @Resource
                     SessionContext ejbContext;
                    
                     public void testMethod()
                     {
                     MyCustomPrincipal principal = (MyCustomPrincipal) ejbContext.getCallerPrincipal();
                     //I get a class cast exception here
                     }
                    }


                    • 7. Re: looking for working example: custom login module extends
                      hedinant

                       

                      "ragavgomatam" wrote:
                      Nope...Seperate jar file...Put it in the $JBOSS/server/lib directory OR add it to the classpath in the run.sh/run.bat...It picks ity up from there


                      You sure?
                      looks like it pick it from my project ear. Or may it not work as good ?

                      • 8. Re: looking for working example: custom login module extends
                        hedinant

                        And ...

                        May i not define a new security domain, but reconfigure JBossWS

                        May this be the source of strange SimplePrincipal instead of my own.

                        I wirote a commit method as you example, but still get the SimplePrincipal ...

                        • 9. Re: looking for working example: custom login module extends
                          hedinant

                          Finaly i find my mistake.

                          "CallerPrinciple" is a key