在开发环境中将Spring ldapAuthentication()与inMemoryAuthentication()绕过

时间:2020-02-11 09:58:52

标签: java spring-boot spring-mvc spring-security ldap

作为Spring框架的初学者,我正在为我的公司从事一个使用LDAP身份验证的项目。对于开发,该代码使用“ ldif”(ApacheDS)测试身份验证。然后,已记录的用户详细信息(会话)将保存在CustomLdapUserDetails(实现LdapUserDetails)中。然后,在应用程序中的任何地方都使用CustomLdapUserDetails来检索会话信息。

问题

在进行开发时,每次我重新编译项目以查看更改如何反映在应用程序中时,该会话都会过期。发生这种情况是因为在每次重新启动时,Spring框架都会删除ApacheDS目录。

我希望能解决此问题,因为我无法一次又一次登录。我已经尝试通过添加以下内容来进行内存中身份验证:

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;
    }
}

0 个答案:

没有答案