Printemps LDAP à l'aide de Java Configuration

J'ai été à la suite de la des échantillons de Printemps LDAP projet et essayait de convertir xml configuration de Java Configuration.

Je suis en train de faire les opérations CRUD sur le serveur LDAP.

J'ai été en mesure de comprendre la suite,

C'est le xml de configuration de l'application, dont je suis l'espoir de les convertir en Java Config.

<context:property-placeholder location="classpath:/ldap.properties"
        system-properties-mode="OVERRIDE" />
    <context:annotation-config />

    <ldap:context-source id="contextSource" password="${sample.ldap.password}"
        url="${sample.ldap.url}" username="${sample.ldap.userDn}" base="${sample.ldap.base}" />

    <ldap:ldap-template id="ldapTemplate"
        context-source-ref="contextSource" />

    <!-- This will scan the org.springframework.ldap.samples.useradmin.domain 
        package for interfaces extending CrudRepository (in our case, LdapRepository), 
        automatically creating repository beans based on these interfaces. -->
    <ldap:repositories base-package="com.cazysystems.appstore.model" />

    <!-- This one will never be referenced directly, but the ldap:repositories 
        tag will make sure it will be 'wired in', because the GroupRepo interface 
        extends from an interface that GroupRepoImpl imlements. -->
    <bean class="com.cazysystems.appstore.model.impli.GroupRepoImpl" />

    <bean class="com.cazysystems.appstore.model.impli.DepartmentRepoImpl" />

    <bean class="com.cazysystems.appstore.service.UserService">
        <property name="directoryType" value="${sample.ldap.directory.type}" />
    </bean>

J'ai donc les classes suivantes qui sont censés faire la migration,

@Configuration
@EnableLdapRepositories("com.cazysystems.appstore.model")
public class LdapConfiguration {

    @Autowired
    Environment env;

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

    @Bean
    public LdapTemplate ldapTemplate() {
        return new LdapTemplate(contextSource());
    }

}

et la

 @Configuration
public class AuthenticationConfiguration extends
        GlobalAuthenticationConfigurerAdapter {

    @Autowired
    Environment env;

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {

        auth.ldapAuthentication()
                //.userDetailsContextMapper(userDetailsContextMapper())
                .userDnPatterns(
                        env.getRequiredProperty("ldap.user_dn_patterns"))
                .groupSearchBase(
                        env.getRequiredProperty("ldap.group_search_base"))
                .contextSource().ldif("classpath:setup_data.ldif")
                .url(env.getRequiredProperty("sample.ldap.url"))
                .managerDn("sample.ldap.userDn")
                .managerPassword("sample.ldap.password").port(10389);
    }

}

Mais quand je lance l'application,

J'obtiens l'erreur suivante,

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'groupRepo': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class com.cazysystems.appstore.model.Group

Mais en vertu de la com.cazysystems.appstore.modelpaquet,

J'ai,

public interface GroupRepo extends LdapRepository<Group>, GroupRepoExtension {
    public final static String USER_GROUP = "ROLE_USER";

    Group findByName(String groupName);

    @Query("(member={0})")
    Collection<Group> findByMember(Name member);
}

et

@Entry(objectClasses = { "groupOfNames", "top" }, base = "ou=Groups")
public final class Group {
    @Id
    private Name id;

    @Attribute(name = "cn")
    @DnAttribute(value = "cn", index = 1)
    private String name;

    @Attribute(name = "description")
    private String description;

    @Attribute(name = "member")
    private Set<Name> members = new HashSet<Name>();

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Set<Name> getMembers() {
        return members;
    }

    public void addMember(Name newMember) {
        members.add(newMember);
    }

    public void removeMember(Name member) {
        members.remove(member);
    }

    public Name getId() {
        return id;
    }

