java - Spring Security LDAP 广告身份验证

标签 java spring-security ldap

我正在尝试使用 spring security 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;
  }
}

我试图在 spring 安全文件中执行此操作:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:s="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <s:http auto-config="true">
                <s:intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
                <s:intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <s:intercept-url pattern="/**" access="ROLE_USER" />
                <s:intercept-url pattern="/" access="ROLE_USER" />       
        <s:form-login login-page="/login" default-target-url="/getemp"/>
        <s:logout logout-success-url="/logout" />
    </s:http>

    <s:authentication-manager>


                        <s:authentication-provider ref="adAuthenticationProvider"/>


    </s:authentication-manager>


      <bean id="adAuthenticationProvider"
  class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <constructor-arg value="*********" />
    <constructor-arg value="************" />
    <property name="convertSubErrorCodesToExceptions" value="true"/>
</bean>       
</beans>

显示的 html 登录页面是:

使用用户名和密码登录(自定义页面)

    <form method="POST" action="j_spring_security_check" name="f">

        <table>
            <tbody><tr>
                <td>User:</td>
                <td><input type="text" value="" name="j_username">
                </td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type="password" name="j_password">
                </td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="submit" name="submit">
                </td>
            </tr>
            <tr>
                <td colspan="2"><input type="reset" name="reset">
                </td>
            </tr>
        </tbody></table>

    </form>

</body>

早些时候,我尝试使用filterbasedLdapAuthenticator,但至少遇到了异常。现在,当我尝试登录时:控制台上没有显示任何内容 - 我再次进入登录页面。 我哪里可能出错了。

最佳答案

要查看登录期间是否出现异常,请将以下内容添加到您的 jsp 中。

<c:if test="${not empty param.login_error}">
  <font color="red">
    Your login attempt was not successful, try again.<br/><br/>
    Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.
  </font>
</c:if>

这也必须添加到您的 Spring 安全文件中。

<s:form-login login-page="/login" default-target-url="/getemp" authentication-failure-url="/login?login_error=1"/>

要检查的另一件事是 ldap 返回的角色是否具有 ROLE_USER。如果您不需要特定角色,则更改拦截 URL 以仅检查 isAuthenticated()。

<s:intercept-url pattern="/**" access="isAuthenticated()" />

关于java - Spring Security LDAP 广告身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14060298/

相关文章:

grails - 用于grails的Spring Security Core插件-无法从数据库访问RequestMap参数

java - Kryo序列化错误

java - Windows 中缺少 Java 进程的命令行输出

java - 如何修复 Netbeans 8.0 未检测到 Java ME 的问题

java - 增量运算符功能。它是如何工作的?

ldap - Gitlab ldap 登录 FreeIPA 服务器陷入设定的电子邮件循环

mysql - 使用springboot从mysql表中获取id并与url连接

grails - 在Grails GSP中从用户类springSecurityService读取未生成的属性

c# - .Net 中的 LDAP 目录条目 - 不适用于 OU=Users

java - 如何为 ldap DirContext.search(...) 指定搜索范围和返回属性