7 Replies Latest reply on Sep 11, 2009 9:13 AM by tmalatinszki

    LDAP Authentication

    kmali


      Hi I've implemented a simple LDAP authentication in a seam application.
      Currenty only a logon name and password authentication is possible.


      I would like add that only users who are member of a certain group can pass the authentication.


      How can I do this?



      This my code:



      import static org.jboss.seam.ScopeType.SESSION;
      
      import java.util.Hashtable;
      import java.util.List;
      
      import javax.ejb.Stateless;
      import javax.naming.AuthenticationException;
      import javax.naming.Context;
      import javax.naming.NamingException;
      import javax.naming.directory.DirContext;
      import javax.naming.directory.InitialDirContext;
      import javax.persistence.EntityManager;
      import javax.persistence.PersistenceContext;
      
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.security.Identity;
      
      import javax.naming.*;
      
      
      import javax.naming.*;
      
      @Stateless
      @Name("authenticator")
      public class AuthenticatorAction implements Authenticator
      {
         @In
         Identity identity;
         
         public boolean authenticate()
         {
           
           Hashtable authEnv = new Hashtable(11);
             
             String userName = identity.getUsername(); 
             String passWord = identity.getPassword();
             if (passWord=="")
                  return false;
             
       
             String ldapURL = "ldap://f2.enterprise";
             
             authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
                 authEnv.put(Context.PROVIDER_URL, ldapURL);
                 authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
                 authEnv.put(Context.SECURITY_PRINCIPAL, userName+"@Research");
                 authEnv.put(Context.SECURITY_CREDENTIALS, passWord);
                 
             try {
                  DirContext authContext = new InitialDirContext(authEnv);
                  return true;
                  
             } catch (AuthenticationException authEx) {
                  return false;
             
             } catch (NamingException namEx) {
                  return false;
                  
             }
        }
      } 




      Thanks for your help.



        • 1. Re: LDAP Authentication
          tmalatinszki

          You can use security:ldap-identity-store, here's how it works:


          First You have to configure it in your components.xml:


          <security:ldap-identity-store
          name="ldapIdentityStore"
          server-address="server.ad.myworld.com"
          server-port="389"
          first-name-attribute="givenName"
          last-name-attribute="sn"
          bind-DN="CN=SERVICEUSER,OU=Users,DC=server,DC=ad,DC=myworld,DC=com"
          bind-credentials="SERVICEUSERPASSWORD"
          user-DN-prefix="sAMAccountName="
          user-name-attribute="sAMAccountName"
          user-DN-suffix=",OU=Users,DC=server,DC=ad,DC=myworld,DC=com"
          user-context-DN="OU=Users,DC=server,DC=ad,DC=myworld,DC=com"
          role-DN-prefix="distinguishedName="
          role-name-attribute="distinguishedName"
          role-object-classes="group"
          role-DN-suffix=",OU=Groups,DC=server,DC=ad,DC=myworld,DC=com"
          role-context-DN="OU=Groups,DC=server,DC=ad,DC=myworld,DC=com"
          user-role-attribute="memberOf"
          user-object-classes="user" 
          role-attribute-is-DN="false"/>
          
          <security:identity-manager name="identityManager" identity-store="#{ldapIdentityStore}"/>



          You need to modify the paramaters according to Your LDAP server hierarchy, and You should use a SERVICEUSER to connect to LDAP server.


          In AuthenticatorAction use this code to get the groups of a specified user:


          @In
          IdentityManager identityManager;
          
          List<String> groups=identityManager.getImpliedRoles(identity.getUsername());



          The groups will contain all the LDAP group names where the user has membership.


          Let me know if it works!


          Regards,
          Tamas


          • 2. Re: LDAP Authentication
            kmali



            Thank you for your help.


            I don't want to read out the groupmemberships.
            I just want to check the Username, Password, and if the user is member of a certain
            group. The group name won't change...


            Is there a esay way to implement this with your code? Or is it must to read out the group memberships?


            PS:
            Please keep in mind that I use Seam 1.2 and JBOSS AS 4.0.5.

            • 3. Re: LDAP Authentication
              tmalatinszki

              If You want to check only one group without using security:ldap-identity-store here's a shortest way:


              String groupName="CN=GROUPNAME,OU=Groups,DC=server,DC=ad,DC=myworld,DC=com";
              String userDir="OU=Users,DC=server,DC=ad,DC=myworld,DC=com";
                               
              SearchControls constraints = new SearchControls();
              constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
              NamingEnumeration<SearchResult> result=authContext.search(userDir,"(&(objectClass=user)(sAMAccountName="+userName+")(memberOf="+groupName+"))",constraints);
                               
              if(result!=null&&result.hasMore()){
                 //user is member of the certain group 
              }



              Anyway it should be a better solution for You, because as far as I know Seam 1.2 not contains security:ldap-identity-store anyway.


              Regards,
              Tamas

              • 4. Re: LDAP Authentication
                kmali


                Thank you.


                I've tried to integrate this to my code, but it doesn't work.


                Could you show me how I can integrate your funktion in my code?
                (you can find my athentication method in the first post)


                thank you very much



                • 5. Re: LDAP Authentication
                  tmalatinszki

                  It's strange, because I used Your authentication method to test this code, and it worked fine. What was the error message?


                  Here's how I modified Your method:


                  try {
                     DirContext authContext = new InitialDirContext(authEnv);
                     String groupName="CN=GROUPNAME,OU=Groups,DC=server,DC=ad,DC=myworld,DC=com";
                     String userDir="OU=Users,DC=server,DC=ad,DC=myworld,DC=com";
                  
                     SearchControls constraints = new SearchControls();
                     constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
                     NamingEnumeration<SearchResult> result=authContext.search(userDir,"(&(objectClass=user)(sAMAccountName="+userName+")(memberOf="+groupName+"))",constraints);
                                                    
                     return (result!=null&&result.hasMore());
                  } catch (AuthenticationException authEx) {
                     return false;
                  } catch (NamingException namEx) {
                     return false;
                  }



                  Did You configured groupName and userDir parameters to match You LDAP server's directory structure? For example:


                  String groupName="CN=GROUPNAME,OU=Groups,DC=f2,DC=enterprise";
                  String userDir="OU=Users,DC=f2,DC=enterprise";



                  Regards,
                  Tamas

                  • 6. Re: LDAP Authentication
                    kmali


                    Yes I have configured groupname and userDir. But I have missed that the group is in another domain. (not in f2.enterprise)
                    I guess that it would be better to move the group, I hope that's possible.


                    Does this return a boolean value? (true or false)? :



                    return (result!=null&&result.hasMore());







                    • 7. Re: LDAP Authentication
                      tmalatinszki

                      Yes, it returns with a boolean type: it will be true, if result is not null and it has at least one element, so searching was successful (usually result contains only one record, because You are searching for one certain record where sAMAccountName equals the username, and it has a memberOf parameter with the certain group name).


                      If You want to check what was the result:


                      if(result!=null){
                         while(result.hasMore()){
                            SearchResult record=result.next();
                            System.out.println(record.getAttributes().get("sAMAccountName"));
                            //this way You can get all LDAP attributes You need
                         }
                      }
                      else{
                         System.out.println("NOT RESULTS");
                      }



                      Regards,
                      Tamas