    public void setId(Name id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Mais cette annotation est censé faire le tour, Mais il ne fonctionne pas,

@EnableLdapRepositories("com.cazysystems.appstore.model")

Je suis en utilisant les dépendances suivantes dans mon pompon.

<dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-ldap</artifactId>
    </dependency>


    <dependency>
        <groupId>org.springframework.ldap</groupId>
        <artifactId>spring-ldap-core</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.ldap</groupId>
        <artifactId>spring-ldap-core-tiger</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
    </dependency>

Je ne suis pas sûr de ce que je fais de mal, parce que la documentation sur ce sujet sont très difficiles à trouver. S'il vous plaît aider si vous savez ce genre de choses.

EDIT:

Voici mon Contrôleur de classe,

@Controller
public class GroupController {
@Autowired
private GroupRepo groupRepo;
@Autowired
private UserService userService;
@RequestMapping(value = "/groups", method = GET)
public String listGroups(ModelMap map) {
map.put("groups", groupRepo.getAllGroupNames());
return "listGroups";
}
@RequestMapping(value = "/newGroup", method = GET)
public String initNewGroup() {
return "newGroup";
}
@RequestMapping(value = "/groups", method = POST)
public String newGroup(Group group) {
groupRepo.create(group);
return "redirect:groups/" + group.getName();
}
@RequestMapping(value = "/groups/{name}", method = GET)
public String editGroup(@PathVariable String name, ModelMap map) {
Group foundGroup = groupRepo.findByName(name);
map.put("group", foundGroup);
final Set<User> groupMembers = userService.findAllMembers(foundGroup.getMembers());
map.put("members", groupMembers);
Iterable<User> otherUsers = Iterables.filter(userService.findAll(), new Predicate<User>() {
@Override
public boolean apply(User user) {
return !groupMembers.contains(user);
}
});
map.put("nonMembers", Lists.newLinkedList(otherUsers));
return "editGroup";
}
@RequestMapping(value = "/groups/{name}/members", method = POST)
public String addUserToGroup(@PathVariable String name, @RequestParam String userId) {
Group group = groupRepo.findByName(name);
group.addMember(userService.toAbsoluteDn(LdapUtils.newLdapName(userId)));
groupRepo.save(group);
return "redirect:/groups/" + name;
}
@RequestMapping(value = "/groups/{name}/members", method = DELETE)
public String removeUserFromGroup(@PathVariable String name, @RequestParam String userId) {
Group group = groupRepo.findByName(name);
group.removeMember(userService.toAbsoluteDn(LdapUtils.newLdapName(userId)));
groupRepo.save(group);
return "redirect:/groups/" + name;
}
}

EDIT:

Ce qui suit est la trace de la pile complète,

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'groupController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.cazysystems.appstore.domain.GroupRepo com.eazysystems.appstore.controller.GroupController.groupRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'groupRepo': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class com.cazysystems.appstore.domain.Group
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.eazysystems.appstore.Application.main(Application.java:20)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.cazysystems.appstore.domain.GroupRepo com.eazysystems.appstore.controller.GroupController.groupRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'groupRepo': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class com.eazysystems.appstore.domain.Group
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 16 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'groupRepo': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class com.eazysystems.appstore.domain.Group
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
... 18 common frames omitted
Caused by: java.lang.IllegalArgumentException: Not an managed type: class com.cazysystems.appstore.domain.Group
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:68)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:67)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:145)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:89)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:69)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:173)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:239)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:225)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 28 common frames omitted

Mon UserService classe comme suite,

