2016-09-08 5 views
2

リモート認証サーバを備えた春のブートoauth 2.0リソースサーバで動的スプリングセキュリティマッチャー(URL、メソッド、ロール、権限など)の検証を実装する必要があります。ダイナミックURLマッチャー設定でSpringセキュリティOauth 2.0を設定するには?

これらの情報をデータベースに抽出する方法はありますか?

これまでのところ、私は(Objectオブジェクト)メソッドのgetAttributesをDefaultFilterInvocationSecurityMetadataSource拡張フィルタを作成し、オーバーライド、進め方の一つの小さな兆候を発見したが、これは行うための最善の方法である場合、私は知りませんそれ。 https://github.com/sohamghosh/spring-security-dynamic-roles

答えて

1

私は私の質問と一緒に投稿したリンクで示されたアイデアを使用して解決しました。誰かが私にそれについてのヒントを与えることができたら、私は感謝します。私認証サーバはすべてを持っていないとする必要がないため、すべての

まず私は、唯一の私リソースサーバユーザーに関連付けられている当局を望んでいた今、私のアプリケーションのビジネスルール、役割とパーミッション。また、の機関をデータベースに保存して、動的に管理できるようにしました。だから私は私のRemoteTokenServicesにリンクするカスタムaccessTokenConverterを作成した(つまり私のOAuth 2.0の認証サーバへのポイント)これらの新しい当局を追加DefaultAccessTokenConverterの方法extractAuthenticationを上書きします。以下の完全なクラス構成を参照してください。

/** 
    * Class responsible for configuring Resource Server's security filters and connectivity with Heimdall (Authorization Server) 
    * @author mariane.vieira 
    * 
    */ 
    @Configuration 
    @EnableResourceServer 
    public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter { 
     @Value("${auth.server.resourceId}") 
     private String resourceId; 
     @Autowired 
     private AuthenticationManager authenticationManager; 
     @Autowired 
     private DynamicAuthorityRepository authorityRepository; 
     @Autowired 
     private UrlInterceptorRepository urlInterceptorRepository; 
     @Override 
     public void configure(ResourceServerSecurityConfigurer resources) { 
      resources.resourceId(resourceId).stateless(false); 
     } 

     @Override 
     public void configure(HttpSecurity http) throws Exception { 
      http 
       // Since we want the protected resources to be accessible in the UI as well we need 
       // session creation to be allowed (it's disabled by default in 2.0.6) 
       .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)   
      .and() 
       .addFilter(filterSecurityInterceptor()) 
       //permitting all because security paths verifications are going to be dynamic 
       //because of this filter above 
       .authorizeRequests().antMatchers("/**").permitAll(); 
     } 

     /** 
     * Dynamic {@link AccessTokenConverter}, normaly extracts authentication just like 
     * {@link DefaultAccessTokenConverter} but fetches others authorities localy stored 
     * with {@link DynamicAuthorityRepository} by username. 
     * 
     * @author mariane.vieira 
     * 
     */ 
     public class DynamicAccessTokenConverter extends DefaultAccessTokenConverter { 
      @Override 
      public OAuth2Authentication extractAuthentication(Map<String, ?> map) { 
       OAuth2Authentication authentication = super.extractAuthentication(map); 

       List<DynamicAuthority> dynamicAuthorities = authorityRepository.findByUsername(String.valueOf(authentication.getPrincipal())); 

       List<GrantedAuthority> authorities = authentication.getAuthorities().stream().collect(Collectors.toList()); 
       authorities.addAll(dynamicAuthorities.stream().map(auth -> new SimpleGrantedAuthority(auth.getAuthority())) 
         .collect(Collectors.toList())); 

       OAuth2Request request = new OAuth2Request(authentication.getOAuth2Request().getRequestParameters(), 
         authentication.getOAuth2Request().getClientId(), authorities, true, 
         authentication.getOAuth2Request().getScope(), authentication.getOAuth2Request().getResourceIds(), 
         null, null, null); 

       return new OAuth2Authentication(request, 
         new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), "N/A", authorities)); 
      } 
     } 
     /** 
     * Instantiates Bean accessTokenConverter as an instance of {@link DynamicAccessTokenConverter} 
     * @return {@link DynamicAccessTokenConverter} 
     */ 
     @Bean 
     public AccessTokenConverter accessTokenConverter() {   
      return new DynamicAccessTokenConverter(); 
     } 

     /** 
     * Instantiates Bean remoteTokenServices with informations of Heimdall (Authorization Server) instance and 
     * client credentials. Besides, sets our custom accessTokenConverter to fetch authorities dynamically. 
     * @param checkTokenUrl Url to Heimdall's (Authorization Server) check token endpoint 
     * @param clientId Client Id registered in Heimdall (Authorization Server) 
     * @param clientSecret Client Secret registered in Heimdall (Authorization Server) 
     * @return {@link RemoteTokenServices} bean 
     */ 
     @Bean 
     public RemoteTokenServices remoteTokenServices(final @Value("${auth.server.url}") String checkTokenUrl, 
       final @Value("${auth.server.clientId}") String clientId, 
       final @Value("${auth.server.clientsecret}") String clientSecret) { 
      final RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); 
      remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl); 
      remoteTokenServices.setClientId(clientId); 
      remoteTokenServices.setClientSecret(clientSecret);  
      remoteTokenServices.setAccessTokenConverter(accessTokenConverter()); 
      return remoteTokenServices; 
     } 

     /** 
     * Instantiates Bean remoteTokenServices filterSecurityInterceptor, instance of {@link DynamicFilterInvocationSecurityMetadataSource} 
     * that intercepts every request to verify security rules. These rules are stored in database and can be formed and verified 
     * dynamically. 
     * @return {@link FilterSecurityInterceptor} Bean, instance of {@link DynamicFilterInvocationSecurityMetadataSource} 
     */ 
     public FilterSecurityInterceptor filterSecurityInterceptor(){  
      DynamicFilterInvocationSecurityMetadataSource dynamicFilter = new DynamicFilterInvocationSecurityMetadataSource(
        new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>()); 
      dynamicFilter.setUrlInterceptorRepository(urlInterceptorRepository);   
      FilterSecurityInterceptor filter = new FilterSecurityInterceptor(); 
      filter.setAuthenticationManager(authenticationManager); 
      filter.setAccessDecisionManager(accessDecisionManager()); 
      filter.setSecurityMetadataSource(dynamicFilter); 
      return filter; 
     } 

     /** 
     * Instantiates Bean accessDecisionManager, instance of {@link UnanimousBased} with {@link ScopeVoter}, {@link RoleVoter} 
     * and {@link AuthenticatedVoter}. 
     * @return {@link AccessDecisionManager} bean, instance of {@link UnanimousBased} 
     */ 
     @Bean 
     public AccessDecisionManager accessDecisionManager(){ 
      return new UnanimousBased(Arrays.asList(new ScopeVoter(), new RoleVoter(), new AuthenticatedVoter())); 
     } 
    } 

さらに、前述のように、セキュリティパスのアクセスを動的に検証し、データベースに格納したいと考えました。私はFilterSecurityInterceptorを私の個人化されたセキュリティメタデータソースに追加しました。上記の構成クラスによってインスタンス化されます。以下のクラスは、データベース内でパスを検索するように適合されたセキュリティメタデータソースと、ConfigAttributesです。

public class DynamicFilterInvocationSecurityMetadataSource extends DefaultFilterInvocationSecurityMetadataSource { 

    private UrlInterceptorRepository urlInterceptorRepository; 

    public DynamicFilterInvocationSecurityMetadataSource(LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap) { 
     super(requestMap); 
    } 

    public UrlInterceptorRepository getUrlInterceptorRepository() { 
     return urlInterceptorRepository; 
    } 

    public void setUrlInterceptorRepository(UrlInterceptorRepository urlInterceptorRepository) { 
     this.urlInterceptorRepository = urlInterceptorRepository; 
    } 

    /** 
    * {@link ConfigAttribute} with specific attribute (access rule). 
    * Possible values to getAttribute's return: 
    * - IS_AUTHENTICATED_ANONYMOUSLY - No token in the request 
    * - IS_AUTHENTICATED_REMEMBERED 
    * - IS_AUTHENTICATED_FULLY - With a valid token 
    * - SCOPE_<scope> - Token with a specific scope 
    * - ROLE_<role> - Token's user with specific role 
    * @author mariane.vieira 
    * 
    */ 
    public class DynamicConfigAttribute implements ConfigAttribute { 
     private static final long serialVersionUID = 1201502296417220314L; 
     private String attribute; 
     public DynamicConfigAttribute(String attribute) { 
      this.attribute = attribute; 
     } 
     @Override 
     public String getAttribute() { 
      /* Possible values to getAttribute's return: 
      * IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_REMEMBERED 
      * IS_AUTHENTICATED_FULLY, SCOPE_<scope>, ROLE_<role> 
      */ 
      return this.attribute; 
     } 
     @Override 
     public String toString() { 
      return this.attribute; 
     } 
    } 

    @Override 
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { 
     FilterInvocation fi = (FilterInvocation) object; 
     String url = fi.getRequestUrl(); 
     String httpMethod = fi.getRequest().getMethod(); 

     if (url != null) {   
      //Searches for interceptors whose patterns matches the URL 
      List<UrlInterceptor> interceptors = this.urlInterceptorRepository.findByUrl(url);   

      Collection<ConfigAttribute> configAttributes = interceptors.stream() 
        //If the httpMethod is null is because it is valid for all methods 
        .filter(in -> in.getHttpMethod() == null || in.getHttpMethod().equals(httpMethod)) 
        .map(in -> new DynamicConfigAttribute(in.getAccess())) 
        .collect(Collectors.toList()); 

      return configAttributes; 
     } 
     return null; 
    } 

    @Override 
    public Collection<ConfigAttribute> getAllConfigAttributes() { 
     return null; 
    } 

    @Override 
    public boolean supports(Class<?> clazz) { 
     return FilterInvocation.class.isAssignableFrom(clazz); 
    } 
} 
関連する問題