I'm currently trying to implement an simple CRUD integrated with Active Directory via LDAP, using Spring Data, for managing my internal users.
The problem is, while the reading works as expected, any writing on AD (creating or editing a user, for example) results in a generic error message, shown below:
[LDAP: error code 53 - 0000209A: SvcErr: DSID-031A107A, problem 5003 (WILL_NOT_PERFORM), data 0\n\u0000]; remaining name 'DC=company, DC=com'
The ldap connection is being made using LDAPS with an admin user. I can even work with the same credentials without any issues in a simple nodejs test application. So I'm probably making some mistake with Spring Data.
The relevant source code is attached below.
Entity class:
// 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;
}
Repository class:
// PersonRepository.java
@Repository
public interface PersonRepository extends LdapRepository<Person> {
Person findByMailIgnoreCase(String mail);
}
Service class:
@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;
}
}
The exception is thrown when I call personRepository.save(user);
As a addtional information, I've already tried a few variations of the code attached -- tried to remove almost all user data beforing saving it, different password encodings and hashing -- but the result is always the same. Any help on this will be greatly appreciated.
Thanks!
EDIT: Investigation indicates that the cause is probably something related with the way I'm sending my user DN. Anyway, I'm still wrestling with this issue.