스프링 보안 LDAP 및 리멤버 미
LDAP와 통합된 Spring Boot으로 앱을 만들고 있습니다.LDAP 서버에 접속하여 사용자를 인증할 수 있었습니다.Remember-Me 기능을 추가해야 합니다.여러 게시물을 살펴보려고 했지만 문제에 대한 답을 찾을 수 없었습니다.스프링 보안 공식 문서에는 다음과 같이 기술되어 있습니다.
UserDetails Service를 사용하지 않는 인증 공급자(LDAP 공급자 등)를 사용하는 경우 애플리케이션 컨텍스트에 UserDetails Service bean도 없으면 작동하지 않습니다.
여기 내 작업 코드와 리멤버 미 기능을 추가하기 위한 몇 가지 초기 생각이 있습니다.
Web Security Config
import com.ui.security.CustomUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.event.LoggerListener;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
String DOMAIN = "ldap-server.com";
String URL = "ldap://ds.ldap-server.com:389";
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/ui/**").authenticated()
.antMatchers("/", "/home", "/UIDL/**", "/ui/**").permitAll()
.anyRequest().authenticated()
;
http
.formLogin()
.loginPage("/login").failureUrl("/login?error=true").permitAll()
.and().logout().permitAll()
;
// Not sure how to implement this
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService())
;
}
@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper());
return provider;
}
@Bean
public UserDetailsContextMapper userDetailsContextMapper() {
UserDetailsContextMapper contextMapper = new CustomUserDetailsServiceImpl();
return contextMapper;
}
/**
* Impl of remember me service
* @return
*/
@Bean
public RememberMeServices rememberMeServices() {
// TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
// rememberMeServices.setCookieName("cookieName");
// rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
@Bean
public LoggerListener loggerListener() {
return new LoggerListener();
}
}
Custom User Details Service Impl
public class CustomUserDetailsServiceImpl implements UserDetailsContextMapper {
@Autowired
SecurityHelper securityHelper;
Log ___log = LogFactory.getLog(this.getClass());
@Override
public LoggedInUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> grantedAuthorities) {
LoggedInUserDetails userDetails = null;
try {
userDetails = securityHelper.authenticateUser(ctx, username, grantedAuthorities);
} catch (NamingException e) {
e.printStackTrace();
}
return userDetails;
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
}
}
어떻게든 User Service를 실장할 필요가 있다는 것은 알고 있습니다만, 그 실현 방법에 대해서는 잘 모르겠습니다.
LDAP 를 사용한 Remember Me 기능의 설정에는, 다음의 2개의 문제가 있습니다.
- 올바른 Remember Me 구현 선택(토큰 vs.영속적토큰)
- Spring의 Java Configuration을 사용한 구성
차근차근 진행하겠습니다.
미 「 」 。TokenBasedRememberMeServices
)는합니다.
- 사용자가 인증되고(agaisnt AD), 현재 사용자의 ID와 비밀번호를 알고 있습니다.
- 가치 사용자 이름 + 유효기간 구성Time + Password + static Key 및 MD5 해시 생성
- 사용자 이름 + 만료 + 계산된 해시가 포함된 쿠키를 만듭니다.
사용자가 서비스로 돌아와 remember me 기능을 사용하여 인증받기를 원할 경우 다음을 수행합니다.
- 쿠키가 존재하는지, 만료되지 않았는지 확인합니다.
- 쿠키에서 사용자 ID를 입력하고 제공된 UserDetails Service를 호출합니다.이 서비스는 패스워드를 포함한 사용자 ID와 관련된 정보를 반환하도록 요구됩니다.
- 그런 다음 반환된 데이터에서 해시를 계산하고 쿠키의 해시가 우리가 계산한 값과 일치하는지 확인합니다.
- 일치하는 경우 사용자의 Authentication 개체를 반환합니다.
해시 체크 프로세스는 아무도 다른 사용자를 가장할 수 있는 "fake" remember me cookie를 작성할 수 없도록 하기 위해 필요합니다.문제는 이 프로세스가 저장소에서 패스워드를 로드하는 가능성에 의존하지만 Active Directory에서는 불가능하다는 것입니다.사용자명에 따라 보통 텍스트의 패스워드를 로드할 수 없습니다.
이로 인해 토큰 기반 구현은 AD에서의 사용에 적합하지 않습니다(비밀번호나 다른 비밀 사용자 기반 자격 증명을 포함하는 로컬 사용자 저장소를 생성하기 시작하지 않는 한). 응용 프로그램의 다른 자세한 내용은 알 수 없으므로 이 방법을 제안하지 않습니다.
토큰을 미입니다('리멤버 미'는 영속적인 토큰을 기반으로 합니다.PersistentTokenBasedRememberMeServices
는 다음과 같이 동작합니다(조금 심플하게).
- 사용자가 인증할 때 랜덤 토큰을 생성합니다.
- 토큰과 관련된 사용자 ID에 대한 정보와 함께 토큰을 스토리지에 저장합니다.
- 토큰 ID가 포함된 쿠키를 만듭니다.
사용자가 인증을 원할 때 다음을 수행합니다.
- 토큰 ID를 가진 쿠키가 있는지 확인합니다.
- 토큰 ID가 데이터베이스에 있는지 확인
- 데이터베이스 내의 정보를 바탕으로 사용자 데이터를 로드하다
보시는 바와 같이 패스워드는 더 이상 필요하지 않습니다.다만, 현재는 패스워드 검증 대신에 사용되는 토큰 스토리지(일반적으로 데이타베이스, 테스트에 인메모리 사용 가능)가 필요합니다.
그러면 구성 부분으로 이동합니다.persistent-token-based remember me 기본 설정은 다음과 같습니다.
@Override
protected void configure(HttpSecurity http) throws Exception {
....
String internalSecretKey = "internalSecretKey";
http.rememberMe().rememberMeServices(rememberMeServices(internalSecretKey)).key(internalSecretKey);
}
@Bean
public RememberMeServices rememberMeServices(String internalSecretKey) {
BasicRememberMeUserDetailsService rememberMeUserDetailsService = new BasicRememberMeUserDetailsService();
InMemoryTokenRepositoryImpl rememberMeTokenRepository = new InMemoryTokenRepositoryImpl();
PersistentTokenBasedRememberMeServices services = new PersistentTokenBasedRememberMeServices(staticKey, rememberMeUserDetailsService, rememberMeTokenRepository);
services.setAlwaysRemember(true);
return services;
}
에서는 인메모리 토큰 스토리지는 토큰 스토리지로 됩니다.이 스토리지는 다음과 같이 대체해야 합니다.JdbcTokenRepositoryImpl
제공받은 것UserDetailsService
"리멤버 미 쿠키" "리멤버 미 쿠키"가장 간단한 구현은 다음과 같습니다.
public class BasicRememberMeUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new User(username, "", Collections.<GrantedAuthority>emptyList());
}
}
하나 더 줄 요.UserDetailsService
필요에 따라 AD 또는 내부 데이터베이스에서 추가 속성 또는 그룹 구성원 자격을 로드하는 구현입니다.하다
@Bean
public RememberMeServices rememberMeServices(String internalSecretKey) {
LdapContextSource ldapContext = getLdapContext();
String searchBase = "OU=Users,DC=test,DC=company,DC=com";
String searchFilter = "(&(objectClass=user)(sAMAccountName={0}))";
FilterBasedLdapUserSearch search = new FilterBasedLdapUserSearch(searchBase, searchFilter, ldapContext);
search.setSearchSubtree(true);
LdapUserDetailsService rememberMeUserDetailsService = new LdapUserDetailsService(search);
rememberMeUserDetailsService.setUserDetailsMapper(new CustomUserDetailsServiceImpl());
InMemoryTokenRepositoryImpl rememberMeTokenRepository = new InMemoryTokenRepositoryImpl();
PersistentTokenBasedRememberMeServices services = new PersistentTokenBasedRememberMeServices(internalSecretKey, rememberMeUserDetailsService, rememberMeTokenRepository);
services.setAlwaysRemember(true);
return services;
}
@Bean
public LdapContextSource getLdapContext() {
LdapContextSource source = new LdapContextSource();
source.setUserDn("user@"+DOMAIN);
source.setPassword("password");
source.setUrl(URL);
return source;
}
에 의해, 로해, 「LDAP」내에 하는 「 Me」됩니다.RememberMeAuthenticationToken
이 파일은 다음에서 입수할 수 있습니다.SecurityContextHolder.getContext().getAuthentication()
, 오브젝트 「」, 「LDAP」, 「User」)로 하기 위해서 CustomUserDetailsServiceImpl
를 참조해 주세요.
다른 주제로서 질문에 게재된 코드에도 문제가 있습니다.다음 항목을 교체해야 합니다.
authManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService())
;
포함:
authManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
;
userDetailsService에 대한 호출은 DAO 기반 인증을 추가하기 위해(예를 들어 데이터베이스에 대해) 이루어져야 하며 사용자 세부 정보 서비스를 실제로 구현하여 호출해야 합니다.현재 설정에서는 무한 루프가 발생할 수 있습니다.
의 예를 놓치고 있는 것처럼 들리네요.UserService
너의 것RememberMeService
에 대한 참조가 필요합니다.LDAP 를 사용하고 있기 때문에, 다음의 LDAP 버전이 필요합니다.UserService
JDBC/JPA의 실장만을 잘 알고 있습니다만,org.springframework.security.ldap.userdetails.LdapUserDetailsManager
당신이 찾고 있는 것입니다.그 후, 설정은 다음과 같습니다.
@Bean
public UserDetailsService getUserDetailsService() {
return new LdapUserDetailsManager(); // TODO give it whatever constructor params it needs
}
@Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", getUserDetailsService());
rememberMeServices.setCookieName("cookieName");
rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
언급URL : https://stackoverflow.com/questions/24745528/spring-security-ldap-and-remember-me
'source' 카테고리의 다른 글
WooCommerce - 커스텀 주문 상태 변경 시 커스텀 이메일 보내기 (0) | 2023.04.02 |
---|---|
구조물에 여러 개의 이름 태그를 정의하는 방법 (0) | 2023.04.02 |
재생 프레임워크 JsObject에서 Json 배열 구문 분석 (0) | 2023.04.02 |
제품 ID에 대한 PHP 변수와 함께 wc_get_product() 사용 (0) | 2023.04.02 |
현재 사용자가 wordpress에서 관리자인지 확인합니다. (0) | 2023.04.02 |