9

spring-security-oauth2 2.0.7 の設定に関して 1 つ質問があります。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ように、更新中に新しいアクセス トークンを取得しようとするときに使用するようにを設定する必要があります。

私の知る限り、これはspring-security-oauth2の次の変更と関係があります。

残念ながら、うまく設定できませんでした。

org.springframework.security.oauth2.provider.token.DefaultTokenServices#setAuthenticationManager

呼ばれてAuthenticationManager注射を受ける。LdapUserDetailsServiceどのように注射されるのか理解できません。私が見る唯一のことはPreAuthenticatedAuthenticationProvider、トークン更新呼び出し中にユーザーを再認証しようとしているときに呼び出されることです。

誰かがそれを行う方法について私にアドバイスできますか?

ps:私が取得している例外は次のとおりです。

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.
4

3 に答える 3

5

ログイン認証を解決AuthenticationProviderする実装ではなくカスタムで JWT トークンを使用して OAuth2 サーバーを実装していたときに、同様の問題が発生しました。UserDetailsService

しかし最近、正しく動作させたい場合は、Spring が発生させるエラーが正しいことがわかりましたrefresh_token。実装では、トークンを で更新するAuthenticationProviderことは不可能refresh_tokenです。そのような実装では、パスワードが正しいかどうかを解決する必要がありますが、更新トークンにはその情報がありません。ただし、UserDetailsServiceパスワードに依存しません。

のバージョン 2.0.6 はspring-security-oauth2、ユーザー許可をチェックせず、リフレッシュ トークンが有効かどうか (秘密鍵で署名されているかどうか) をチェックするだけなので、機能しますが、最初のログイン後にユーザーがシステムから削除された場合、リフレッシュ トークンを使用すると、削除されたユーザーはシステムに無期限にアクセスできます。これはセキュリティ上の大きな問題です。

私がこれで報告した問題を見てください: https://github.com/spring-projects/spring-security-oauth/issues/813

于 2016-08-01T13:03:31.740 に答える
4

OAuth ピースに必要なのは、LdapUserDetailsServiceオーセンティケーターと同じクエリで を作成し、それを に挿入することAuthorizationServerEndpointsConfigurerです。UserDetailServiceスタイルで作成するためのサポートはないと思います@Configuration(JIRA でチケットを開く価値があるかもしれません) が、XML でできるようです。

于 2015-06-04T06:44:35.797 に答える
4

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})
于 2015-06-11T08:24:02.467 に答える