使用 Spring Data LdapRepository 创建新用户失败,LDAP 错误代码为 32

End*_*die 4 java spring ldap spring-data

我正在尝试使用 Spring Data 和 LdapRepository api 在 Ldap 中读取、更新和创建用户数据。我已经能够成功读取和更新,但是每当我尝试插入新记录时,我都会收到此错误:

2017-07-25 17:31:01.966 ERROR 14404 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; 
nested exception is org.springframework.ldap.NameNotFoundException: 
[LDAP: error code 32 - The search base entry 'uid=testy1@testy.org,ou=people,ou=myou,dc=bar,dc=foo' does not exist]; 
nested exception is javax.naming.NameNotFoundException: 
[LDAP: error code 32 - The search base entry 'uid=testy1@testy.org,ou=people,ou=myou,dc=bar,dc=foo' does not exist]; remaining name 'uid=testy1@testy.org'] 
with root cause
javax.naming.NameNotFoundException: [LDAP: error code 32 - The search base entry 'uid=testy1@testy.org,ou=people,ou=myou,dc=bar,dc=foo' does not exist]
Run Code Online (Sandbox Code Playgroud)

我的 application.properties 是:

user-api.ldap.contextSource.url=ldap://server.address.com:1389
user-api.ldap.contextSource.userDn=cn=manager role
user-api.ldap.contextSource.password=apasswordwashere
user-api.ldap.contextSource.base=ou=people,ou=myou,dc=bar,dc=foo
Run Code Online (Sandbox Code Playgroud)

我的回购界面,LdapUserRepository.java:

public interface LdapUserRepository extends LdapRepository<LdapUser>{

   LdapUser findByCn(String cn);

   LdapUser findBySn(String sn);

   LdapUser save(LdapUser ldapUser);
}
Run Code Online (Sandbox Code Playgroud)

无论我是否明确公开save方法,我都会得到相同的响应。

我的配置是在 LdapConfiguration.java 中完成的:

@Configuration
@EnableLdapRepositories(basePackages = "foo.bar.userapi.dao.ldap", ldapTemplateRef="userLdapTemplate")
public class LdapConfiguration {

    @Autowired
    Environment env;

    @Bean
    public LdapContextSource contextSource () {
        LdapContextSource contextSource= new LdapContextSource();
        contextSource.setUrl(env.getRequiredProperty("user-api.ldap.contextSource.url"));
        contextSource.setBase(env.getRequiredProperty("user-api.ldap.contextSource.base"));
        contextSource.setUserDn(env.getRequiredProperty("user-api.ldap.contextSource.userDn"));
        contextSource.setPassword(env.getRequiredProperty("user-api.ldap.contextSource.password"));
        return contextSource;
    }

    @Bean(name="userLdapTemplate")
    public LdapTemplate ldapTemplate() {
        return new LdapTemplate(contextSource());       
    }

}
Run Code Online (Sandbox Code Playgroud)

还有我的测试程序:

public void test() {
   LdapUser ldapUser =  new LdapUser();

   ldapUser.setCn("198777777");
   ldapUser.setCountry("United States");
   ldapUser.setGivenName("Hepsibah");
   ldapUser.setIsActive("true");
   ldapUser.setSn("Testerson91");
   ldapUser.setStatus("active");
   ldapUser.setUid(LdapUtils.newLdapName("uid=testy1@testy.org"));
   ldapUser.setUserModifyTimestamp("20160222145439Z");
   ldapUser.setUserPassword("Password-12345");
   ldapUser = ldapUserRepository.save(ldapUser);
}
Run Code Online (Sandbox Code Playgroud)

强调一下,该配置适用于除插入之外的所有内容,因为如果我这样做,它会起作用:

   public void test2() {
          LdapUser ldapUser =  ldapUserRepository.findBySn("Testerson");
          if ( ldapUser != null) {
                 System.out.println(ldapUser.getUid().toString());
                 System.out.println("result: " + ldapUser.toString());

                 ldapUser.setSn("Testerson2");
                 ldapUser.setUserPassword("Password-12345!");
                 ldapUser = ldapUserRepository.save(ldapUser);

                 ldapUser = ldapUserRepository.findBySn("Testerson2");
                 if ( ldapUser != null) {
                       System.out.println("result: " + ldapUser.toString());
                 }
          }
   }
Run Code Online (Sandbox Code Playgroud)

我怀疑答案可能与将用户添加到 ldap 时的 Ldap 错误代码 32 有关,但我没有在保存操作期间明确添加 dn,并且更新操作工作正常。

检索记录、更改 uid 值并保存它会产生相同的错误。检索记录并检查 uid 仅显示“uid=testy1@testy.org”部分而不是“ou=people,ou=myou,dc=bar,dc=foo”部分。

tur*_*emu 6

假设正在使用默认实现(SimpleLdapRepository - 如果您没有自己实现存储库接口,您会得到这个),那么当 SimpleLdapRepository 尝试确定它是否应该“保存”或“更新”您的实体时,就会出现问题。从这里开始,SimpleLdapRepository 中的代码如下所示:

 @Override
 public <S extends T> S More ...save(S entity) {
     Assert.notNull(entity, "Entity must not be null");
     Name declaredId = odm.getId(entity);

     if (isNew(entity, declaredId)) {
         ldapOperations.create(entity);
     } else {
         ldapOperations.update(entity);
     }

     return entity;
 }
Run Code Online (Sandbox Code Playgroud)

为了获得您所看到的错误,您的实体可能未被确定为新实体,执行此更新时会在发现实体不存在且无法更新时失败。

isNew()方法如下所示:

     private <S extends T> boolean More ...isNew(S entity, Name id) {
     if (entity instanceof Persistable) {
         Persistable<?> persistable = (Persistable<?>) entity;
         return persistable.isNew();
     } else {
         return id == null;
     }
 }
Run Code Online (Sandbox Code Playgroud)

在您的示例中,您似乎需要设置 ID。因此,另一种选择是实现 Persistable 接口和isNew()返回实体是否为新实体的方法。如果您的实体被确定为新实体(您可以ldapUser.setNew(true);在保存之前调用),它将被保存而不是更新。

  • 那太完美了,谢谢!我将要保存的对象更改为:`public final class LdapUser implements Persistable{...` 然后我在 LdapUser 类中添加了 isNew 成员,并带有瞬态注释,这样它就不会尝试将其与字段匹配在 ldap 表中:`@Transient private boolean isNew;` 连同标准的 setter 和你建议的方法:`@Override public boolean isNew() { return this.isNew; }` 当我将该字段设置为 true 并保存时,它就成功了! (2认同)