Обход Spring ldapAuthentication () с inMemoryAuthentication () для среды разработки - PullRequest
0 голосов
/ 11 февраля 2020

Будучи новичком в Spring Framework, я работаю над проектом для моей компании, где они используют аутентификацию LDAP. Для разработки в коде используется тестовая аутентификация "ldif" (ApacheDS). Затем зарегистрированные данные пользователя (сеанс) сохраняются в CustomLdapUserDetails (реализует LdapUserDetails). Затем CustomLdapUserDetails используется повсеместно в приложении для получения информации о сеансе.

Проблема

Во время разработки каждый раз, когда я перекомпилирую проект, чтобы увидеть, как отражаются мои изменения в приложении сеанс истекает. Это происходит потому, что при каждом перезапуске среда Spring удаляет каталог ApacheDS.

I wi sh, чтобы найти решение этой проблемы, поскольку я не могу войти снова и снова. Я уже пытался выполнить аутентификацию в памяти, добавив следующее:

authManagerBuilder.inMemoryAuthentication().withUser("user").password("test2").authorities("SUPER_ADMIN");

Поскольку проект использует CustomLdapUserDetails вместо UserDetails, я получаю ошибку приведения:

org.springframework.security.core.userdetails.User cannot be cast to com.domain.configuration.datasource.CustomLdapUserDetails

Любая помощь будет принята с благодарностью.

SecurityConfiguration. java

package com.domain.configuration;

import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.domain.configuration.datasource.CustomLdapUserMapper;
import com.domain.model.RoleType;

@Configuration 
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("com.domain")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @SuppressWarnings("unused")
    private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

    private static final String[] IGNORED_RESOURCE_LIST = new String[] {"/assets/**", "/static/**", "classpath:/resources/pdf_rendering/**", "/bdd/**"};
    private static final String[] PERMITALL_RESOURCE_LIST = new String[] {"/json/**", "/errors/**", "/login", "/lostPassword"};
    private static final String[] ADMIN_RESOURCE_LIST = new String[] {"/template/admin**"};
    private static final String[] ADMIN_ROLES = new String[] {RoleType.SUPER_ADMIN.toString(), RoleType.CENTRAL_ADMIN.toString()};

    @Value("${ldap.mocked.file}")
    private String ldapMockedFile;

    @Value("${ldap.url}")
    private String ldapUrl;

    @Value("${ldap.user.search.filter}")
    private String ldapUserSearchFilter;

    @Value("${ldap.user.search.base}")
    private String ldapUserSearchBase;

    @Value("${ldap.managerDn}")
    private String managerDn;

    @Value("${ldap.managerPasswd}")
    private String managerPw;

    @Value("${spring.profiles.active}")
    private String profil;

    @Autowired
    private CustomLdapUserMapper customLdapMapper;

    @Override
    /**
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(WebSecurity)
     */
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(IGNORED_RESOURCE_LIST);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable().authorizeRequests().antMatchers(PERMITALL_RESOURCE_LIST).permitAll().antMatchers(ADMIN_RESOURCE_LIST)
                .hasAnyRole(ADMIN_ROLES).anyRequest().authenticated();

        http.formLogin().failureUrl("/login?error").defaultSuccessUrl("/home").loginPage("/login").defaultSuccessUrl("/home", true)
                .permitAll().and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
                .permitAll().and().exceptionHandling().accessDeniedPage("/403");

        http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin();

    }



    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {

        LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> provider = authManagerBuilder.ldapAuthentication()
                .userDetailsContextMapper(this.customLdapMapper);
        provider = provider.userSearchFilter(this.ldapUserSearchFilter);
        provider.ldapAuthoritiesPopulator(generateMockLdapAuthoritiesPopulatorForAd());
        if (this.ldapUserSearchBase != null && !this.ldapUserSearchBase.isEmpty()) {
            provider = provider.userSearchBase(this.ldapUserSearchBase);
        }

        if ("dev".equals(this.profil) || "qualif".equals(this.profil)) {
            provider.contextSource().ldif(this.ldapMockedFile);
        } else {
            provider.contextSource().managerDn(managerDn);
            provider.contextSource().managerPassword(managerPw);
            provider.contextSource().url(this.ldapUrl); 
        }

        authManagerBuilder.inMemoryAuthentication().withUser("user").password("test2").authorities("SUPER_ADMIN");
    }

    /**
     * Company's AD does not support basic ldap authorities, we handle them differently.
     * @return
     */
    private LdapAuthoritiesPopulator generateMockLdapAuthoritiesPopulatorForAd() {
        return new LdapAuthoritiesPopulator() {
            @Override
            public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData,
                    String username) {
                // Roles are not handled by AD
                return null;
            }
        };
    }
}

