🤖
Spring Security
- Main機能
- 認証
- 認可
- 強化機能
- Session機能
- CSRF機能
- ブラウザのセキュリティ対策機能との連携機能
Spring Security Module Structures
Module Name | Description |
---|---|
spring-security-core | 認証と認可機能を実現するためのcore component |
spring-security-web | WebアプリケーションのSecurity対策を実現するためのcomponent |
spring-security-config | 各moduleから提供されているcomponentのsetupをsupportするためのcomponent |
Spring Security Architecture
- client -> WebApplication request
- SpringSecurityの
FilterChainProxy
クラス(Servlet Filter)がリクエストを受け取り、HttpFirewall interfaceのmethodを呼び出してHttpServletRequest
とHttpServletResponse
に対してfirewall機能を組み込む -
FilterChainProxy
クラスは、SecurityFilterChain
に設定されているsecurity対策用のsecurity fileterクラスに処理を委譲する -
SecurityFilterChain
には複数のSecurity Filterが設定されていて、SecurityFilterの処理が正常に終了すると後続のSecurityFilterが実行される - 最後のSecurityFilterの処理が正常に終了した場合、後続処理(ServletFilterやServletなど)を呼び出し、WebApplication内のリソースへアクセスする
-
SecurityFilterChain
クラスは、WebApplicationが返却したリソースをclientに返却する
Authentication Process Flow
- clientは、認証処理を行うpathに対して資格情報(username/password/token)を指定してリクエストを送信
-
AuthenticationFilter
は資格情報を取得し、AuthenticationManager
classの認証処理を呼び出す -
ProviderManager
は実際の認証処理をAuthenticationProvider
interfaceの実装に委譲する -
DaoAuthenticationProvider
は、UserDetailsService
のユーザー情報取得処理を呼び出す -
UserDetailsService
の実装classは、datasourceからユーザー情報を取得する -
UserDetailsService
の実装classは、datasourceから取得したユーザー情報からUserDetailを生成する -
DaoAuthenticatorProvider
は、UserDetailsServiceから返却されたUserDetailsとclientが指定した認証情報との照合を行い認証結果を返す -
AuthenticationFilter
classはAuthenticationManager
から返却された認証結果をhandlingする- 認証成功:
AuthenticationSuccessHandler
にてhandling - 認証失敗:
AuthenticationFailureHandler
にてhandling
- 認証成功:
- Authentication Filter
- 認証方式に対する実装を提供するServletFilter
- Basic認証ServletFilter
- Digest認証ServletFilter
- RememberMe認証ServletFilter
- 認証方式に対する実装を提供するServletFilter
- Authentication Manager
- 認証処理を実行するためのinterface
- default実装(
ProviderManager
): 認証処理はAuthenticationProvider
に委譲し、AuthenticationProvider
で行われた認証処理の結果をhandling
- Authentication Provider
- 認証処理を実装を提供するためのinterface
Authentication Event Handling
Spring Securityは、Spring Frameworkが提供しているEvent通知の仕組みを利用して、認証処理の処理結果を他のcomponentへ連携する仕組みを提供している.この機能を利用することで、以下のような機能を容易に実装することができる.
- 認証成功or失敗などの認証履歴をdatabaseやログに保存したい
- Passwordを連続して間違った場合、アカウントをロックしたい
- SpringSecurityの認証機能は、認証結果(認証情報や認証例外)を
AuthenticationEventPublisher
に渡して認証イベントの通知依頼を行う -
AuthenticationEventPublisher
interfaceのdefaultの実装クラスは、認証結果に対応する認証Event classのinstanceを生成し、ApplicationEventPublisher
に渡してEventの通知依頼を行う -
ApplicationEventPublisher
interfaceの実装は、ApplicatioinListener
interfaceの実装classにeventを通知する -
ApplicationListener
の実装classの1つであるApplicationListenerMethodAdaptor
は、@org.springframework.context.EventListener
が付与されているmethodを呼び出してEventを通知する
Event Class | Description |
---|---|
AuthenticationSuccessEvent | AuthenticationProviderによる認証処理が成功したことを通知(後続の認証処理で失敗する可能性あり) |
SessionFixationProtectionEvent | Session固定攻撃対策の処理が成功したことを通知 |
InteractiveAuthenticationSuccessEvent | 認証処理がすべて成功したことを通知 |
AuthenticationFailureBadCredentialsEvent | BadCredentialsExceptionが発生したことを通知 |
AuthenticationFailureDisableEvent | DisabledExceptionが発生したことを通知 |
...etc | ...etc |
@Component
public class AuthenticationEventListeners {
private static final Logger log = LoggerFactory.getLogger(AuthenticationEventListeners.class);
public void handleBadCredential(AuthenticationFailureBadCredentialsEvent event) {
log.info("Bad credentials is detected. username: {}", event.getAuthentication().getName());
// 任意の処理
}
}
Authorization Process
- clientが任意のresourceにアクセス
-
FilterSecurityInterceptor
classは、AccessDecisionManager
interfaceのmethodを呼び出し、resourceへのアクセス権限の有無をチェックする -
AffirmativeBased
classは、AccessDecisionVoter
interfaceのmethodの呼び出し、アクセス権限の有無を投票してもらう -
FilterSecurityInterceptor
は、AccessDecisionManager
によってアクセス権限が付与された場合のみ、resourceへアクセスする
-
FilterSeurityInterceptor
- http requestに対して認可処理を適用するためのServletFilter
-
AccessDecisionManager
- アクセスしようとしたresourceに対してアクセス権限があるかチェックを行うためのinterface
-
AccessDecisionVoter
- アクセスしようとしたresourceに指定されているaccess policyを参照し、アクセス権を付与するか、投票(付与/拒否/棄権)するためのinterface
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
ReservationUserDetailsService userDetailsService;
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/js/**", "/css/**").permitAll().antMatchers("/**").authenticated().and()
.formLogin().loginPage("/loginForm").loginProcessingUrl("/login").usernameParameter("username")
.passwordParameter("password").defaultSuccessUrl("/rooms", true).failureUrl("/loginForm?error=true")
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
Discussion