現時点では、Spring-Security-Oauth2、Zuul、OpenAM を OAuth2 認証サーバーとして、WCF REST API をリソース サーバーとして統合しようとしています。最終的なセットアップは次のようになります。
spring と AngularJS を使用して SSO 環境をセットアップする方法を説明するチュートリアルを読みました ( sso with spring と angularJS )。ただし、私の場合は、OpenAM とパスワード付与フローを使用してユーザーを認証したいと考えています。したがって、Spring Boot アプリケーションでは、現在の構成は次のようになります。
@SpringBootApplication
@EnableZuulProxy
@EnableOAuth2Client
public class ApolloUIProxyApplication {
public static void main(String[] args) {
SpringApplication.run(ApolloUIProxyApplication.class, args);
}
@Configuration
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.logout().and().antMatcher("/**").authorizeRequests()
.antMatchers("/index.html", "/home.html", "/", "/login").permitAll()
.anyRequest().authenticated().and().csrf()
.csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterAfter(authenticationProcessingFilter(), CsrfFilter.class);
}
@Bean
public ZuulFilter tokenRelayFilter(){
JwtTokenRelayFilter filter = new JwtTokenRelayFilter();
filter.setRestTemplate(restTemplate());
return new JwtTokenRelayFilter();
}
@Bean
public ZuulFilter customTokenFilter(){
return new CustomZuulFilter();
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
return new JwtAccessTokenConverter();
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
private OAuth2ClientAuthenticationProcessingFilter authenticationProcessingFilter(){
OAuth2ClientAuthenticationProcessingFilter processingFilter = new OAuth2ClientAuthenticationProcessingFilter("/login");
processingFilter.setRestTemplate(restTemplate());
processingFilter.setTokenServices(resourceServerTokenServices());
return processingFilter;
}
@Bean
public ResourceServerTokenServices resourceServerTokenServices(){
OpenAMRemoteTokenService remoteTokenServices = new OpenAMRemoteTokenService();
remoteTokenServices.setRestTemplate(restTemplate());
remoteTokenServices.setAccessTokenConverter(accessTokenConverter());
remoteTokenServices.setClientId("...");
remoteTokenServices.setClientSecret("...");
remoteTokenServices.setCheckTokenEndpointUrl("http://...");
return remoteTokenServices;
}
@Bean
public OAuth2RestTemplate restTemplate(){
OAuth2RestTemplate template = new OAuth2RestTemplate(resourceDetails(), clientContext());
return template;
}
@Bean
public AccessTokenProvider accessTokenProvider(){
ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider();
return provider;
}
@Bean
public OAuth2ClientContext clientContext(){
return new OpenAMClientContext();
}
@Bean
public OAuth2ProtectedResourceDetails resourceDetails(){
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
details.setGrantType("password");
details.setAccessTokenUri("http://...");
details.setScope(Arrays.asList("openid");
details.setClientId("...");
details.setClientSecret("...");
return details;
}
@Bean
public AccessTokenConverter accessTokenConverter(){
DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
tokenConverter.setUserTokenConverter(userAuthenticationConverter());
return tokenConverter;
}
@Bean
public UserAuthenticationConverter userAuthenticationConverter(){
return new OpenAMUserAuthenticationConverter();
}
}
}
カスタムの RemoteTokenService を作成しました。そうしないと、Spring が OpenAM の tokeninfo エンドポイントにアクセスできず、Post ではなく GET リクエストが必要になるためです。この接続は現在正常に機能しているため、OpenAM から有効なアクセス トークンを取得し、tokeninfo.endpoint でトークン/ユーザー情報を照会することもできます。Authentication オブジェクトが作成され、Spring のセキュリティ コンテキストに格納されます。ZuulFilter の認証オブジェクトにもアクセスできます。
私の問題は、「OAuth2ClientContext」を微調整して、servletRequest からユーザーの資格情報を取得し、それを「AccessTokenRequest」に配置する必要があることです。それ以外の場合は、ResourceDetails でそれらをハードコードする必要がありますが、これは私の場合には適切ではありません。
その結果、ClientContext (およびおそらく AccessTokenRequest も) がシステムのすべてのユーザー間で共有されます。私が欲しいのは、セッションスコープのクライアントコンテキストです。これにより、複数のユーザーをログインさせ、すべてのリクエストで各ユーザーの適切な SecurityContext にアクセスできます。
だから私の質問は、
1) ClientContext および AccessTokenRequest セッションをスコープ化するにはどうすればよいですか?
2) Spring Session モジュールを使用する必要がありますか?
3) sessionStrategy を設定する必要がありますか?
ありがとうございました!