简体   繁体   English

无法通过 Spring LDAP 获取 Active Directory 记录的修改上下文

[英]Unable to get modification context for Active Directory records through Spring LDAP

I am trying to use Spring LDAP to retrieve and modify user information in an Active Directory server, but I can't retrieve a user record by dn so that I can modify it.我正在尝试使用 Spring LDAP 来检索和修改 Active Directory 服务器中的用户信息,但我无法通过 dn 检索用户记录以便我可以修改它。

I am able to find the record by username with the LdapTemplate.search method.我可以使用LdapTemplate.search方法按用户名查找记录。 There is no dn attribute in the record, but distinguishedName looks like it should be correct.记录中没有dn属性,但是distinguishedName看起来应该是正确的。 When I use LdapTemplate.lookupContext to retrieve the record by dn, however, the server says that it can't find the record by the dn that it just gave me.但是,当我使用LdapTemplate.lookupContext按 dn 检索记录时,服务器说它找不到它刚刚给我的dn记录。 What am I doing wrong?我究竟做错了什么?

It seem wrong that the LdapTemplate search method doesn't give you a handle that you can use without doing a second query from the Active Directory. LdapTemplate搜索方法没有为您提供无需从 Active Directory 进行第二次查询即可使用的句柄,这似乎是错误的。 Is there a better way to do this?有一个更好的方法吗?

I have created a sample Groovy application to demonstrate the problem.我创建了一个示例 Groovy 应用程序来演示该问题。 My Spring Boot application creates this class and then invokes the runTest method.我的 Spring 引导应用程序创建此 class 然后调用 runTest 方法。

package edu.sunyjcc.gateway.ldap;

import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import static org.springframework.ldap.query.LdapQueryBuilder.query;
import org.springframework.ldap.core.DirContextOperations;

public class ActiveDirectoryDNSample {

  LdapTemplate ldapTemplate;

  /** Attributes to fetch from server */
  static attributeList = [
    "sAMAccountName",
    "distinguishedName",
    "baseDn",
    "userPrincipalName",
  ];

  /** This will represent the record retrieved from Active Directory */
  class Person {
    /** Raw data from server */
    Map attributes = [:];
    /** Return the distinguished name */
    String getDn() {
      attributes?.distinguishedName;
    }
    String getUsername() {
      attributes?.sAMAccountName;
    }
    String toString() {
      "${this.username} <${this.getDn()}>"
    }
    /** Get a handle to the object from AD so we can modify it.  This fails. */
    def getContext() {
      assert ldapTemplate;
      println "in getContext()";
      def dn = new LdapName(this.getDn());
      println "...dn=$dn"
      assert dn;
      // The next line throws an exception.
      DirContextOperations context = ldapTemplate.lookupContext(dn);
      println "...context=$context"
    }
  }

  /** Convert the attributes from AD into a Person object */
  class RecordMapper implements AttributesMapper<Person> {

    /** Create a Person object from the attribute map */
    Person mapFromAttributes(Attributes attributes)
    throws NamingException {
      assert ldapTemplate;
      Person prec = new Person(
        ldapTemplate: ldapTemplate
      );
      attributeList.collect {
        [attrName: it, attr: attributes.get(it)]
      }.grep {it.attr}.each {
        prec.attributes."${it.attrName}" = it.attr.get() as String;
      }
      return prec;
    }
  }

  /** Get a user from Active Directory */
  public List<Person> getByUsername(String username) throws Exception {
    assert ldapTemplate;
    AttributesMapper attrMapper = new RecordMapper();
    assert attrMapper;
    List s = ldapTemplate.search(
      query().
      where("sAMAccountName").is(username),
      attrMapper
    );
    if (s == null) {
      System.err.println("s is null");
    }
    return s?:[];
  }

  /** Try to fetch a record and get a modify context for it */
  public runTest(String username) {
    println "In ActiveDirectoryDNSample.runText($username)"
    assert ldapTemplate;
    def records = getByUsername(username);
    println "Retrieved ${records?.size()} records";
    records.each {println "   $it"}
    println "Now try to get the context for the records"
    records.each {
      person ->
      println "    getting context for $person";
      def context = person.getContext();
      println "      context=$context"
    }
  }


  public ActiveDirectoryDNSample(LdapTemplate ldapTemplate ) {
    this.ldapTemplate = ldapTemplate;
  }
}

In ActiveDirectoryDNSample.runText(testuser)
Retrieved 1 records
   testuser <CN=Test User,CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu>
Now try to get the context for the records
    getting context for testuser <CN=Test User,CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu>
in getContext()
...dn=CN=Test User,CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu

and then it dies with a javax.naming.NameNotFoundException with the following data.然后它死于带有以下数据的javax.naming.NameNotFoundException

[LDAP: error code 32 - 0000208D: NameErr: DSID-03100238, problem 2001 (NO_OBJECT), data 0, best match of:
    'CN=Users,DC=jccadmin,DC=sunyjcc,DC=edu'
\0]

Thanks for any help you can give me.感谢你给与我的帮助。

It turns out that there was, indeed, a better way.事实证明,确实有更好的方法。 Instead of using an org.springframework.ldap.core.AttributesMapper in the search, you use org.springframework.ldap.core.ContextMapper .代替在搜索中使用org.springframework.ldap.core.AttributesMapper ,您使用org.springframework.ldap.core.ContextMapper

In my example, I added a field to the Person class, which will hold a reference to the context.在我的示例中,我向 Person class 添加了一个字段,该字段将包含对上下文的引用。

DirContextOperations context;

Then I created a new class extending org.springframework.ldap.core.support.AbstractContextMapper .然后我创建了一个新的 class 扩展org.springframework.ldap.core.support.AbstractContextMapper

class PersonContextMapper extends AbstractContextMapper  {
  @Override
  protected Object doMapFromContext(DirContextOperations ctx) {
    AttributesMapper attrMapper = new RecordMapper();
    Person p = attrMapper.mapFromAttributes(ctx.attributes);
    p.context = ctx;
    return p;
  }
}

When I passed it to the ldapTemplate.search method in the place of the AttributeMapper , I was able to use the context to update the Active Directory.当我将它传递给ldapTemplate.search方法来代替AttributeMapper时,我能够使用上下文来更新 Active Directory。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM