spring-attic / spring-security-oauth

Support for adding OAuth1(a) and OAuth2 features (consumer and provider) for Spring web applications.
http://github.com/spring-projects/spring-security-oauth
Apache License 2.0
4.69k stars 4.05k forks source link

Can we add a custom AccessDecisionVoter in pure Authorization server? #1297

Open SameerSharma9 opened 6 years ago

SameerSharma9 commented 6 years ago

Preface

I have two application running on server, one is acting as a resource server having couple of APIs and other is pure auth server having responsibilities of Authentication and authorization. Auth server generates the access token and later validates the access token when asked by the resource server.

What i have done so far

Configurations at Resource server

I have used Remote token service in resource server which communicates with the auth server for validation of token.

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private ClientDetailsService clientService; 

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

   @Bean
   @Primary
   public ResourceServerTokenServices tokenService() {
      RemoteTokenServices tokenServices = new RemoteTokenServices();
      tokenServices.setClientId("remoteclient");
      tokenServices.setClientSecret("secret");
      tokenServices.setCheckTokenEndpointUrl("http://localhost:8082/oauth/check_token");
      return tokenServices;
   }

}

Here is my protected URL confguration :

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

private static final String RESOURCE_ID = "SPRING_REST_API";

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
    resources.resourceId(RESOURCE_ID).stateless(false);
}

@Override
public void configure(HttpSecurity http) throws Exception {
    http.
    anonymous().disable()
    .requestMatchers().antMatchers("/protected/**")
    .and().authorizeRequests()
    .antMatchers("/protected/**").access("hasRole('ADMIN')")
    .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}

}

Configurations at Auth server

For simplicity i am using Inmomory client details and tokenStore.

@Configuration
@EnableAuthorizationServer

public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

private static String REALM="MY_OAUTH_REALM";

@Autowired
private TokenStore tokenStore;

@Autowired
private UserApprovalHandler userApprovalHandler;

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

    clients.inMemory()
        .withClient("sameer")
        .authorizedGrantTypes("password", "client_credentials", "refresh_token", "implicit")
        .authorities("ROLE_CLIENT", "ROLE_ADMIN")
        .scopes("read", "write", "trust")
        .secret("secret")
        .accessTokenValiditySeconds(1000).
        refreshTokenValiditySeconds(6000)
        .and()
        .withClient("remoteclient")
        .authorizedGrantTypes("password", "client_credentials", "refresh_token", "implicit")
        .authorities("ROLE_CLIENT", "ROLE_ADMIN")
        .scopes("read", "write", "trust")
        .secret("secret")
        .accessTokenValiditySeconds(1000).
        refreshTokenValiditySeconds(6000);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
            .authenticationManager(authenticationManager)
            .allowedTokenEndpointRequestMethods(HttpMethod.POST);
}

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.realm(REALM+"/client")
    .allowFormAuthenticationForClients()
    .tokenKeyAccess("permitAll()")
    .checkTokenAccess("permitAll()");
}

}

Here is my custom access Decision voter :

public class MinuteBasedVoter implements AccessDecisionVoter<Object>{

@Override
public boolean supports(ConfigAttribute arg0) {
    // TODO Auto-generated method stub
    return true;
}

@Override
public boolean supports(Class<?> arg0) {
    // TODO Auto-generated method stub 
    return true;
}

@Override
public int vote(Authentication arg0, Object arg1, Collection<ConfigAttribute> arg2) {
    System.out.println("<<<<<<<<<<<<<< My Decision voter >>>>>>>>>>>>>>");
    return ACCESS_GRANTED;
}

}

configurations at the auth server with custom voter added.

@Configuration
@EnableWebSecurity
@Order(2)
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

 @Autowired
 private ClientDetailsService clientDetailsService;

 @Autowired
 public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
   auth.inMemoryAuthentication()
   .withUser("bill").password("abc123").roles("ADMIN").and()
   .withUser("bob").password("abc123").roles("USER");
 }

 @Override
 protected void configure(HttpSecurity http) throws Exception {
   http
   .anonymous().disable()
   .requestMatchers().antMatchers("/oauth/token").and()
   .authorizeRequests()
   .antMatchers("/oauth/token").authenticated().and() 
   .requestMatchers().antMatchers("/oauth/check_token")
   .and()
   .authorizeRequests().antMatchers("/oauth/check_token").hasRole("ADMIN");

   http.authorizeRequests()
   .accessDecisionManager(accessDecisionManager());
 }

 @Override
 @Bean
 public AuthenticationManager authenticationManagerBean() throws Exception      {
   return super.authenticationManagerBean();
   }

@Bean
public TokenStore tokenStore() {
   return new InMemoryTokenStore();
}

@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
   TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
   handler.setTokenStore(tokenStore);
   handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
   handler.setClientDetailsService(clientDetailsService);
   return handler;
}

@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception   {
   TokenApprovalStore store = new TokenApprovalStore();
   store.setTokenStore(tokenStore);
   return store;
 }

@Bean
public AccessDecisionManager accessDecisionManager() {
   java.util.List<AccessDecisionVoter<? extends Object>> decisionVoters
           = Arrays.asList(
           new RoleVoter(),
           new AuthenticatedVoter(),
           new MinuteBasedVoter()                          
   );
   return new UnanimousBased(decisionVoters);
}
}

What i want to achive

When resource server forwards the request to auth server, it should first authenticate the token and after successful validation of token, it should call my custom voter for authorization of client.

Auth server is validating the token but my custom voter is not getting invoked, instead it returns the request to resource server with successful validation of token.

curtiseng commented 5 years ago

Is this solved,I have a same problem.

yanickxia commented 5 years ago

me too····