LoginSignup
66
72

More than 5 years have passed since last update.

Spring Security(Spring Boot)で、PreAuthentication

Last updated at Posted at 2014-06-29

シングルサインオン基盤との連携

Spring Securityでは、シングルサインオン基盤との連携機能もあるらしい。
ちとややこしいが、ひとまず動いたっぽいので、メモ。

下記に機能追加、修正を加える。
http://qiita.com/masatsugumatsus/items/f80819218bb1fa424470

作成するクラス

1.MyPreAuthenticatedFilter

事前にシングルサインオン基盤等でリクエストに埋め込まれた認証情報(principals,credentials)を取り出す。
  AbstractPreAuthenticatedProcessingFilterを継承して作成する。

2.MyUserDetailsService

1.で取り出された認証情報から、アプリケーションで利用するユーザー情報を作成する。AuthenticationUserDetailsServiceを拡張する。後述するPreAuthenticatedAuthenticationProviderにセットするが、その場合は、   AuthenticationUserDetailsService#loadUserDetailsメソッドの引数は   PreAuthenticatedAuthenticationTokenとなるため、AuthenticationUserDetailsServiceとして継承を行う。

3.MyUserAuthority、MyAdminAuthority

一般利用者権限と、管理者権限クラス。GrantedAuthorityを実装する。ま、権限のクラス設計は色々あると思うが、ひとまず、別クラスにした。共通の親クラスを作るべきとは思う。

ざっくりとした流れの解説

  • PreAuthentifiatedFilterで認証情報を取り出し、フィルタ内の処理で、AuthenticationManagerに認証処理を委譲し、認証結果となるAuthenticationオブジェクトをセッションとスレッドローカルに保存する。(Spring Securityは基本、Authenticationオブジェクトを見て、認証、アクセス制御を行う。)
  • AuthenticationManagerのデフォルト実装であるProviderManagerは内部のAuthenticationProviderに処理を委譲する。今回は、Spring Securityが提供するPreAuthenticatedAuthenticationProviderをそのまま設定する。
  • PreAuthenticatedAuthenticationProvider内部ではreAuthentifiatedFilterで取得された認証情報からAuthenticationUserDetailsServiceを利用して、ユーザー情報を作成しているので、今回はAuthenticationUserDetailsServiceを拡張したクラスを設定する。

ソース

WebSecurityConfig.java
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> 
                authenticationUserDetailsService() {
        return new MyUserDetailsService();
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider 
                    preAuthenticatedAuthenticationProvider() {
        PreAuthenticatedAuthenticationProvider provider
            = new PreAuthenticatedAuthenticationProvider();

        provider.
            setPreAuthenticatedUserDetailsService(authenticationUserDetailsService());

        provider.
            setUserDetailsChecker(new AccountStatusUserDetailsChecker());

        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(
                preAuthenticatedAuthenticationProvider()
                );
    }

    @Bean
    public AbstractPreAuthenticatedProcessingFilter preAuthenticatedProcessingFilter()
            throws Exception {
        MyPreAuthentifiatedFilter filter = new MyPreAuthenticatedFilter();

        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilter(preAuthenticatedProcessingFilter());

        http.authorizeRequests().antMatchers("/", "/home").permitAll()
                // 管理者ページの追加
                .antMatchers("/admin").hasRole("ADMIN").anyRequest()
                .authenticated();
        http.formLogin().loginPage("/login").permitAll().and().logout()
                .permitAll();
    }

}
MyPreAuthenticatedFilter.java
public class MyPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter{

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        //リクエストからユーザーID等のユーザー情報を抽出
        return "user01";
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        //リクエストから証明書情報を抽出。DB等にある場合もある?
        return "";
    }

}
MyUserDetailsService.java
public class MyUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

    @Override
    public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
            throws UsernameNotFoundException {
        String userName=(String)token.getPrincipal();
        Object credentials = token.getCredentials();

        //principalとcredentialsを利用して、ユーザー情報を作成。今回は適当にサンプル作成
        Collection<GrantedAuthority> authorities =new HashSet<GrantedAuthority>() ;
        authorities.add(new MyAdminAuthority());
        User user = new User(userName,"",authorities);

        //パスワード渡すとかあり得ないと思うので、別途自分で作成するべき。
        return user;
    }

}
MyAdminAuthority.java
public class MyAdminAuthority implements GrantedAuthority {

    @Override
    public String getAuthority() {
        return "ROLE_ADMIN";    
    }

}
MyUserAuthority.java
public class MyUserAuthority implements GrantedAuthority {

    @Override
    public String getAuthority() {
        return "ROLE_USER";
    }

}

ドキュメントを見ても、狙い通りの動きをするかは正確には分からないので、ソース見るしかない。でも、ソースが十分分かり易いので、それほど困らない。ドキュメントはコンセプト、概要、詳細はソース読めっていうのは、プログラマ向けの成果物としては合理的。Springのドキュメントは豊富で素晴らしいというのは、当然前提としての感想です。

66
72
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
66
72