AD域、ldap协议检索数据的基本使用

最近做一项目,涉及集成AD域系统的一些信息,现在总结下自己使用ldap协议,java实现AD信息的检索方式,希望对读者有点帮助。

目的机的连接,LDAPUrl连接地址,如:ldap://10.xxx.1.xxx:389,user具有检索信息权限的用户名,password相应的密码。返回相关的上下文信息LdapContext对象实例。

public LdapContext connectLDAP(String LDAPUrl, String user, String password)
   throws Exception {
  Hashtable env = new Hashtable();
  env.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.sun.jndi.ldap.LdapCtxFactory");
  env.put(Context.PROVIDER_URL, LDAPUrl);
  env.put(Context.SECURITY_PRINCIPAL, user);
  env.put(Context.SECURITY_CREDENTIALS, password);
  // env.put(Context.BATCHSIZE, "2000");
  LdapContext ctx = new InitialLdapContext(env, null);
  // Control[] contys=ctx.getRequestControls();
  // 链接ldap
  System.out.println("connection is ok");
  return ctx;
 }

得到LdapContext相关实例后,可以检索某个信息点objectClass的数据,objectClass数据如:user-用户,organizationalUnit-组织单位等,userbase为DC(域控制器)名称,如:DC=xxx1,DC=xxx2,DC=xxx3

public List ldapDatalist(LdapContext context, String base,
   String objectClass) throws Exception {
  List resultlist = new ArrayList();
  if (context != null) {
   try {
       SearchControls cons = new SearchControls(
      SearchControls.SUBTREE_SCOPE, 0, 0, null, false, false);//设置检索控制
    NamingEnumeration en = context.search(base, "(objectClass="
      + objectClass + ")", cons); // 查询相关信息,

    while (en != null && en.hasMoreElements()) {
     SearchResult result = (SearchResult) en.next();
     NamingEnumeration attrs = result.getAttributes().getAll();
     int count = 0;
     Map ou = new HashMap();
     while (attrs.hasMore()) {
      Attribute attr = (Attribute) attrs.next();
      // if (count == 0) {
      // System.out.print(attr.getID() + ":"
      // + attr.get().toString() + "|");
      // }
      if ("objectSid".equals(attr.getID())
        || "objectGUID".equals(attr.getID())) {
       ou.put(attr.getID(), getGUID(attr.get().toString()
         .getBytes()));
      } else if ("whenCreated".equals(attr.getID())
        || "whenChanged".equals(attr.getID())
        || "dSCorePropagationData".equals(attr.getID())) {
       String value = attr.get().toString();
       ou.put(attr.getID(), value.subSequence(0, value
         .indexOf(".")));
      } else {
       ou.put(attr.getID(), attr.get().toString());
      }
      count++;
     }
     resultlist.add(ou);
    }
   } catch (Exception ee) {
    ee.printStackTrace();
    return null;
   }
  }
  System.out.println("总共:" + resultlist.size() + "条信息.");
  return resultlist;
 }

