Spring boot OAuth 2 security get access token from Refresh token(if expired) - spring

I have implemented Spring boot Oauth 2 security it works fine but when I try to get access token (if expired) from refresh token it gives me an error
{
"error": "unauthorized",
"error_description": "admin"
}
Console Log
Handling error: UsernameNotFoundException, admin
Following is my code
1.WebSecurityConfigure
#Configuration
#EnableWebSecurity
public class EmployeeSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/user/getEmployeesList")
.hasAnyRole("USER").anyRequest().authenticated().and().formLogin()
.permitAll().and().logout().permitAll();
http.csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationMgr) throws Exception {
authenticationMgr.inMemoryAuthentication().withUser("admin").password("admin")
.authorities("ROLE_USER");
;
}
}
2.AuthorizationServerConfigure
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("MagicUser").authorizedGrantTypes("authorization_code", "refresh_token","password")
.authorities("CLIENT").scopes("openid", "read", "write", "trust").resourceIds("oauth2-resource")
.redirectUris("http://10.9.6.31:8090/showEmployees").accessTokenValiditySeconds(5000).secret("secret")
.refreshTokenValiditySeconds(50000);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
;
}
}
Please help me to figure out this issue
Access token request (if expired)
http://10.9.6.31:8091/oauth/token
Body parameter
grant_type=refresh_token
refresh_token=78d2ab82-46a2-4b70-a9e8-e3f9e5ddfec6

You might have to send an authorization header in the request to authenticate the client.
Check OAuth client authentication and Refreshing an access token specifications in OAuth 2.0 specification.

Related

How to configure oAuth2 when Authorization Server is also the Resource server

