spring OAuth2 zuul--Access token expired,invalid_token - spring

I have a spring zuul OAuth2 app.
authServer--
OAuth2ServerConfiguration:
#Configuration
public class {
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception { http .authorizeRequests()
.antMatchers( "/oauth/authorize/**","/oauth/check_token/**").permitAll()
.anyRequest().authenticated();
// #formatter:on
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
//private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
TokenStore tokenStore;
#Autowired
private CustomUserDetailService customUserDetailService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// #formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(customUserDetailService);
// #formatter:on
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients
.inMemory()
.withClient("kksdi2388wmkwe")
.authorizedGrantTypes("authorization_code","password", "refresh_token")
.scopes("read", "write")
.resourceIds("ReadAndWriteResource")
.secret("kksd23isdmsisdi2")
.autoApprove(true)
.accessTokenValiditySeconds(120)
.refreshTokenValiditySeconds(1200);
// #formatter:on
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
}
webSecurity:
#Configuration
#EnableWebSecurity
#Order(-20)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/login", "/").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.csrf().disable()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated()
;
// #formatter:on
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(11);
}
}
zuul server:
security:
user:
password: none
oauth2:
client:
accessTokenUri: http://localhost:9999/uaa/oauth/token
userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
clientId: kksdi2388wmkwe
clientSecret: kksd23isdmsisdi2
resource:
userInfoUri: http://localhost:9999/uaa/user
zuul:
routes:
auth-server: /auth-server/**
resource: /resource/**
zuul app:
#SpringBootApplication
#EnableZuulProxy
#EnableOAuth2Sso
public class Application extends WebSecurityConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.logout().permitAll()
.and().authorizeRequests()
.mvcMatchers("/login/**").permitAll()
.anyRequest().authenticated();
}
}
problem:
after logged in:
can access: AuthServer "http://localhost:8080/auth-server/uaa/user" and "http://localhost:8080/api/test"
but when access_token expired,
can oly access: "http://localhost:8080/api/test",
when accessing AuthServer "http://localhost:8080/auth-server/uaa/user" met error--
<error_description>
Access token expired: 530c9247-2331-47e3-a6c0-ed61814642f5
</error_description>
<error>invalid_token</error>
and I can't get access_token from request header,
How to resolve?

Before everything check your OAUTH server application server and your client application server time and timezone if they are separated in two different machine.
Your OAUTH Server Configuration I think has some problems. OAUTH Server itself is secured with 'BASIC ACCESS AUTHENTICATION' : https://en.wikipedia.org/wiki/Basic_access_authentication
Which works with a token on his requests headers :
'Authorization' : Basic=Base64.encode(username+' '+password).
If you miss this token then you can't access any endpoint on your OAUTH server.
Mine works fine, you can test it:
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.formLogin().loginPage("/login").permitAll()
.and().requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/fonts/**", "/css/**")
.and().authorizeRequests().antMatchers("/fonts/**", "/css/**").anonymous().anyRequest().authenticated();
// #formatter:on
}
And why have you disabled csrf protection?

these are my token store configuration :
#Autowired
#Qualifier("datasource")
private DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(authenticationManager).tokenStore(tokenStore())
.approvalStoreDisabled();
}

Related

Spring OAuth security - Implicit flow

Is it possible to implement OAuth implicit flow with spring security? I want to create both auth and resource server in the same application. I need standard auth endpoints for authentication and authorization and some custom endpoints for handling with users (create/update/list...).
Requirements:
implicit flow
custom login page (/my_login_page)
silent mode for obtaining token (/oauth/authorize?...&prompt=none)
secured custom endpoints with OAuth (/users)
I'm stuck with configuration. Whatever I do, the requirements above never work together.
Spring WebSecurityConfig
#Configuration
#Order(-10)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MyAuthenticationProvider authenticationProvider;
private MyAuthenticationDetailsSource authenticationDetailsSource;
#Autowired
public SecurityConfig(MyAuthenticationProvider authenticationProvider, MyAuthenticationDetailsSource authenticationDetailsSource) {
this.authenticationProvider = authenticationProvider;
this.authenticationDetailsSource = authenticationDetailsSource;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation().newSession()
.and()
.authorizeRequests()
.antMatchers("/assets/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/my_login_page")
.loginProcessingUrl("/my_process_login")
.usernameParameter("my_username")
.passwordParameter("pmy_assword")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll();
}
}
Spring AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private ResourceLoader resourceLoader;
private AuthProps authProps;
#Autowired
public OAuth2AuthorizationServerConfig(ResourceLoader resourceLoader, AuthProps authProps) {
this.resourceLoader = resourceLoader;
this.authProps = authProps;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Qualifier("jwtAccessTokenConverter")
public JwtAccessTokenConverter accessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resourceLoader.getResource(authProps.getAuthServerPrivateCertPath()), authProps.getAuthServerPrivateCertKey().toCharArray());
JwtAccessTokenConverter converter = new MYJwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory
.getKeyPair(authProps.getAuthServerPrivateCertAlias()));
final Resource resource = resourceLoader.getResource(authProps.getAuthServerPublicCertPath());
String publicKey;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-secured-client")
.secret("foo")
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds("my-resource")
.authorities("CLIENT")
.redirectUris(
"http://localhost:4200"
)
.accessTokenValiditySeconds(300)
.autoApprove(true);
}
}
Spring ResourceServerConfig
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private AuthProps authProps;
private TokenStore tokenStore;
private DefaultTokenServices tokenServices;
#Autowired
public OAuth2ResourceServerConfig(AuthProps authProps, TokenStore tokenStore, DefaultTokenServices tokenServices) {
this.authProps = authProps;
this.tokenStore = tokenStore;
this.tokenServices = tokenServices;
}
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config
.resourceId("my-resource")
.tokenStore(tokenStore)
.tokenServices(tokenServices);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/**").authenticated()
.and()
.csrf().disable();
}
}
I placed WebSecurityConfig before ResourceServerConfig otherwise login page doesn't work. But now I can't access my custom endpoint for users (I'm redirected to the login page). If I place ResourceServerConfig before WebSecurityConfig login page stop working. I get 404 not found response when I submit login page form.
I also have an issue with silent mode to obtain a new access token. When calling /oauth/authorize with still valid access_token I'm redirected to the login page.
Finally I found a solution:
ResourceServerConfig have to be before WebSecurityConfig
loginProcessingUrl should be /oauth/authorize
Silent refresh works by default until session is valid (login form)
Custom endpoint for logout where invalidate current session
EDITED:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MyAuthenticationProvider authenticationProvider;
private MyAuthenticationDetailsSource authenticationDetailsSource;
#Autowired
public SecurityConfig(MyAuthenticationProvider authenticationProvider, MyAuthenticationDetailsSource authenticationDetailsSource) {
this.authenticationProvider = authenticationProvider;
this.authenticationDetailsSource = authenticationDetailsSource;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(authenticationProvider);
}
#Override
public void configure(WebSecurity web) {
web
.debug(true)
.ignoring()
.antMatchers(HttpMethod.OPTIONS)
.antMatchers("/my-custom-login-page", "/my-custom-logout-page")
.antMatchers("/assets/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/my-custom-login-page")
.loginProcessingUrl("/oauth/authorize")
.usernameParameter("myUsernameParam")
.passwordParameter("myPasswordParam")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll()
.and()
.csrf().disable();
}
}
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private ResourceLoader resourceLoader;
private AuthProps authProps;
#Autowired
public OAuth2AuthorizationServerConfig(ResourceLoader resourceLoader, AuthProps authProps) {
this.resourceLoader = resourceLoader;
this.authProps = authProps;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Qualifier("jwtAccessTokenConverter")
public JwtAccessTokenConverter accessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resourceLoader.getResource(authProps.getAuthServerPrivateCertPath()), authProps.getAuthServerPrivateCertKey().toCharArray());
JwtAccessTokenConverter converter = new MyJwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(authProps.getAuthServerPrivateCertAlias()));
final Resource resource = resourceLoader.getResource(authProps.getAuthServerPublicCertPath());
String publicKey;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(authProps.getAuthServerClientId())
.secret(authProps.getAuthServerClientSecret())
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds(authProps.getAuthServerResourceId())
.authorities("CLIENT")
.redirectUris(
"http://localhost:4200/#/login",
"http://localhost:4200/assets/silent-refresh.html",
"http://localhost:8080/my-api/webjars/springfox-swagger-ui/oauth2-redirect.html"
)
.accessTokenValiditySeconds(authProps.getAuthServerAccessTokenValiditySeconds())
.autoApprove(true);
}
}
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private AuthProps authProps;
private TokenStore tokenStore;
private DefaultTokenServices tokenServices;
#Autowired
public OAuth2ResourceServerConfig(AuthProps authProps, TokenStore tokenStore, DefaultTokenServices tokenServices) {
this.authProps = authProps;
this.tokenStore = tokenStore;
this.tokenServices = tokenServices;
}
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config.resourceId(authProps.getAuthServerResourceId()).tokenStore(tokenStore);
config.resourceId(authProps.getAuthServerResourceId()).tokenServices(tokenServices);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().hasRole(AppRole.ROLE_APP_USER.split("ROLE_")[1])
.and()
.csrf().disable();
}
}
#Controller
public class MainController {
#Autowired
public MainController() {
...
}
#GetMapping("/my-custom-login-page")
public ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView("login-page");
return mv;
}
#GetMapping("/my-custom-logout-page")
public ModelAndView logoutPage(HttpServletRequest request) {
ModelAndView mv = new ModelAndView("logout-page");
HttpSession session = request.getSession(false);
if (Objects.isNull(session)) {
mv.addObject("msg", "NO SESSION");
return mv;
}
session.invalidate();
mv.addObject("msg", "SUCCEEDED");
return mv;
}
}
In addition to #user3714967 answer, I add some tips maybe It helps someone. The problem is that we are defining multiple HttpSecurity (The resourceServer is a WebSecurityConfigurerAdapter with order 3). The solution is to use HttpSecurity.requestMatchers() with the specific value.
Example
First Class:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("url1", "url2", ...).and()
.authorizeRequests()
.antMatchers(...).and()...
}
}
Second Class:
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("url3", "url4", ...)
.and()
.authorizeRequests()
.antMatchers(...).and()...
}
}
}
This will be useful when we have more than flow (password && implicit flows for my case).

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 Security using Oauth | Overriding HttpSecurity

I am Implementing Spring Security using Oauth following these websystique , baeldung,What I found WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter both provides control over HttpSecurity,and filterchain adds them in order 0 and 3 respectively.
So I am overriding configure of any of the above ConfigurerAdapter but only one at a time.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.requestMatchers().antMatchers("/api/**").and()
.authorizeRequests()
.antMatchers("/api/ads").permitAll()
.antMatchers("/api/admin").hasAuthority(RoleConstant.ADMIN.getRole())
.antMatchers("/api/user").hasAuthority(RoleConstant.USER.getRole())
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
What I observe in case of WebSecurityConfigurerAdapter I am able to access unauthorized resources ie I am able to access /api/user after being authenticated even with token having authority ADMIN.Why so?
Note : I am not overriding HttpSecurity of ResourceServerConfigurerAdapter.
References : There are similar resources available here. Resource1 , Resource2.
Also I want to know,I must have to override both configure(HttpSecurity http) or any of the class is sufficient?If yes,which one is recommended?
ResourceServer :
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_rest_api";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.requestMatchers().antMatchers("/api/**").and()
.authorizeRequests()
.antMatchers("/api/ads").permitAll()
.antMatchers("/api/admin").hasAuthority(RoleConstant.ADMIN.getRole())
.antMatchers("/api/user").hasAuthority(RoleConstant.USER.getRole())
.antMatchers("/api/readProperty").access("hasRole('ADMIN')")
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
SpringSecurityConfig :
#Configuration
#EnableWebSecurity
#ComponentScan(basePackages = {"com.ttnd.mvc_mod.services","com.ttnd.mvc_mod.repository","com.ttnd.mvc_mod.config","com.ttnd.mvc_mod.custom"})
#Import({SpringORMHibernateSupportConfig.class})
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
private CustomAuthenticationProvider authProvider;
/* #Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.requestMatchers().antMatchers("/**").and()
.authorizeRequests()
.antMatchers("/oauth/token","/api/ads").permitAll()
.antMatchers("/api/admin").hasAuthority(RoleConstant.ADMIN.getRole())
.antMatchers("/api/user").hasAuthority(RoleConstant.USER.getRole())
.antMatchers("/api/readProperty").access("hasRole('ADMIN')")
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());//.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
}
*/
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.userDetailsService(customUserDetailsService);
auth.authenticationProvider(authProvider);
}
#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;
}
}