正常检索可以得到属性-值的Map信息列表。但当某中类型的数据量很大的时候,你会发现每次检索数据只能获取到100条数据记录。其中值得注意的是,LDAP获取数据的默认上限为1000。很多时候,数据会超出1000,将会丢失多余的数据。为此,如果不改配置,则需要分批进行读取,这就需要根据entryid排序来进行。在LDAP Java JDK的文档中寻找关于Filter的描述。以下是从原文中查找到关于如何设置该限制的相关描述。
Setting Size and Time Limits
By default, when you search the directory from a client built with the Netscape Directory SDK for Java, the maximum number of entries to return is set to 1000, and there is no maximum time limit for waiting on an operation to complete.
To change these default values, you can do one of the following:
l Use the setOption method of the LDAPConnection object to set the LDAPv2.SIZELIMIT and LDAPv2.TIMELIMIT preferences.
l Use the setMaxResults method and the setTimeLimit method of the LDAPSearchConstraints object to change this for a particular set of search constraints.
Setting the size limit or time limit may cause an LDAPException to be thrown if the size limit or time limit is exceeded:
If the size limit is exceeded, the server returns an LDAPException.SIZE_LIMIT_EXCEEDED result code.
If the time limit is exceeded, the server returns an LDAPException.TIME_LIMIT_EXCEEDED result code.
Note that the smallest unit supported by the Netscape Directory Server is seconds, not milliseconds. Since the Netscape Directory SDK for Java allows you to specify the time limit in milliseconds, the value that you specify will be rounded to the nearest second by the Directory Server.
当你用Netscape目录Java开发包建立客户端程序搜索目录时,每个入口的最大返回数值默认被设置为1000并且操作完成时间没有限制。
要是不改变这些默认值,数据检索时我们可以使用下列的方法进行分页读取:
public List ldapDatalistPage(LdapContext context, String base,
   String objectClass) {
  List resultlist = new ArrayList();
  int pageSize = 1000; // 1000 entries per page
  byte[] cookie = null;
  int total;
  try {
   context.setRequestControls(new Control[] { new PagedResultsControl(
     pageSize, Control.CRITICAL) });//分页读取控制
   do {//循环检索数据
    // Perform the search
    SearchControls cons = new SearchControls(
      SearchControls.SUBTREE_SCOPE, 0, 0, null, false, false);
    NamingEnumeration results = context.search(base,
      "(objectClass=" + objectClass + ")", cons); // 查询所有信息
    // Iterate over a batch of search results
    while (results != null && results.hasMoreElements()) {
     SearchResult result = (SearchResult) results.next();
     NamingEnumeration attrs = result.getAttributes().getAll();
     int count = 0;
     Map ou = new HashMap();
     while (attrs.hasMore()) {
      Attribute attr = (Attribute) attrs.next();
      if ("objectSid".equals(attr.getID())
        || "objectGUID".equals(attr.getID())) {
       ou.put(attr.getID(), getGUID(attr.get().toString()
         .getBytes()));
      } else if ("whenCreated".equals(attr.getID())
        || "whenChanged".equals(attr.getID())
        || "dSCorePropagationData".equals(attr.getID())) {
       String value = attr.get().toString();
       ou.put(attr.getID(), value.subSequence(0, value
         .indexOf(".")));
      } else {
       ou.put(attr.getID(), attr.get().toString());
      }
      count++;
     }
     resultlist.add(ou);
    }
    // Examine the paged results control response
    Control[] controls = context.getResponseControls();
    if (controls != null) {
     for (int i = 0; i < controls.length; i++) {
      if (controls[i] instanceof PagedResultsResponseControl) {
       PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
       total = prrc.getResultSize();
       cookie = prrc.getCookie();
      } else {
       // Handle other response controls (if any)
      }
     }
    }
    // Re-activate paged results
    context.setRequestControls(new Control[] { new PagedResultsControl(
        pageSize, cookie, Control.CRITICAL) });
   } while (cookie != null);
  } catch (NamingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  System.out.println("总共:" + resultlist.size() + "条信息.");
  return resultlist;
 }

使用Spring Boot集成LDAP实现AD用户认证、用户检索和密码重置,需要进行以下步骤: 1. 添加Spring LDAP和Spring Security依赖 首先,在pom.xml文件中添加Spring LDAP和Spring Security依赖: ```xml <dependency> <groupId>org.springframework.ldap</groupId> <artifactId>spring-ldap-core</artifactId> <version>2.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-ldap</artifactId> <version>5.4.6</version> </dependency> ``` 2. 配置LDAP连接信息 在application.properties文件中配置LDAP连接信息,如下所示: ```properties # LDAP server URL spring.ldap.urls=ldap://ad.example.com:389/ # LDAP base DN spring.ldap.base=dc=example,dc=com # LDAP user DN spring.ldap.username=cn=admin,dc=example,dc=com # LDAP user password spring.ldap.password=secret ``` 3. 配置Spring Security认证 在SecurityConfig类中配置Spring Security认证: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/home") .failureUrl("/login?error=true") .permitAll() .and() .logout() .logoutSuccessUrl("/login") .permitAll(); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth .ldapAuthentication() .userDnPatterns("uid={0},ou=people") .groupSearchBase("ou=groups") .contextSource() .url("ldap://ad.example.com:389/dc=example,dc=com") .and() .passwordCompare() .passwordEncoder(new BCryptPasswordEncoder()) .passwordAttribute("userPassword"); } } ``` 这里,我们使用LDAP进行用户认证,用户DN格式为`uid={0},ou=people`,组DN为`ou=groups`。同时,我们使用BCrypt密码编码器进行密码加密。 4. 实现用户检索和密码重置 我们可以使用LdapTemplate类来检索用户和重置密码。例如,检索所有用户的代码如下: ```java @Autowired private LdapTemplate ldapTemplate; public List<String> findAllUsers() { return ldapTemplate.search( LdapQueryBuilder.query().where("objectclass").is("person"), (AttributesMapper<String>) attrs -> (String) attrs.get("cn").get() ); } ``` 重置密码的代码如下: ```java @Autowired private LdapTemplate ldapTemplate; public void resetPassword(String username, String newPassword) { Name dn = LdapNameBuilder .newInstance() .add("ou", "people") .add("uid", username) .build(); ModificationItem[] mods = new ModificationItem[] { new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userPassword", newPassword)) }; ldapTemplate.modifyAttributes(dn, mods); } ``` 这里,我们使用LdapNameBuilder类构建用户DN,然后使用ModifyAttributes方法重置用户密码。 以上就是使用Spring Boot集成LDAP实现AD用户认证、用户检索和密码重置的步骤。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值