7 Replies Latest reply on Nov 9, 2012 12:58 PM by Derek Lee

    LDAP Authentication and Database Authorization

    Derek Lee Newbie

      Hi experts ,

       

      As the title says I am trying to authenticate user from LDAP and get the roles from the database.

      I am using JBoss 7.1.1 As and picketlink 2.1.5.

       

      My IDP configuration, I have ldap setup like this, (standalone.xml under $jboss_installation/standalone/configuration)

       

      <security-domain name="idp" cache-type="default">

        <authentication>

            <login-module code="org.jboss.security.auth.spi.LdapLoginModule" flag="required">

                <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>

                <module-option name="java.naming.provider.url" value="ldap://xxx:xxx"/>

                <module-option name="java.naming.security.authentication" value="simple"/>

                <module-option name="bindDN" value="xxx"/>

                <module-option name="bindCredential" value="xxx"/>

                <module-option name="baseCtxDN" value="DC=xxx,DC=xxx,DC=com"/>

                <module-option name="baseFilter" value="(sAMAccountName={0})"/>

                <module-option name="rolesCtxDN" value="DC=xxx,DC=xxx,DC=com"/>

                <module-option name="roleFilter" value="(member={0})"/>

                <module-option name="roleAttributeID" value="cn"/>

                <module-option name="searchScope" value="ONELEVEL_SCOPE"/>

                <module-option name="allowEmptyPasswords" value="false"/>

            </login-module>

        </authentication>

        <audit>

            <provider-module code="org.picketlink.identity.federation.core.audit.PicketLinkAuditProvider"/>

        </audit>

      </security-domain>

       

      My SP, (picketlink.xml under \WEB-INF\)

       

      <PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">

          <PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"

              ServerEnvironment="tomcat" BindingType="REDIRECT" RelayState="someURL">

              <IdentityURL>${idp.url::http://localhost:8080/idp/}</IdentityURL>

              <ServiceURL>${myapp.url::http://localhost:8080/myapp/}</ServiceURL>

          </PicketLinkSP>

       

          <Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">

              <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />

              <Handler class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />

            <Handler class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler">

              <Option Key="ROLE_GENERATOR" Value="CustomRoleGenerator"/>

            </Handler>

          </Handlers>   

      </PicketLink>

       

      I also have CustomRoleGenerator.java

       

      public class CustomRoleGenerator implements RoleGenerator

      {

         public List<String> generateRoles(Principal principal)

         {

            // TODO : Replace code below to call database to get the roles.

            // but for now returns the dummy roles.

       

            ArrayList<String> roleList = new ArrayList<String>();

            roleList.add("user");

            roleList.add("manager");

            return roleList;

         }

      }

       

      The error that I am getting is,

      PLFED000092: Null Value: Destination is null, basically the role is null in this case. I traced and this CustomRoleGenerator doesn't get called.

       

      I am questionning myself if CustomRoleGenerator should be packaged at the SP level or IDP level ? Afterall it looks like you can also define custom handlers in IDP.

       

      Any comments or any direction can be very helful

       

      Thanks in advance,

      Derek.

        • 1. Re: LDAP Authentication and Database Authorization
          Derek Lee Newbie

          Ooops looks like I am using the wrong handler key, but after I changed from ROLE_GENERATOR to ATTRIBUTE_MANAGER still not working

           

          RolesGenerationHandler.java (From picketlink-core-2.1.5.Final-sources.jar)

           

          @Override
          public void initHandlerConfig(SAML2HandlerConfig handlerConfig) throws ConfigurationException {
              super.initHandlerConfig(handlerConfig);
              String roleGeneratorString = (String) this.handlerConfig.getParameter(GeneralConstants.ATTIBUTE_MANAGER);
              this.insantiateRoleValidator(roleGeneratorString);
          }
          • 2. Re: LDAP Authentication and Database Authorization
            Derek Lee Newbie

            I guess I am all bymyself in this long journey.  I manage to fix one problem but still not getting ServiceProviderBaseProcessor to propagate the RolegenerationHandler.handleRequestType(...).

             

            One thing I had to fix is it's missing bouncycastle dependency, you can follow this link to set it up if you are missing.

            https://community.jboss.org/thread/175395

             

            After that you need to include this in your module.xml dependency of picketlink.

             

            $jboss_installed_directory/modules/org/picketlink/main/

             

            add

             

            <module name="org.bouncycastle"/>

            • 3. Re: LDAP Authentication and Database Authorization
              Teemu K Newbie

              I had the same issue with the quickstart applications and with following kind of LDAP login-module configuration:

               

                                      <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required">
                                          <module-option name="java.naming.provider.url" value="ldap://XX:389"/>
                                          <module-option name="java.naming.security.authentication" value="simple"/>
                                          <module-option name="bindDN" value="cn=XX"/>
                                          <module-option name="bindCredential" value="XX"/>
                                          <module-option name="baseCtxDN" value="ou=People,dc=XX,dc=com"/>
                                          <module-option name="baseFilter" value="(uid={0})"/>
                                          <module-option name="rolesCtxDN" value="ou=groups,dc=XX,dc=com"/>
                                          <module-option name="roleFilter" value="(uniqueMember={0})"/>
                                          <module-option name="roleNameAttributeID" value="cn"/>
                                          <module-option name="roleAttributeIsDN" value="true"/>
                                      </login-module>
              
              

              I was able to solve the issue by replacing roleFilter value '(uniqueMember={0})' with '(uniqueMember={1})'. The problem was that when using '{0}' only the uid attribute of the user was populated in the search string. Using '{1}' will use the whole DN. This behavior is documented in the LdapExtLoginModule configuration reference here: http://docs.jboss.org/jbosssecurity/docs/6.0/security_guide/html/Login_Modules.html#sec-LdapExtLoginModule.

              • 4. Re: LDAP Authentication and Database Authorization
                Derek Lee Newbie

                Hi Teemu,

                 

                Thanks for the contribution, but I am not having a problem authenticating but authorizing user wth custom roles.

                I have tested IDP with LDAP, database and with property files containg authorized users and works fine, the problem is that Picketlink doesn't look like it's propagating the roles read by the IDP to SP.

                 

                I might think there is a bug in picketlink for passing the roles back to SP.  Still no clue.

                 

                Thanks,
                Derek.

                • 5. Re: LDAP Authentication and Database Authorization
                  Josef Cacek Newbie

                  IMHO The correct way is to use a custom login module on IDP side. It would be nice if the DatabaseServerLoginModule is able  to map additional roles for already authenicated Subject - i.e. without doing authentication itself.

                   

                  Sample login module for role mapping:

                   

                  package org.jboss.test;
                  
                  import java.security.Principal;
                  import java.security.acl.Group;
                  import java.util.Iterator;
                  import javax.security.auth.login.LoginException;
                  import org.jboss.security.SimpleGroup;
                  import org.jboss.security.SimplePrincipal;
                  import org.jboss.security.auth.spi.AbstractServerLoginModule;
                  
                  public class RoleMappingLoginModule extends AbstractServerLoginModule {
                  
                      @Override
                      public boolean login() throws LoginException {
                          return super.loginOk = true;
                      }
                  
                      @Override
                      protected Principal getIdentity() {
                          //We have an authenticated subject
                          Iterator<? extends Principal> iter = subject.getPrincipals().iterator();
                          while (iter.hasNext()) {
                              Principal p = iter.next();
                              if (p instanceof Group == false)
                                  return p;
                          }
                          return null;
                      }
                  
                      @Override
                      protected Group[] getRoleSets() throws LoginException {
                          Group rolesGroup = new SimpleGroup("Roles");
                          rolesGroup.addMember(new SimplePrincipal("manager"));
                          rolesGroup.addMember(new SimplePrincipal("sales"));
                          rolesGroup.addMember(new SimplePrincipal("employee"));
                          return new Group[] { rolesGroup };
                      }
                  }
                  
                  

                   

                  and add it to your login module stack in the idp security-domain configuration in the JBoss AS:

                   

                  <security-domain name="idp" cache-type="default">
                            <authentication>
                                      <login-module code="YourLdapLM" flag="required">
                                                ...
                                      </login-module>
                                      <login-module code="org.jboss.test.RoleMappingLoginModule" flag="required" />
                            </authentication>
                  </security-domain>
                  
                  

                   

                  Other possibility is the custom Picketlink RoleGenerator:

                   

                  package org.jboss.test;
                  
                  import java.security.Principal;
                  import java.util.ArrayList;
                  import java.util.List;
                  import org.picketlink.identity.federation.core.interfaces.RoleGenerator;
                  
                  public class CustomRoleGenerator implements RoleGenerator {
                  
                      public List<String> generateRoles(Principal principal) {
                          List<String> userRoles = new ArrayList<String>();
                          userRoles.add("manager");
                          userRoles.add("sales");
                          userRoles.add("employee");
                          return userRoles;
                      }
                  }
                  
                  

                  and then add RoleGenerator attribute to PicketLinkIDP element in the picketlink.xml (idp.war):

                   

                  <PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
                            <PicketLinkIDP xmlns="urn:picketlink:identity-federation:config:2.1" RoleGenerator="org.jboss.test.CustomRoleGenerator">
                                      <IdentityURL>${idp.url::http://localhost:8080/idp/}</IdentityURL>
                                      <Trust>
                                                <Domains>localhost,jboss.com,jboss.org,amazonaws.com</Domains>
                                      </Trust>
                            </PicketLinkIDP>
                            <Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">
                                      <Handler
                                                class="org.picketlink.identity.federation.web.handlers.saml2.SAML2IssuerTrustHandler" />
                                      <Handler
                                                class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
                                      <Handler
                                                class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
                                      <Handler
                                                class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />
                            </Handlers>
                            <!-- 
                                      The configuration bellow defines a token timeout and a clock skew. Both configurations will be used during the SAML Assertion creation.
                                      This configuration is optional. It is defined only to show you how to set the token timeout and clock skew configuration. 
                             -->
                            <PicketLinkSTS xmlns="urn:picketlink:identity-federation:config:1.0" TokenTimeout="5000" ClockSkew="0">
                                      <TokenProviders>
                                                <TokenProvider
                                                          ProviderClass="org.picketlink.identity.federation.core.saml.v1.providers.SAML11AssertionTokenProvider"
                                                          TokenType="urn:oasis:names:tc:SAML:1.0:assertion"
                                                          TokenElement="Assertion" TokenElementNS="urn:oasis:names:tc:SAML:1.0:assertion" />
                                                <TokenProvider
                                                          ProviderClass="org.picketlink.identity.federation.core.saml.v2.providers.SAML20AssertionTokenProvider"
                                                          TokenType="urn:oasis:names:tc:SAML:2.0:assertion"
                                                          TokenElement="Assertion" TokenElementNS="urn:oasis:names:tc:SAML:2.0:assertion" />
                                      </TokenProviders>
                            </PicketLinkSTS>
                  </PicketLink>
                  
                  

                   

                  Thats all. Both ways should work, but I would prefer the LoginModule one in this case.

                   

                  Custom classes (LoginModule or RoleGenerator) should be placed under idp.war WEB-INF/classes (in the correct package folder) or as a jar file they can live in WEB-INF/lib.

                   

                  The sample classes are in my GitHub playground - https://github.com/kwart/test-app/tree/picketlink-role-mapping

                   

                  Message was edited by: Josef Cacek

                  • 6. Re: LDAP Authentication and Database Authorization
                    Adrian Chia Newbie

                    I am facing a similar problem as well, basically I am trying to have multiple SPs authenticate with single IDP. I have my IDP authenticate against LDAP and each of my SPs has different set of roles stored in the database. What is the appropriate way to only do authentication on IDP and only authorization on SP?

                    • 7. Re: LDAP Authentication and Database Authorization
                      Derek Lee Newbie

                      Hi Adrian,

                       

                      Unfortunately I was not able to solve this issue using picketlink, having muliple SPs with it own rolegenerator didn't work.

                      I am not sure if I miss something but the solution provided by Josef is "Authorize and authenticate from IDP", I need "Authorize from one IDP and authenticate from multiple SPs".

                       

                      If you look at the picketlink documentation, (https://docs.jboss.org/author/display/PLINK/RolesGenerationHandler).

                      You will notice that ATTRIBUTE_MANAGER is within the scope of IDP, your SP cannot use this if I am reading the document correctly, and this picketlink document is outdated by the way. (i.e. don't use picketlink-handlers.xml but picketlink.xml, in ver 2, they consolidate all xml into one).

                       

                      In the end, I ended up building my own picketlink , it's not that complicated, just need to find the time.

                      You really need some jar file that authenticate given user against LDAP then each of your SP uses this module to authorize, simple as 1 2 3

                       

                      I will dig more hopefully I can get it to work one day, but for now I give up, I spent too much time going through their source code.

                       

                      Derek.