[SPRING] spring-security-oauth2 2.0.7 새로 고침 토큰 UserDetailsService 구성 - UserDetailsService가 필요합니다.
SPRINGspring-security-oauth2 2.0.7 새로 고침 토큰 UserDetailsService 구성 - UserDetailsService가 필요합니다.
나는 spring-security-oauth2 2.0.7의 설정에 관해서 하나의 질문을 할 것이다. GlobalAuthenticationConfigurerAdapter를 통해 LDAP를 사용하여 인증을 수행하고 있습니다.
@SpringBootApplication
@Controller
@SessionAttributes("authorizationRequest")
public class AuthorizationServer extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(AuthorizationServer.class, args);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/oauth/confirm_access").setViewName("authorize");
}
@Configuration
public static class JwtConfiguration {
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "foobar".toCharArray())
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
@Bean
public JwtTokenStore jwtTokenStore(){
return new JwtTokenStore(jwtAccessTokenConverter());
}
}
@Configuration
@EnableAuthorizationServer
public static class OAuth2Config extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
@Inject
private AuthenticationManager authenticationManager;
@Inject
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Inject
private JwtTokenStore jwtTokenStore;
@Inject
private UserDetailsService userDetailsService;
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(jwtTokenStore);
tokenServices.setAuthenticationManager(authenticationManager);
return tokenServices;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(jwtTokenStore).accessTokenConverter(
jwtAccessTokenConverter).userDetailsService(userDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));
}
}
@Configuration
@Order(-10)
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
}
@Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=groups")
.contextSource().ldif("classpath:test-server.ldif");
}
}
}
새로 고침 토큰은 spring-security-oauth2 릴리스 2.0.6에서 제대로 작동하지만 버전 2.0.7에서는 더 이상 작동하지 않습니다. 여기서 읽으면서 새로 고침 중에 새로운 액세스 토큰을 얻으려고 할 때 AuthenticationManager를 사용하도록 설정해야합니다.
내가 이해하는 한, 이것은 봄 보안 oauth2의 다음 변경 사항과 관련이 있습니다.
불행히도 제대로 설정하지 못했습니다.
org.springframework.security.oauth2.provider.token.DefaultTokenServices#setAuthenticationManager
AuthenticationManager가 호출되도록합니다. 나는 LdapUserDetailsService가 어떻게 주입 될지 이해하지 못한다. 내가 보는 유일한 것은 토큰 새로 고침 호출 중에 사용자를 다시 인증하는 동안 PreAuthenticatedAuthenticationProvider가 호출된다는 것입니다.
아무도 내게 조언 해 줄 수 있니?
추신 : 내가 받고있는 예외는 다음과 같습니다 :
p.PreAuthenticatedAuthenticationProvider : PreAuthenticated authentication request: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@5775: Principal: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@441d5545: Principal: bob; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER
o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: IllegalStateException, UserDetailsService is required.
해결법
-
==============================
1.로그인 인증을 해결하기 위해 UserDetailsService 구현 대신 사용자 정의 AuthenticationProvider를 사용하여 JWT 토큰을 사용하여 OAuth2 서버를 구현할 때 비슷한 문제가 발생했습니다.
로그인 인증을 해결하기 위해 UserDetailsService 구현 대신 사용자 정의 AuthenticationProvider를 사용하여 JWT 토큰을 사용하여 OAuth2 서버를 구현할 때 비슷한 문제가 발생했습니다.
하지만 최근에 나는 refresh_token이 올바르게 작동하기를 원한다면 스프링이 올리는 오류가 맞다는 것을 발견했다. AuthenticationProvider 구현에서는 refresh_token으로 토큰을 새로 고치는 것은 불가능합니다. 그 종류의 구현에서는 비밀번호가 맞지만 새로 고침 토큰에 해당 정보가 없으면 해결해야하기 때문입니다. 그러나 UserDetailsService는 암호를 알지 못합니다.
spring-security-oauth2의 버전 2.0.6은 사용자 허가를 확인하지 않고 새로 고침 토큰이 유효한지 (개인 키로 서명 된) 만 확인하기 때문에 작동하지만 처음 로그인 한 후 사용자가 시스템에서 삭제 된 경우, 새로 고침 토큰을 사용하면 삭제 된 사용자가 시스템에 무한 시간 액세스 할 수 있습니다. 이는 큰 보안 문제입니다.
이 문제를보고 싶습니다. https://github.com/spring-projects/spring-security-oauth/issues/813
-
==============================
2.Dave Syer의 조언에 따라 맞춤 LdapUserDetailsService를 만들었습니다. 작업 솔루션은 다음 태그 아래에 있습니다.
Dave Syer의 조언에 따라 맞춤 LdapUserDetailsService를 만들었습니다. 작업 솔루션은 다음 태그 아래에 있습니다.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <context:property-placeholder location="application.yml"/> <bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"> <constructor-arg value="${authentication.ldap.url}" /> </bean> <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> <constructor-arg index="0" value="${authentication.ldap.userSearchBase}" /> <constructor-arg index="1" value="uid={0}" /> <constructor-arg index="2" ref="contextSource"/> </bean> <bean id="ldapAuthoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator"> <constructor-arg index="0" ref="contextSource"/> <constructor-arg index="1" value="${authentication.ldap.groupSearchBase}"/> <property name="groupSearchFilter" value="${authentication.ldap.groupSearchFilter}"/> </bean> <bean id="myUserDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService"> <constructor-arg index="0" ref="userSearch"/> <constructor-arg index="1" ref="ldapAuthoritiesPopulator"/> </bean> </beans>
authentication: ldap: url: ldap://127.0.0.1:33389/dc=springframework,dc=org userSearchBase: userDnPatterns: uid={0},ou=people groupSearchBase: ou=groups groupSearchFilter: (uniqueMember={0})
-
==============================
3.OAuth 부분에 필요한 것은 authenticator와 동일한 쿼리를 사용하여 LdapUserDetailsService를 만들고이를 AuthorizationServerEndpointsConfigurer에 삽입하는 것입니다. @Configuration 스타일로 UserDetailService를 생성하는 것에 대한 지원이 없다고 생각합니다 (JIRA에서 티켓을 열어 볼만한 가치가있을 수 있습니다). 그러나 XML로 할 수있는 것처럼 보입니다.
OAuth 부분에 필요한 것은 authenticator와 동일한 쿼리를 사용하여 LdapUserDetailsService를 만들고이를 AuthorizationServerEndpointsConfigurer에 삽입하는 것입니다. @Configuration 스타일로 UserDetailService를 생성하는 것에 대한 지원이 없다고 생각합니다 (JIRA에서 티켓을 열어 볼만한 가치가있을 수 있습니다). 그러나 XML로 할 수있는 것처럼 보입니다.
from https://stackoverflow.com/questions/30454480/spring-security-oauth2-2-0-7-refresh-token-userdetailsservice-configuration-us by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring Security와의 CSRF 통합시 Session timeout으로 인해 Spring MVC에서 Access Denied가 발생합니다. (0) | 2019.04.06 |
---|---|
[SPRING] Spring MVC가 ArrayList를 컨트롤러로 전달 (0) | 2019.04.06 |
[SPRING] 스프링 빈을 JSF 변환기에 삽입하는 법 [duplicate] (0) | 2019.04.06 |
[SPRING] HSQLDB에서 스키마를 생성하는 시작 스크립트 (0) | 2019.04.06 |
[SPRING] RestTemplate을 사용하여 보안 쿠키 설정 (0) | 2019.04.06 |