0
votes

I am trying to authenticate to an ldap server using spring security 3.1.

I have zero to very little knowledge of ldap.

In the old code , which is around 7years old. we have a servlet calling a login object as

  mypackage.Login login = new mypackage.Login("*******",
                          "389",
                          "none",
                          "cn",
                          "ou=Employees, ou=**, o=ny, c=US",
                          "ou=Employees, ou=**, o=ny, c=US",
                          v);
   String[] res = login.authenticate(username, password);

The Login code is as:

package mypackage;

import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import java.util.StringTokenizer;
import java.lang.*;
import java.util.regex.*;
import javax.naming.*;
import javax.naming.directory.*;
import mypackage.LoginErrorBean;

import javax.naming.NamingException;

public class Login 
{
  private static String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";

  private String host;
  private String port;
  private String encryption;
  private String mgrdnattrib;
  private String mgrdnpath;
  private String searchbase;
  private Vector attribs;

  private LoginErrorBean myErrors = new LoginErrorBean();

  public Login() {}

  public Login(String host,String port,String encryption,String mgrdnattrib,String mgrdnpath,String searchbase,Vector attribs) 

  {
    // Parameter settings to connect to desired LDAP service.
    // Note: the encryption piece does not seem to work at all
    this.host = host;
    this.port = port;
    this.encryption = encryption;
    this.mgrdnattrib = mgrdnattrib;
    this.mgrdnpath = mgrdnpath;
    this.searchbase = searchbase;
    this.attribs = attribs;
  }

  public String[] authenticate(String username, String password) throws NamingException
  {
     String[] authenticate;
          authenticate = new String [5];

    //Set default authentication code to false, f. Authentication is considered valid if value other than 'f' is returned for [0]
          authenticate[0] = "f";

    try {
      String MGR_DN = mgrdnattrib + "="  + username.toUpperCase() + "," + mgrdnpath;
      String MGR_PW = password;
      String provider = "ldap://" + host + ":" + port;

      // Parse atributes
      String MY_ATTRS[] = new String[attribs.size()];
      for (int i = 0; i < attribs.size(); ++i) {MY_ATTRS[i] = (String)attribs.get(i);}

      // Specify the search filter to match for general users
      String MY_FILTER ="("+ mgrdnattrib+"=*)";

      Hashtable env = new Hashtable();

      // Specify which class to use for our JNDI provider
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
      env.put(Context.PROVIDER_URL, provider);
      env.put(Context.SECURITY_AUTHENTICATION,"simple");
      env.put(Context.SECURITY_PRINCIPAL,MGR_DN);
      env.put(Context.SECURITY_CREDENTIALS,MGR_PW);

      if ( encryption.toUpperCase().compareTo("SSL") == 0 ) {env.put(Context.SECURITY_PROTOCOL,"ssl");}

      // Specify host and port to use for directory service

      // Get a reference to a directory context
      DirContext ctx = new InitialDirContext(env);

      // Specify the scope of the search
      SearchControls constraints = new SearchControls();
      constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);

      // Perform the actual search
      // We give it a searchbase, a filter and a the constraints
      // containing the scope of the search
      NamingEnumeration results = ctx.search(searchbase,MY_FILTER, constraints);

      Attribute fn = null;
      Attribute last = null;
      Attributes res = null;
      Attribute ou = null;
      Attribute tel = null;
      Attribute rm = null;
      String givenname = "";
      String ln = "";
      String area = "";
      String phone = "";
      String room = "";

        if (results != null && results.hasMore()) {

          SearchResult sr = (SearchResult) results.next();

          //Attempt to retrieve the ou
          try 
          {  res = sr.getAttributes();
             ou = res.get("ou");
             area = ou.toString();            
          } catch (Exception ex) {ex.printStackTrace();} 
          finally {}

          area.trim();

          //Given name
          try 
          { fn = res.get("givenname");
            givenname = fn.toString();
            givenname = givenname.replaceAll("givenName:","");
            givenname = givenname.trim();
            authenticate[1]=givenname;
          } catch (Exception ex) {ex.printStackTrace();} 
          finally {}

          //sn
          try 
          { last = res.get("sn");
            ln = last.toString();
            ln = ln.replaceAll("sn:","");
            ln = ln.trim();
            authenticate[2]= ln;
          } catch (Exception ex) {ex.printStackTrace();} 
          finally {}

          //Phone
          try 
          { tel = res.get("telephonenumber");
            phone = (tel.toString()==null?"No Phone":tel.toString());
            if(phone.length()==0)
            {phone="telephoneNumber:None";}
          phone = phone.replaceAll("telephoneNumber:","");
          phone = phone.trim();
          authenticate[3]= phone;
          } catch (Exception ex) {ex.printStackTrace();} 
          finally {}

          //Room
          try 
          { rm = res.get("l");
            room = rm.toString();
           if(room.length()==0)
            {room="l:None";}
          room = room.replaceAll("l:","");
          room = room.trim();
          authenticate[4]= room;
          } catch (Exception ex) {ex.printStackTrace();} 
          finally {}
          authenticate [0] = "u";
          /**
           * This section appears to check again, confirming that the username for login is the same login name found in LDAP. 
           * It seems like this is repetitive, will maintain for now however. 10/30/06 axk
          */

      }

    } catch (Exception e) {
        System.err.println("Exception: " + e.getMessage());
        authenticate[1] = e.getMessage();
        myErrors.addErrorMessage(e.toString());

    }
    return authenticate;
  }
}

