Skip to main content
 首页 » 编程设计

active-directory之具有 LDAP(Active Directory)的 Spring 数据返回将不会在任何写入操作中执行

2024年06月03日18dudu

我目前正在尝试使用 Spring Data 通过 LDAP 实现与 Active Directory 集成的简单 CRUD,以管理我的内部用户。

问题是,虽然读取按预期进行,但对 AD 的任何写入(例如创建或编辑用户)都会导致通用错误消息,如下所示:

[LDAP:错误代码 53 - 0000209A:SvcErr:DSID-031A107A,问题 5003 (WILL_NOT_PERFORM),数据 0\n\u0000];剩余名称 'DC=company, DC=com'

LDAP 连接是使用 LDAPS 与管理员用户建立的。我什至可以在简单的 Nodejs 测试应用程序中使用相同的凭据,而不会出现任何问题。所以我可能在 Spring Data 方面犯了一些错误。

下面附上相关源码

实体类:

// Person.java (Entity model) 
@Data 
@Entry( 
   base = "ou=Employees,dc=company,dc=com", 
   objectClasses = {"person", "top"} 
) 
public class Person { 
 
  @Id 
  private Name dn; 
 
  @Attribute(name = "cn") 
  private String commonName; 
 
  @Attribute(name = "sAMAccountName") 
  private String accountName; 
 
  @Attribute(name = "userPrincipalName") 
  private String username; 
 
  @Attribute(name = "mail") 
  private String mail; 
 
  @Attribute(name = "userPassword") 
  private String password; 
 
  @Attribute(name = "description") 
  private String desc; 
 
  @Attribute(name = "memberOf") 
  private List<String> groups; 
 
  @Attribute(name = "company") 
  private String company; 
 
  @Attribute(name = "objectClass") 
  private List<String> objectClasses; 
 
  @Attribute(name = "objectCategory") 
  private String objectCategory; 
} 

存储库类:

// PersonRepository.java 
@Repository 
public interface PersonRepository extends LdapRepository<Person> { 
    Person findByMailIgnoreCase(String mail); 
} 

服务等级:

@Service 
public class UserService { 
 
   @Autowired 
   private PersonRepository personRepository; 
 
    /** 
    * Save the user at AD. 
    * 
    * @param username       the user login name 
    * @param name           the user name and surename 
    * @param companyExtName the company external name 
    * @param email          the user email 
    * @param description    the user description 
    * @return the newly created user 
    */ 
    public Person createPerson(String username, String name, String companyExtName, 
                            String email, String description) { 
 
        final Person user = new Person(); 
        user.setAccountName(username); 
        user.setCommonName(name); 
        user.setCompany(companyExtName); 
        user.setMail(email); 
        user.setUsername(email); 
 
        String tempPass = RandomStringUtils.randomAscii(10); 
        user.setPassword(digestSHA(tempPass)); 
        user.setDn(LdapNameBuilder.newInstance("DC=company, DC=com") 
                .build()); 
 
        List<String> objClasses = new ArrayList<>(); 
        objClasses.add("person"); 
        objClasses.add("top"); 
        user.setObjectClasses(objClasses); 
        user.setObjectCategory("CN=Person,CN=Schema,CN=Configuration,DC=company,DC=com"); 
 
        List<String> groups = new ArrayList<>(); 
        groups.add("CN=Administrators,CN=Builtin,DC=company,DC=com"); 
        user.setGroups(groups); 
 
        if (description != null && !description.isEmpty()) { 
            user.setDesc(description); 
        } 
 
        return personRepository.save(user); 
    } 
 
    /** 
    * Encodes the user password as it is used at Active Directory 
    * 
    * @param plain the plain text password 
    * @return the password hash 
    */ 
    private static String digestSHA(String plain) { 
        try { 
            MessageDigest digester = MessageDigest.getInstance("SHA-256"); 
            digester.update(plain.getBytes()); 
            return String.format("{SHA}%s", Base64.getEncoder().encodeToString(digester.digest())); 
        } catch (NoSuchAlgorithmException ex) { 
            return null; 
        } 
    } 

调用personRepository.save(user);时抛出异常

作为附加信息,我已经尝试了所附代码的一些变体 - 尝试在保存之前删除几乎所有用户数据、不同的密码编码和散列 - 但结果始终相同。 对此的任何帮助将不胜感激。

谢谢!

编辑: 调查表明,原因可能与我发送用户 DN 的方式有关。 无论如何,我仍在努力解决这个问题。

请您参考如下方法:

我能够通过解决方法创建/编辑我的 Active Directory 用户。 在我的 UserService 中,我没有使用 Spring Data Ldap 存储库,而是使用了 LdapTemplate 方法,如下所示。

// UserService.java 
   public void createPerson() { 
    Name userDn = LdapNameBuilder 
            .newInstance() 
            .add("ou", ou) 
            .add("cn", accountName) 
            .build(); 
    DirContextAdapter context = new DirContextAdapter(userDn); 
 
    context.setAttributeValue("cn", accountName); 
    context.setAttributeValue("sn", accountName); 
    context.setAttributeValue("userPassword", digestSHA(password)); 
    context.setAttributeValue("company", company); 
    context.setAttributeValue("description", desc); 
    context.setAttributeValue("mail", mail); 
    context.setAttributeValue("sAMAccountName", accountName); 
    context.setAttributeValue("userPrincipalName", username); 
    context.setAttributeValue("objectCategory", objectCategory); 
 
    context.setAttributeValues("objectClass", objectClasses.toArray()); 
    DirContextAdapter context = user.getLdapContext("Users"); 
    ldapTemplate.bind(context); 
 } 

由于我使用 Spring Data 和 LdapTemplate 创建用户时使用了相同的值,因此我最初的问题可能与 Spring 在将数据发送到我的 Active Directory 服务器之前所做的一些处理有关。

由于上述方法目前对我有效,因此我将遵循它。当我有空闲时间时,我会回到这里来找出我在 Spring 上做错了什么。

为了将来的使用,我相信它与 memberOf 属性有关。该属性必须在创建用户后设置,但即使我在创建用户时将该属性设置为 null ,Spring Data 似乎也会用空字符串填充该属性。