ejemplo - spring security oauth2 spring boot
Spring Security OAuth2 Resource Server siempre devuelve token no vĂ¡lido (3)
Estoy intentando que un servidor OAuth2 en memoria básico se ejecute utilizando las bibliotecas Spring. He estado siguiendo el ejemplo brillante .
Actualmente, he configurado el servidor y casi todo funciona, sin embargo, no puedo acceder a mi recurso restringido desde el servidor de recursos.
Mi flujo de trabajo de prueba:
Acceda al URI autorizado de oauth para iniciar el flujo de OAuth2: http://localhost:8080/server/oauth/authorize?response_type=code&client_id=client
Redirigir a la página de inicio de sesión: http://localhost:8080/server/login
Maneje la aprobación y redirija a mi página de redirección configurada con un parámetro de código: http://localhost:8080/client?code=HMJO4K
Construya una solicitud GET usando la Autenticación Básica usando el ID y el secreto del cliente junto con el tipo y el código de la concesión: http://localhost:8080/server/oauth/token?grant_type=authorization_code&code=HMJO4K
Recibe un access_token y actualiza el objeto token a cambio
{access_token: "f853bcc5-7801-42d3-9cb8-303fc67b0453" token_type: "bearer" refresh_token: "57100377-dea9-4df0-adab-62e33f2a1b49" expires_in: 299 alcance: 299 en el alcance: "
Intente acceder a un recurso restringido utilizando access_token: http://localhost:8080/server/me?access_token=f853bcc5-7801-42d3-9cb8-303fc67b0453
Recibir una respuesta de token no válida
{error: "invalid_token" error_description: "Token de acceso no válido: f853bcc5-7801-42d3-9cb8-303fc67b0453"}
Publique el token uri nuevamente para actualizar el token: http://localhost:8080/server/oauth/token?grant_type=refresh_token&refresh_token=57100377-dea9-4df0-adab-62e33f2a1b49
Recibe un nuevo token
{access_token: "ed104994-899c-4cd9-8860-43d5689a9420" token_type: "bearer" refresh_token: "57100377-dea9-4df0-adab-62e33f2a1b49" expires_in: 300 scope: "read write"}
Realmente no estoy seguro de lo que estoy haciendo mal, pero parece que todo lo que no sea acceder al uri restringido está funcionando. Aquí está mi configuración:
@Configuration
public class Oauth2ServerConfiguration {
private static final String SERVER_RESOURCE_ID = "oauth2-server";
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(SERVER_RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and().requestMatchers()
.antMatchers("/me")
.and().authorizeRequests()
.antMatchers("/me").access("#oauth2.clientHasRole(''ROLE_CLIENT'')")
;
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthotizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.resourceIds(SERVER_RESOURCE_ID)
.secret("secret")
.authorizedGrantTypes("authorization_code", "refresh_token")
.authorities("ROLE_CLIENT")
.scopes("read","write")
.redirectUris("http://localhost:8080/client")
.accessTokenValiditySeconds(300)
.autoApprove(true)
;
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.userApprovalHandler(userApprovalHandler())
.authenticationManager(authenticationManager)
;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm("oauth");
}
@Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore());
return store;
}
@Bean
public UserApprovalHandler userApprovalHandler() throws Exception {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
handler.setTokenStore(tokenStore());
return handler;
}
}
}
¿Hay algo que me falta o me estoy acercando a esto incorrectamente? Cualquier ayuda sería muy apreciada.
El problema terminó siendo que el servidor de recursos y el servidor de autorizaciones no obtenían la misma referencia de almacén de token. No estoy seguro de cómo el cableado no funcionaba correctamente, pero usar un objeto fijo en la clase de configuración funcionó a la perfección. En última instancia, me moveré a una tienda de tokens respaldada por persistencia, que probablemente no habría tenido ningún problema.
¡Gracias a @OhadR por la respuesta y la ayuda!
En última instancia, simplifiqué la configuración, pasé por el mismo flujo de trabajo y funcionó
@Configuration
public class Oauth2ServerConfiguration {
private static final String SERVER_RESOURCE_ID = "oauth2-server";
private static InMemoryTokenStore tokenStore = new InMemoryTokenStore();
@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore).resourceId(SERVER_RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/me").and().authorizeRequests().antMatchers("/me").access("#oauth2.hasScope(''read'')");
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore).approvalStoreDisabled();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.authorizedGrantTypes("authorization_code","refresh_token")
.authorities("ROLE_CLIENT")
.scopes("read")
.resourceIds(SERVER_RESOURCE_ID)
.secret("secret")
;
}
}
}
Cualquiera que se tope con este post, recomiendo mirar más las pruebas de unidad, por ejemplo, en lugar del ejemplo completo de sparklr / tonr, ya que tiene una gran cantidad de configuraciones adicionales que no son necesariamente necesarias para comenzar.
Esto funciona para mí:
@Configuration
public class Oauth2ServerConfiguration {
private static final String SERVER_RESOURCE_ID = "oauth2-server";
@Autowired
private TokenStore tokenStore;
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore).resourceId(SERVER_RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
// ... Not important at this stage
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore).approvalStoreDisabled();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//... Not important at this stage
}
}
}
Su paso # 6 es incorrecto: el token de acceso no debe enviarse en la URL, ya que es vulnerable de esta manera. rathen than GET, usa POST.
Además, no entiendo su paso # 1: ¿por qué llama / auth / autoriza? debe hacerse de forma implícita cuando intenta obtener un recurso protegido. Quiero decir, tu flujo debe comenzar con:
Intente acceder a un recurso restringido utilizando access_token: http://localhost:8080/server/me
Luego, la negociación comenzará "detrás de escena": una redirección a "/ oauth / authorize", etc.
Además, en el paso # 8, tenga en cuenta que no está solicitando "otro token de acceso", sino que es una solicitud de "token de actualización". Como si su token de acceso haya caducado.
Nota : ¡El proveedor de identidad y el servidor de recursos deben compartir tokenStore! Lea aquí: Spring Security OAuth2 servidor de recursos puros
HTH