CustomLdapUserDetails. java

package com.domain.configuration.datasource;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.userdetails.LdapUserDetails;

import com.domain.dto.RoleDto;

public class CustomLdapUserDetails implements LdapUserDetails {
    private static final long serialVersionUID = 1L;

    private LdapUserDetails details;

    private String firstname;

    private String lastname;

    private RoleDto roleDto;

    private Locale locale;

    private Long countryId;

    public CustomLdapUserDetails(LdapUserDetails details) {
        this.details = details;
    }

    /**
     * @return the firstname
     */
    public String getFirstname() {

        return this.firstname;
    }

    /**
     * @param firstname
     *            the firstname to set
     */
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    /**
     * @return the lastname
     */
    public String getLastname() {
        return this.lastname;
    }

    /**
     * @param lastname
     *            the lastname to set
     */
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    /**
     * @return the roleDto
     */
    public RoleDto getRole() {
        return this.roleDto;
    }

    /**
     * @param roleDto
     *            the roleDto to set
     */
    public void setRole(RoleDto roleDto) {
        this.roleDto = roleDto;
    }

    /**
     * @return the locale
     */
    public Locale getLocale() {
        return this.locale;
    }

    /**
     * @param locale
     *            the locale to set
     */
    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    @Override
    public boolean isEnabled() {
        return this.details.isEnabled();
    }

    @Override
    public String getDn() {
        return this.details.getDn();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(this.roleDto.getType().toString()));
        return authorities;
    }

    @Override
    public String getPassword() {
        return this.details.getPassword();
    }

    @Override
    public String getUsername() {
        return this.details.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return this.details.isAccountNonExpired();
    }

    @Override
    public boolean isAccountNonLocked() {

        return this.details.isAccountNonLocked();
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return this.details.isCredentialsNonExpired();
    }

    /**
     * @return the countryId
     */
    public Long getCountryId() {
        return this.countryId;
    }

    /**
     * @param countryId
     *            the countryId to set
     */
    public void setCountryId(Long countryId) {
        this.countryId = countryId;
    }

}

CustomLdapUserMapper. java

package com.domain.configuration.datasource;

import java.util.Collection;

import org.apache.commons.lang3.LocaleUtils;
import org.parboiled.common.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.stereotype.Component;

import com.domain.dto.UserDto;
import com.domain.service.interfaces.UserService;

@Component
public class CustomLdapUserMapper extends LdapUserDetailsMapper {

    private static final Logger logger = LoggerFactory.getLogger(CustomLdapUserMapper.class);

    @Autowired
    private UserService userService;

    @Value("${ldap.ad.group.filter}")
    private String groupFilter;

    @Value("${ldap.ad.member.attribute}")
    private String memberOf;



    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
        logger.debug("connection attempt from user: "+username);
        boolean userIsFromGroup = false;
        if (!StringUtils.isEmpty(groupFilter)) {
            Object[] objectAttributes = ctx.getObjectAttributes(memberOf);
            for (int i = 0; i < objectAttributes.length; i++) {
                if(objectAttributes[i].toString().contains(groupFilter)) {
                    userIsFromGroup = true;
                };
            }
            if (!userIsFromGroup) {
                logger.debug("User "+username+" not found in the directory service.");
                throw new UsernameNotFoundException(String.format("User with username=%s was not found", username));
            }
        }
        final UserDto userInfo = this.userService.getUserByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException(String.format("User with username=%s was not found", username)));
        logger.info(String.format("Find role of User=%s as role_Id=%s", username, userInfo.getRole().getId()));
        UserDetails details = super.mapUserFromContext(ctx, username, AuthorityUtils.createAuthorityList(userInfo.getRole().toString()));

        CustomLdapUserDetails customLdapUser = new CustomLdapUserDetails((LdapUserDetails) details);
        customLdapUser.setFirstname(userInfo.getFirstname());
        customLdapUser.setLastname(userInfo.getLastname());
        customLdapUser.setRole(userInfo.getRole());
        customLdapUser.setLocale(LocaleUtils.toLocale(userInfo.getLocale().getCode()));
        customLdapUser.setCountryId(userInfo.getRegion().getBusinessUnitDto().getCountryDto().getId());
        return customLdapUser;
    }
}

...