2012-12-12 145 views
0

我正在嘗試使用spring安全3.1對ldap服務器進行身份驗證。春季安全3.1 ldap

我對ldap知之甚少。

在舊代碼中,這是大約7歲。我們有一個servlet調用一個登錄對象

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); 

的登錄密碼是:

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; 
    } 
} 

我試圖做到這一點在春季安全文件爲:

    <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}" /> 

是這正確的方式, 我不知道,如果

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

在安全配置文件中是正確的。

我試圖在春季實現這一點(它在上面顯示的登錄類文件中) String MGR_DN = mgrdnattrib +「=」+ username.toUpperCase()+「,」+ mgrdnpath; 字符串MGR_PW =密碼;

是manager-password =「{1}」指定管理員密碼與用戶提供的密碼相同的正確方法。 ?

當我使用用於java代碼的用戶名進行身份驗證時,出現錯誤。

<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 

我做了查找,發現錯誤代碼2030意味着用戶的DN無效。

感謝您的期待。

回答

0

您的應用程序代碼使用DirContext.search方法。爲了從Spring Security端獲得相同的功能,你可能需要配置FilterBasedLdapUserSearch bean。詳情請參閱LDAP Search Objects chapiter:

<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> 
+0

請問你可以寫上面代碼的等效spring xml。 – Rpant

+0

我需要一個具有相同結構和一些用於測試的數據的LDAP服務器。您是否嘗試過FilterBasedLdapUserSearch bean?你有什麼樣的問題? –