I'm trying to setup a very basic oAuth2 authentication in spring boot 2.x.x using either authorization code grant or implicit grant but I can't seem to access the Resource server (which resides in the same spring boot app as the Authorization server) after the token is obtained.
Following is the configuration of WebSecurityConfigurerAdapter
#EnableWebSecurity
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String[] IGNORE_URIS = {
"/swagger-resources/**",
"/swagger-ui.html",
"/v2/api-docs",
"/webjars/**",
"/resources/**",
"/h2-console/**",
"/common/**",
"/configuration/ui",
"/configuration/security",
"/error"
};
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(IGNORE_URIS);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/product/**")
.hasAnyRole("ADMIN").and()
.httpBasic().and().formLogin().and().authorizeRequests().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("{noop}admin").roles("ADMIN");
}
#Bean
public PasswordEncoder bCrypt() {
return new BCryptPasswordEncoder();
}
And the AuthorizationServerConfigurerAdapter
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
#Autowired
public AuthorizationServerConfiguration(AuthenticationConfiguration authenticationConfiguration) throws Exception {
this.authenticationManager = authenticationConfiguration.getAuthenticationManager();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("my-client-id")
.authorizedGrantTypes("authorization_code", "implicit")
.authorities("ADMIN")
.scopes("all")
.resourceIds("product_api")
.secret("{noop}secret").redirectUris("https://google.com").accessTokenValiditySeconds(0);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
So far so good. I am able to reach the default Spring login page by typing the following Url in the browser.
http://localhost:8080/oauth/authorize?response_type=token&client_id=my-client-id&redirect_uri=https://google.com
Then The login page shows up and I enter my credentials.
After I log in I can then grant access to "my-client-id" app.
Eventually after I approve the app I can see the newly generated access token in the URL bar of the browser which is something like this.
https://www.google.com/#access_token=f2153498-6a26-42c6-93f0-80825ef03b16&token_type=bearer&scope=all
My question is that All of this flow won't work when I also configure a Resource Server.
#EnableResourceServer
#Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("product_api");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/**")
.and().authorizeRequests()
.antMatchers("/**").permitAll();
}
}
What am I doing wrong? When I try to access the oauth/authorize url as before I get the following:
Why? How can one access the login page and retrieve the token? What Am I missing?
You need to use
#Order
Annotation to specify order for WebMvc and ResourceServer classes
#EnableWebSecurity
#Configuration
#Order(1)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}
and for Resource Server
#EnableResourceServer
#Configuration
#Order(2)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
...
}
If you want to see workable example, you can check it here https://github.com/alex-petrov81/stackoverflow-answers/tree/master/auth-server-also-resource
I've created it from your code example.

Spring OAuth2 "Full authentication is required to access this resource error" when trying to access login url

I am using Spring Security OAuth2 (Spring Boot 2.0.2 + Spring Cloud Finchley) and trying to initiate an implicit login. The browser redirects me to the /login URL but I get the the error "Full authentication is required to access this resource." How do I allow the login page to be displayed but still allow all REST urls to be secured?
My config is as follows:
App.java
#SpringBootApplication
#RestController
#EnableResourceServer
#EnableAuthorizationServer
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
OAuth2Config.java
#Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("XXXXX")
.secret("XXXXX")
.authorizedGrantTypes("refresh_token", "password", "client_credentials")
.scopes("webclient", "mobileclient");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
WebSecurityConfigurer.java
#Configuration
#Order(-20) // EDIT
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("XXXXX"). password("XXXXXX").roles("USER");
}
// EDIT
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().permitAll()
.and().httpBasic().and()
.requestMatchers()
//specify urls handled
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.antMatchers("/fonts/**", "/js/**", "/css/**")
.and()
.authorizeRequests()
.antMatchers("/fonts/**", "/js/**", "/css/**").permitAll()
.anyRequest().authenticated();
}
}
}

Spring oauth2 - Cannot login to /oauth/authorization

I'm trying to secure my REST app with OAUTH2, in this case with Authorization Code Grant. So basically i think that when trying to access the /oauth/authorize endpoint, i should get a login page (from my app) where the user should authenticate with my app in order to make the client app get the token in the redirect_uri. Is this correct?
My clients are in a DB, I have created all the tables Spring Security needs. In this case I have a client_id = test and authorized_grant_types "access_token,refresh_token,implicit,authorization_code"
This is my AuthorizationServer config
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.authenticationManager(authManager);
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
}
The resource server (in the same app) is
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
#Autowired
DataSource dataSource;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").access("hasRole('USER')");
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore());
}
}
Last, my general SecurityConfiguration sets the security levels for the web app part of the application and not for the "/api/**" part. I'm trying with PostMan to send a post request to http://localhost:8080/oauth/authorize with this parameters: client_id=test redirect_uri=http://test.com response_type=code but i'm getting this error
User must be authenticated with Spring Security before authorization can be completed.
I thought i should get a login window where the user should authenticate
what i'm doing wrong?

spring security token request requires authentication

I am trying to implement Authorization Code Grant Flow of OAuth 2.0. But stuck with the issue of Authentication popup on token request.
Here is my code.
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
#Configuration
public class SecurityConfig
extends WebSecurityConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("abc").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and().csrf().disable();
}
}
#Configuration
#EnableAuthorizationServer
public class AuthServerOAuth2Config
extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("test")
.secret("test_secret")
.authorizedGrantTypes("authorization_code")
.scopes("write");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.approvalStoreDisabled();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
}
To get token I do the following steps:
Using browser go to:
http://localhost:9000/oauth/authorize?response_type=code&client_id=test&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&scope=write
First it redirects me to a Login form, where I enter username and passord: admin abc
Then it asks if I allow to provide the permission to my "test" client.
It redirects me to "redirect uri": http://localhost:8080?code=XXX
Then I copy code and use Google Advanced Rest Client to send Token Request:
POST on http://localhost:9000/oauth/token?client_id=test&grant_type=authorization_code&code=XXX
Without any headers. As far as I understand Poster should use Browser cookie.
As result on token request I see a popup asking to fill username and password while expecting to get access token in response.
Please, help me to solve the issue. Should I add some headers to my token request? Or my Authorization Server config is not correct?
I found the reason of the issue by myself just reading others resources of OAuth2 specification.
It it is required to send Authorization on token request with the following value:
Authorization: Basic {base64 encode of clientId:clientSecret}

How do you properly configure Spring Security's OAuth2 system to work with EmberJS

I'm creating an EmberJS app wrapped with Cordova alongside a Rest API provided by Spring Boot. Here is my Spring Code:
#SpringBootApplication
#RestController
public class Application extends SpringBootServletInitializer {
...
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// any calls made to the API must be authenticated
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().fullyAuthenticated();
http
.cors().disable();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("b-api");
}
}
#Configuration
#EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
// we're hosting a static landing page with Spring so we're removing any security requirements for them
.antMatchers("/resources/**")
.antMatchers("/img/**")
.antMatchers("/*")
// this is to allow preflight to work but it doesn't seem to be doing the trick...
.antMatchers(HttpMethod.OPTIONS, "/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest()
.hasRole("USER");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
// enable in memory based authentication with a user named "user" and "admin"
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER")
.and()
.withUser("admin")
.password("password")
.roles("USER", "ADMIN");
}
}
#Configuration
#EnableAuthorizationServer
#CrossOrigin(origins = "http://localhost:4200", methods = {RequestMethod.GET, RequestMethod.PUT, RequestMethod.OPTIONS, RequestMethod.HEAD}, allowedHeaders = "**")
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT", "ROLE_USER")
.scopes("read", "write", "trust")
.resourceIds("b-api")
.accessTokenValiditySeconds(600);
}
}
}
The frontend code is using EmberJS with ember-simple-auth's oauth2 authenticator.
Currently when I try and authenticate through the frontend Chrome's devtools throw this error:
XMLHttpRequest cannot load http://localhost:8080/oauth/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.
Any ideas regarding what I'm missing would be appreciated. Thanks :)

Resources