@Component
public class UserService implements BaseLdapNameAware {
@Autowired
private UserRepo userRepo;
@Autowired
private GroupRepo groupRepo;
private LdapName baseLdapPath;
@Autowired
@Value("${sample.ldap.directory.type}")
private DirectoryType directoryType;
/*
* @Autowired public UserService(UserRepo userRepo, GroupRepo groupRepo) {
* this.userRepo = userRepo; this.groupRepo = groupRepo; }
*/
public Group getUserGroup() {
return groupRepo.findByName(GroupRepo.USER_GROUP);
}
public void setDirectoryType(DirectoryType directoryType) {
this.directoryType = directoryType;
}
@Override
public void setBaseLdapPath(LdapName baseLdapPath) {
this.baseLdapPath = baseLdapPath;
}
public Iterable<User> findAll() {
return userRepo.findAll();
}
public User findUser(String userId) {
return userRepo.findOne(LdapUtils.newLdapName(userId));
}
public User createUser(User user) {
User savedUser = userRepo.save(user);
Group userGroup = getUserGroup();
//The DN the member attribute must be absolute
userGroup.addMember(toAbsoluteDn(savedUser.getId()));
groupRepo.save(userGroup);
return savedUser;
}
public LdapName toAbsoluteDn(Name relativeName) {
return LdapNameBuilder.newInstance(baseLdapPath).add(relativeName)
.build();
}
/**
* This method expects absolute DNs of group members. In order to find the
* actual users the DNs need to have the base LDAP path removed.
*
* @param absoluteIds
* @return
*/
public Set<User> findAllMembers(Iterable<Name> absoluteIds) {
return Sets.newLinkedHashSet(userRepo
.findAll(toRelativeIds(absoluteIds)));
}
public Iterable<Name> toRelativeIds(Iterable<Name> absoluteIds) {
return Iterables.transform(absoluteIds, new Function<Name, Name>() {
@Override
public Name apply(Name input) {
return LdapUtils.removeFirst(input, baseLdapPath);
}
});
}
public User updateUser(String userId, User user) {
LdapName originalId = LdapUtils.newLdapName(userId);
User existingUser = userRepo.findOne(originalId);
existingUser.setFirstName(user.getFirstName());
existingUser.setLastName(user.getLastName());
existingUser.setFullName(user.getFullName());
existingUser.setEmail(user.getEmail());
existingUser.setPhone(user.getPhone());
existingUser.setTitle(user.getTitle());
existingUser.setDepartment(user.getDepartment());
existingUser.setUnit(user.getUnit());
if (directoryType == DirectoryType.AD) {
return updateUserAd(originalId, existingUser);
} else {
return updateUserStandard(originalId, existingUser);
}
}
/**
* Update the user and - if its id changed - update all group references to
* the user.
*
* @param originalId
*            the original id of the user.
* @param existingUser
*            the user, populated with new data
*
* @return the updated entry
*/
private User updateUserStandard(LdapName originalId, User existingUser) {
User savedUser = userRepo.save(existingUser);
if (!originalId.equals(savedUser.getId())) {
//The user has moved - we need to update group references.
LdapName oldMemberDn = toAbsoluteDn(originalId);
LdapName newMemberDn = toAbsoluteDn(savedUser.getId());
Collection<Group> groups = groupRepo.findByMember(oldMemberDn);
updateGroupReferences(groups, oldMemberDn, newMemberDn);
}
return savedUser;
}
/**
* Special behaviour in AD forces us to get the group membership before the
* user is updated, because AD clears group membership for removed entries,
* which means that once the user is update we've lost track of which groups
* the user was originally member of, preventing us to update the membership
* references so that they point to the new DN of the user.
*
* This is slightly less efficient, since we need to get the group
* membership for all updates even though the user may not have been moved.
* Using our knowledge of which attributes are part of the distinguished
* name we can do this more efficiently if we are implementing specifically
* for Active Directory - this approach is just to highlight this quite
* significant difference.
*
* @param originalId
*            the original id of the user.
* @param existingUser
*            the user, populated with new data
*
* @return the updated entry
*/
private User updateUserAd(LdapName originalId, User existingUser) {
LdapName oldMemberDn = toAbsoluteDn(originalId);
Collection<Group> groups = groupRepo.findByMember(oldMemberDn);
User savedUser = userRepo.save(existingUser);
LdapName newMemberDn = toAbsoluteDn(savedUser.getId());
if (!originalId.equals(savedUser.getId())) {
//The user has moved - we need to update group references.
updateGroupReferences(groups, oldMemberDn, newMemberDn);
}
return savedUser;
}
private void updateGroupReferences(Collection<Group> groups,
Name originalId, Name newId) {
for (Group group : groups) {
group.removeMember(originalId);
group.addMember(newId);
groupRepo.save(group);
}
}
public List<User> searchByNameName(String lastName) {
return userRepo.findByFullNameContains(lastName);
}
}

Pendant le dépannage,

J'ai remarqué que, l'échec de l'application que lorsque j'ai utilisé les deux JPA et LDAP ensemble. Quand j'ai enlevé toutes les APC, les dépendances et la mise en œuvre, l'application fonctionne comme prévu.

Le problème semble être causé par le conflit entre la JPA et LDAP dépendances. Mais je ne suis pas sûr de la façon de le résoudre.

OriginalL'auteur Jane | 2015-09-23