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.