I am trying to do this in spring security file as:

                    <s:ldap-authentication-provider user-search-filter="(uid={0})"
                    user-search-base="ou=Employees, ou=***, o=ny, c=US"/>


</s:authentication-manager>

    <s:ldap-server id="ldapServer" url="ldap://****:389" manager-dn="cn={0},ou=Employees, ou=nysed, o=ny, c=US" manager-password="{1}" />

Is this the right way , i am not sure if

manager-dn="cn={0},ou=Employees, ou=nysed, o=ny, c=US" manager-password="{1}" 

is right in the security config file.

I am trying to implement this in spring ( its there in Login class file shown above) String MGR_DN = mgrdnattrib + "=" + username.toUpperCase() + "," + mgrdnpath; String MGR_PW = password;

is manager-password="{1}" the right way to specify that manager password is same as user provided password. ?

When I am tring to authenticate using a user-name provided that worked for the java code , I get an error.

<AbstractAuthenticationProcessingFilter> <doFilter> An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: [LDAP: error code 49 - 8009030C: LdapErr: DSID-0C0903AA, comment: AcceptSecurityContext error, data 2030, v1772
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:191)
    at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:61)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:195)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:111)
    at java.security.AccessController.doPrivileged(Native Method)
    at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:313)
    at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:413)
    at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:94)
    at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:161)
    at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:71)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:136)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3715)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:178)


Caused by: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - 8009030C: LdapErr: DSID-0C0903AA, comment: AcceptSecurityContext error, data 2030, v1772

at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:182)
    at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:266)
    at org.springframework.ldap.core.support.AbstractContextSource.getContext(AbstractContextSource.java:106)
    at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:125)
    at org.springframework.ldap.core.LdapTemplate.executeReadOnly(LdapTemplate.java:792)
    at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntry(SpringSecurityLdapTemplate.java:196)
    at org.springframework.security.ldap.search.FilterBasedLdapUserSearch.searchForUser(FilterBasedLdapUserSearch.java:116)
    at org.springframework.security.ldap.authentication.BindAuthenticator.authenticate(BindAuthenticator.java:90)
    at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:178)
    ... 34 more

Caused by: javax.naming.AuthenticationException: [LDAP: error code 49 - 8009030C: LdapErr: DSID-0C0903AA, comment: AcceptSecurityContext error, data 2030, v1772
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3041)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2789)
    at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2703)
    at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
    at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
    at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
    at javax.naming.InitialContext.init(InitialContext.java:223)
    at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134)
    at org.springframework.ldap.core.support.LdapContextSource.getDirContextInstance(LdapContextSource.java:43)
    at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:254)
    ... 41 more

I did a lookup and found Error code 2030 means that the DN of the user is invalid.

Thanks in anticipation.

1

1 Answers

0
votes

Your application code uses DirContext.search method. To archieve the same functionality from Spring Security side you may need to configure FilterBasedLdapUserSearch bean. See LDAP Search Objects chapiter for details:

<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <constructor-arg index="0" value=""/>
    <constructor-arg index="1" value="(uid={0})"/>
    <constructor-arg index="2" ref="contextSource" />
</bean>

<bean id="ldapAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <constructor-arg ref="contextSource" />
            <property name="userSearch" ref="userSearch"/>
        </bean>
    </constructor-arg>
</bean>