我目前正在尝试使用 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 似乎也会用空字符串填充该属性。