Spring Security: extremo seguro basado en la autoridad del cliente

Actualmente estoy usando OAuth2 de Spring Security para implementar la autorización en una serie de micro services. Nuestro AuthService realiza toda la authentication con tokens OAuth2, etc. y puede crear usuarios.

Considere dos clientes: Cliente A y Cliente B.

El cliente A tiene autoridades: CREATE_USER, CREATE_POST cliente B tiene autoridades: READ_USER

(Sí, podríamos usar un endoscopio, ¡pero esto es solo un ejemplo!)

Objetivo:

Solo el Cliente A, que tiene la autoridad CREATE_USER , debería poder crear un usuario. Los usuarios están creando mediante la publicación en /users .

Problema:

El problema es que cuando envío una request POST al punto final de / users con el encabezado de authentication básico para el Cliente A, la autoridad CREATE_USER no se encuentra porque la request golpea el ROLE_ANONYMOUS AnonymousAuthenticationFilter y la única autoridad encontrada es ROLE_ANONYMOUS y recibo lo siguiente:

 10:38:34.852 [http-nio-9999-exec-1] DEBUG osswaiFilterSecurityInterceptor - Secure object: FilterInvocation: URL: /users; Attributes: [#oauth2.throwOnError(#oauth2.hasAuthority('CREATE_USER))] 10:38:34.852 [http-nio-9999-exec-1] DEBUG osswaiFilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Cnetworkingentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS 10:38:34.854 [http-nio-9999-exec-1] DEBUG ossaccess.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@a63e3e8, returned: -1 10:38:34.856 [http-nio-9999-exec-1] DEBUG osswaExceptionTranslationFilter - Access is denied (user is anonymous); networkingirecting to authentication entry point org.springframework.security.access.AccessDeniedException: Access is denied 

Una solución increíblemente hacky sería registrar un filter de security personalizado que lea el encabezado de authentication básica y verifique que el nombre de un cliente sea igual al Cliente A, pero esto no funcionará para un tercer cliente, el Cliente C que también tiene la autoridad CREATE_VIEWER , como el nombre y no las autoridades están verificadas aquí.

 // UsersController.kt @PostMapping("/users") @ResponseStatus(HttpStatus.OK) @ResponseBody fun createUser(): String { return "Created user!" } 

Configuración del cliente

 override fun configure(clients: ClientDetailsServiceConfigurer?) { clients!!.inMemory() .withClient("ClientA") .scopes("all") .authorities("CREATE_USER", "CREATE_POST") .authorizedGrantTypes("refresh_token", "password") .and() .withClient("ClientB") .scopes("all") .authorities("READ_USER") .authorizedGrantTypes("refresh_token", "password") } 

WebSecurityConfigurerAdaptor impl

 override fun configure(http: HttpSecurity) { http.requestMatchers().antMatchers("/oauth/authorize", "/oauth/confirm_access") .and() .authorizeRequests() .antMatchers("/users").access("hasAuthority('CREATE_USER')") .anyRequest().authenticated() .and() .csrf().disable() } override fun configure(auth: AuthenticationManagerBuilder) { auth.authenticationProvider(authenticationProvider()) } @Bean open fun authenticationProvider(): DaoAuthenticationProvider { val authProvider = DaoAuthenticationProvider() authProvider.setUserDetailsService(userCnetworkingentialService) authProvider.setPasswordEncoder(passwordEncoderService) return authProvider }