Cette question concerne l'utilisation de plusieurs bases de recherche de groupe au lieu d'une seule.

J'ai utilisé un exemple fourni par samaddico (simple spring security + exemple LDAP), je l'ai modifié pour une base de recherche de groupe unique avec le texte de configuration serveur / utilisateur / LDAP fourni. Il utilise un compte de service pour se connecter à ldap et un utilisateur qui tente ensuite de s'authentifier pour certaines pages Web simples. Cette approche fonctionne mais n'a pas la capacité de collecter les membres / rôles de différents groupes dans l'arborescence de recherche.

Spring Security fournit des classes LdapContextSource et MultipleLdapAuthoritiesPopulator pour permettre la recherche de rôles dans différents emplacements. Voici maintenant le code qui entraînera l'erreur ci-dessous:

Configuration LDAP:

* Create an implementation of org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator which can call 
multiple instances of LdapAuthoritiesPopulator.
 * Then create one LdapAuthoritiesPopulatorfor each 'groupSearchBase' that I wanted to query.

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

        LdapContextSource contextSource =   contextSource();

        MultipleLdapAuthoritiesPopulator multipleLdapAuthoritiesPopulator = new MultipleLdapAuthoritiesPopulator(
        new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseA),
        new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseB),
        new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseC));

        auth
            .ldapAuthentication()
            .contextSource(contextSource)
            .ldapAuthoritiesPopulator(multipleLdapAuthoritiesPopulator)
            .userSearchFilter(ldapUserSearchFilter)
            .userSearchBase(ldapUserSearchBase);
    }

    class MultipleLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
        private List<LdapAuthoritiesPopulator> authoritiesPopulators;

        public MultipleLdapAuthoritiesPopulator(LdapAuthoritiesPopulator...authoritiesPopulators) {
            this.authoritiesPopulators = Arrays.asList(authoritiesPopulators);
        }

        @Override
        public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
            List<GrantedAuthority> grantedAuthorities = authoritiesPopulators.stream()
                    .map(authPopulator -> authPopulator.getGrantedAuthorities(userData, username))
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());
            return grantedAuthorities;
        }
    }

    /**
     * Creates context source object instead of configuring it with AuthenticationBuilder
     * @return Context source object used for accessing ldap server
     */
    @Bean
    public LdapContextSource contextSource() {
        LdapContextSource contextSource= new LdapContextSource();
        contextSource.setUrl(ldapUrl);
        contextSource.setUserDn(ldapManagerDn);
        contextSource.setPassword(ldapManagerPassword);
        contextSource.afterPropertiesSet();
        return contextSource;
    }

Configuration de la session:

/**
 * This is essential to make sure that the Spring Security session registry is notified when the session is destroyed.
 * @return
 */
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}

L'application Spring m'indique que mon compte de service s'est connecté avec succès au serveur LDAP.

DEBUG 17220 --- [nio-8080-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@c1e15be1: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 127.0.0.1; SessionId: 0A82CE8FA4FB9EB248D756EEE8134CAE; Granted Authorities: ROLE_ANONYMOUS

L'erreur est ensuite renvoyée lorsque l'utilisateur trouvé tente de se lier:

DEBUG 17220 --- [nio-8080-exec-8] o.s.s.l.a.BindAuthenticator              : Failed to bind as CN=familyName\, name,OU=Group: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839 ]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839 ]
DEBUG 17220 --- [nio-8080-exec-8] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

Pour résumer: mes informations d'identification sont correctes pour une base de groupe unique sans utiliser LdapContextSource et MultipleLdapAuthoritiesPopulator. Mais le processus d'authentification ne semble pas fournir le mot de passe enteret pour mon utilisateur avec plusieurs bases de groupe.

0
GoToJack 19 févr. 2021 à 18:25

1 réponse

Meilleure réponse

Après avoir passé un certain temps à trouver une solution, j'ai dû admettre qu'il n'y avait aucun moyen efficace de créer une solution, c'est-à-dire avec des méthodes ou des classes d'écrasement.

Mais je suis tombé sur une demande de changement pour la sécurité du printemps, précisément pour ce cas d'utilisation lorsque plusieurs bases de recherche de groupe doivent être vérifiées. Il est implémenté depuis la version 5.4.1 de Spring Security (je crois) ou inclus lors de l'utilisation de la version parent 2.4.2 de Spring Starter.

Ajoutez simplement l'option à votre méthode d'authentification:

.groupSearchSubtree(true)

L'exemple de méthode mis à jour complet pour l'authentification ressemble alors à ceci:

    @Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{   
    auth
            .ldapAuthentication()
            .contextSource()
            .url(ldapUrl)
            .managerDn(ldapManagerDn)
            .managerPassword(ldapManagerPassword)
       .and()
            .userSearchFilter(ldapUserSearchFilter)
            .userSearchBase(ldapUserSearchBase)
            .groupSearchFilter(ldapGroupSearchFilter)
            .groupSearchBase(ldapGroupSearchBase)
            .groupSearchSubtree(true)
    ;

Vous voyez qu'il n'est plus nécessaire de transférer trois nœuds différents et plus d'objet de contexte personnalisé, ajoutez simplement le nœud parent pour la base de recherche de groupe et laissez la recherche de sous-arborescence faire le reste.

Cela aurait peut-être été bien de trouver un moyen par moi-même, mais utiliser une solution intégrée du cadre est sûrement la meilleure façon de procéder.

0
GoToJack 8 mars 2021 à 12:30