Get AccessToken when Login in from OAuth2 LoginFrom

I'm using spring OAuth2 loginForm and access_token way to authenticate. But when I login in, I can not get access to resource server which needs access_token authorization.
How can I get access_token when I login in?
Should I create access_token by myself manually?
What I config with spring security is:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SpringDataMyBatisUserDetailsService userDetailsService;
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(this.userDetailsService)
.passwordEncoder(Manager.PASSWORD_ENCODER);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/druid/**",
"/images/**"
);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
}
#Order(1)
#Configuration
#EnableAuthorizationServer
public static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
#Autowired
private TokenStore tokenStore;
#Autowired
private SpringDataMyBatisClientDetailsService clientDetailsService;
#Autowired
public AuthorizationServerConfig(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
/**
* Defines the security constraints on the token endpoints /oauth/token_key and /oauth/check_token
* Client credentials are required to access the endpoints
*
* #param oauthServer
* #throws Exception
*/
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
// .passwordEncoder(Client.PASSWORD_ENCODER)
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
/**
* Defines the authorization and token endpoints and the token services
*
* #param endpoints
* #throws Exception
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(this.authenticationManager)
.tokenEnhancer(tokenEnhancer())
.tokenStore(tokenStore);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.withClientDetails(clientDetailsService);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
}
#Order(3)
#Configuration
#EnableResourceServer
public static class ApiResources extends ResourceServerConfigurerAdapter {
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
private AuthenticationSuccessHandler successHandler;
#Autowired
private AuthenticationFailureHandler failureHandler;
#Autowired
private TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(successHandler)
.failureHandler(failureHandler)
.and()
.logout();
}
}
#Order(4)
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/authention/login")
.defaultSuccessUrl("/", true)
.failureUrl("/authention/login?error")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/authention/login?success")
.and()
.sessionManagement()
.sessionFixation().migrateSession();
}
}
#Bean
public static AuthenticationSuccessHandler myAuthenticationSuccessHandler() {
return new SavedRequestAwareAuthenticationSuccessHandler();
}
#Bean
public static AuthenticationFailureHandler myAuthenticationFailureHandler() {
return new SavedRequestAwareAuthenticationFailureHandler();
}
}
When you configure spring-oauth in your app you can access REST APIs to get the tokens, revoke tokens etc.
See this link For basic oauth configuration for a spring boot application. And also go through the API reference
Sample OAuth2AuthorizationServerConfig :
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("hello")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_APP")
.scopes("read", "write")
.secret("secret");
}
}
And the SecurityConfig class:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan(basePackages = {"com.test.config"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable();
http
.authorizeRequests()
.anyRequest().access("#oauth2.hasScope('read')")
.and()
.exceptionHandling()
.authenticationEntryPoint(oauthAuthenticationEntryPoint())
.accessDeniedHandler(oAuth2AccessDeniedHandler());
http
.formLogin()
.loginPage("/login")
.failureUrl("/")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.permitAll();
}
}
After you configure your application. You can access the REST API as below.
For getting the token you need to access this URL:
localhost:8080/oauth/token?grant_type=password&client_id=hello&client_secret=secret&username=admin&password=password
This will authenticate the user if it is successful then the token is generated as shown below:
{
"access_token": "0307d70f-e3da-40f4-804b-f3a8aba4d8a8",
"token_type": "bearer",
"refresh_token": "daf21f97-f425-4245-8e47-19e4c87000e8",
"expires_in": 119,
"scope": "read write"
}
After getting this token you can access the REST APIs of your application just by passing this token. For example, if you have a URL "/hello" then
put a request appending the token which you obtained through above step.
"http://localhost:8080/hello?access_token=0307d70f-e3da-40f4-804b-f3a8aba4d8a8"

Spring OAuth2 additional permision

I need to add additional restriction to authenticate users. My User model has a field 'active'. It is false, when User registers, but not activate his account with hash from mail. Now, even if User is not active he gets access_token from Oauth.
How should I configure this?
I was thinking about SpringSecurityInterceptor, but I'm not sure about confusing Spring Security with OAuth2.
This is my SpringOAuth2.0 configuration:
#Configuration
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
private static final String RESOURCE_ID = "restservice";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/rest/**")
))
.authorizeRequests()
.anyRequest().access("#oauth2.hasScope('read')");
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
UserDetailsService userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService)
.pathMapping("/oauth/token", "/rest/oauth/token");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("USER")
.scopes("read", "write", "trust")
.resourceIds(RESOURCE_ID)
.secret("123456");
}
}
}
And also Spring security
#Configuration
#Order(2147483640)
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
UserDetailsService userDetailsService;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("email")
.passwordParameter("password")
.defaultSuccessUrl("/user/")
.successHandler(successHandler())
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(86400)
.and()
.csrf().disable();
}
#Bean
public AuthenticationSuccessHandler successHandler() {
return new UserLoginSuccessHandler();
}
#Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
tokenRepositoryImpl.setDataSource(dataSource);
return tokenRepositoryImpl;
}
#Bean
public SpringSecurityDialect securityDialect() {
return new SpringSecurityDialect();
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Any advice would be helpful.
If I understand you correctly, you don't want your authorization server to grant an access token for a user that is not activated?
You could let your UserDetailsService.loadUserByUsername throw a UsernameNotFoundException if the user exists, but is not activated.

Resources