How to verify signature utilizing accessTokenConverter? - spring

I need to verify signature at resource server. I am signing JWT with private key at auth.server and It is signed OK, but I cannot find a way, how to verify it using accessTokenConverter. In my previous project, I did not use JDBC, so I was using jwtTokenStore and It worked without a problem, but I cannot verify that signature with JDBCTokenStore. How to do that? So code at authorization server works, I need to verify it at resource server... .setVerifiedKey(publicKey) should be working, but I need to configure it with JDBCTokenStore...
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
// #Autowired
// private JwtAccessTokenConverter accessTokenConverter;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userCustomService;
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.jdbc(jdbcTemplate.getDataSource());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.reuseRefreshTokens(false)
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager)
.userDetailsService(userCustomService);
;
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter(){
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
if(authentication.getOAuth2Request().getGrantType().equalsIgnoreCase("password")) {
final Map<String, Object> additionalInfo = new HashMap<String, Object>();
additionalInfo.put("organization", "NEJAKA INFORMACE");
((DefaultOAuth2AccessToken) accessToken)
.setAdditionalInformation(additionalInfo);
}
accessToken = super.enhance(accessToken, authentication);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(new HashMap<>());
return accessToken;
}
};
KeyStoreKeyFactory keyStoreKeyFactory =
new KeyStoreKeyFactory(new ClassPathResource("test.jks"), "password".toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("test"));
return converter;
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Autowired
private ResourceServerTokenServices tokenServices;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices); }
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/documents/**").authenticated()
.antMatchers("/users/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
public JwtAccessTokenConverter accessTokenConverterr() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// private String signingKey = "MaYzkSjmkzPC57L";
#Autowired
private UserDetailsService userCustomService;
#Autowired
private JdbcTemplate jdbcTemplate;
private PasswordEncoder encoder;
public SecurityConfig(){
this.encoder = new BCryptPasswordEncoder();
}
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userCustomService).passwordEncoder(encoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.
STATELESS)
.and()
.httpBasic()
.and()
.csrf()
.disable();
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(jdbcTemplate.getDataSource());
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}

Related

Springboot + Oauth2 - Failed to find access token

Am getting Failed to find access token for token 9ccc7637-04af-469d-93b8-209cbfac4e49 issue printed in a console when i call http://localhost:8081/oauth/token . Please find attached images for reference .
I gave my best but could find the issue .
Where i click oauth\token the token details are getting stored in database , but still throws error.
Unable to do API calls with access token created.
Please find below code and correct me .
Configuration
public class AppConfig {
#Value("${spring.datasource.url}")
private String datasourceUrl;
#Value("${spring.datasource.driver-class-name}")
private String dbDriverClassName;
#Value("${spring.datasource.username}")
private String dbUsername;
#Value("${spring.datasource.password}")
private String dbPassword;
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(dbDriverClassName);
dataSource.setUrl(datasourceUrl);
dataSource.setUsername(dbUsername);
dataSource.setPassword(dbPassword);
return dataSource;
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource());
}
}
#Configuration
#EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private final AuthenticationManager authenticationManager;
#Autowired
private final BCryptPasswordEncoder passwordEncoder;
#Autowired
private final UserDetailsService userService;
#Autowired
private TokenStore tokenStore;
public OAuthConfiguration(AuthenticationManager authenticationManager, BCryptPasswordEncoder passwordEncoder, UserDetailsService userService) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.userService = userService;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.scopes("read","write","trust")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(50)
.refreshTokenValiditySeconds(1000)
.secret(passwordEncoder.encode("secret"));
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.userDetailsService(userService)
.authenticationManager(authenticationManager)
.tokenStore(tokenStore);
}
#Bean
public OAuth2AccessDeniedHandler oauthAccessDeniedHandler() {
return new OAuth2AccessDeniedHandler();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.requestMatchers().antMatchers("/**").and()
.authorizeRequests()
.antMatchers("/**").access("hasRole('ADMIN') or hasRole('USER')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetails;
#Autowired
DataSource dataSource;
#Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).
usersByUsernameQuery("select username, password, enabled from users where username=?").
authoritiesByUsernameQuery("select username, roles from users where username=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/**").authenticated()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder( bCryptPasswordEncoder() );
provider.setUserDetailsService(userDetails);
return provider;
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/*
* #Autowired // here is configuration related to spring boot basic public void
* configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication() // static users
* .withUser("User").password(bCryptPasswordEncoder().encode("User")).
* roles("USER") .and()
* .withUser("Admin").password(bCryptPasswordEncoder().encode("Admin[")).
* roles("ADMIN"); }
*/
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetails)
.passwordEncoder(bCryptPasswordEncoder());
}
}
error in console :
enter image description here

invalid_token:Cannot convert access token to JSON

I get error while refreshing the token(grant_type=refresh_token). It seems that user did not use the application for long time and both access token as well as refresh token expired. When app now tried to refresh token, it gets the error
{
"error": "invalid_token",
"error_description": "Cannot convert access token to JSON"
}
I saw many posts on this issue but I am still facing this error. I tried to use setVerifierKey. But no luck. Here is the code:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${security.signing-key}")
private String signingKey;
#Value("${security.encoding-strength}")
private Integer encodingStrength;
#Value("${security.security-realm}")
private String securityRealm;
#Autowired
private UserDetailsService userDetailsService;
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
// .passwordEncoder(new ShaPasswordEncoder(encodingStrength));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName(securityRealm)
.and()
.csrf()
.disable();
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
return converter;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}
//AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${security.jwt.client-id}")
private String clientId;
#Value("${security.jwt.client-secret}")
private String clientSecret;
#Value("${security.jwt.grant-type}")
private String grantType;
#Value("${security.jwt.scope-read}")
private String scopeRead;
#Value("${security.jwt.scope-write}")
private String scopeWrite = "write";
#Value("${security.jwt.resource-ids}")
private String resourceIds;
#Autowired
private TokenStore tokenStore;
#Autowired
private JwtAccessTokenConverter accessTokenConverter;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(clientId)
.secret(clientSecret)
.authorizedGrantTypes("client_credentials", "password", "refresh_token", "authorization_code")
.scopes(scopeRead, scopeWrite)
// .accessTokenValiditySeconds(60)
// .refreshTokenValiditySeconds(2000)
.resourceIds(resourceIds);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
enhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
endpoints.tokenStore(tokenStore)
.accessTokenConverter(accessTokenConverter)
.tokenEnhancer(enhancerChain).userDetailsService(userDetailsService)
.authenticationManager(authenticationManager);
}
}
I expect that token will be refreshed but I get the error as mentioned above. my config properties are:
security.oauth2.resource.filter-order=3
security.signing-key=ZMaasazkSjmaasw
security.encoding-strength=256
security.security-realm=Spring Boot JWT Example Realm
security.jwt.grant-type=password security.jwt.scope-read=read
security.jwt.scope-write=write
security.jwt.resource-ids=testjwtresourceid
Any Help appreciated!!

springboot oauth how to validate access_token

Hello everyone hope you doing well,
i have problem using open authentication in spring boot, when accessing page rest with postman is not even using param access token it still show the result, this my code please help???
Authorization Server Config class:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter{
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler);
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// TODO Auto-generated method stub
clients.inMemory()
.withClient("admin").secret("123")
.scopes("read","write")
.authorizedGrantTypes("password","refresh_token")
.accessTokenValiditySeconds(5*60)
.refreshTokenValiditySeconds(10*60);
}
}
Resource Server Config
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
#Override
public void configure(HttpSecurity http)throws Exception{
http
.anonymous().disable()
.authorizeRequests().antMatchers("/api/**") /** this
.authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
Security Config
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private SecurityUtility hash;
#Autowired
private ClientDetailsService clientDetailsService;
private static final String[] PUBLIC_MATCHERS = { "/", "/css/**", "/image/**", "/js/**", "/newUser",
"/forgetPassword", "/login", "/logout", "/fonts/**", "/signUp", "/register", "/sendEmail", "/logout", "/tes","/oauth2/**","/api/**",
"/admin/tes","/SpringSecurityOAuth2Example/**",
"/admin/tes2" };
private static final String[] ADMIN_MATCHERS = { "/admin", "/admin/**" };
private static final String[] OAUTH2_PAGE = { "/oauth/**", "/api/**" };
private final String USERS_QUERY = "select username, password, is_enabled from user where username=?";
private final String ROLES_QUERY = "select u.username, u.is_enabled, r.name as authority from user u "
+ "inner join user_role ur on (u.id = ur.user_id) " + "inner join role r on (ur.role_id = r.roleid) "
+ "where username=?";
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(PUBLIC_MATCHERS).permitAll().anyRequest().authenticated().and().formLogin()
.loginPage("/login").loginProcessingUrl("/app-login").usernameParameter("app_username")
.passwordParameter("app_password").defaultSuccessUrl("/myAccount").permitAll()
.and().logout().logoutSuccessUrl("/login")
.permitAll();
http.authorizeRequests().antMatchers(ADMIN_MATCHERS).hasRole("ADMIN");
// http.csrf().disable();
http.csrf().ignoringAntMatchers(OAUTH2_PAGE);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// temporary
// auth.inMemoryAuthentication().withUser("admin").password("admin").roles("test");
auth.jdbcAuthentication().usersByUsernameQuery(USERS_QUERY).authoritiesByUsernameQuery(ROLES_QUERY)
.dataSource(dataSource).passwordEncoder(hash.passwordEncoder());
}
#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;
}
}
Auth Controller
#RestController
#EnableResourceServer
public class AuthController {
#GetMapping("/api/demo1")
public String apiTes() {
System.out.println("sysout mas");
return "return result";
}
}
solved guys, it because i was using springboot 1.5.10 so i have to add
security.oauth2.resource.filter-order=3
to spring application.properties

Facing Access Denied (403) - Forbidden error in spring security oauth2

.antMatchers("/secure2/**").authenticated();
I have configured one of my api as protected, when I try to access it, It gives me Access Denied error message, I do not know what could be the reason. Note that I am passing valid access token.
My scenario:
Basically I have created logout rest api in authorization server and I want that, request with valid token is allowed to hit this api.
Request:
GET /auth/secure2 HTTP/1.1
Host: localhost:9191
Authorization: Bearer 33984141-1249-4465-a3aa-0b95a053fc63
Cache-Control: no-cache
Postman-Token: f4661790-a8e1-90ea-f6db-79cb37958cdf
Response:
{
"timestamp": 1500186837033,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/auth/secure2"
}
I found out that below method return false and due to that it raise the access denied error.
public final class ExpressionUtils {
public static boolean evaluateAsBoolean(Expression expr, EvaluationContext ctx) {
try {
return ((Boolean) expr.getValue(ctx, Boolean.class)).booleanValue();
}
catch (EvaluationException e) {
throw new IllegalArgumentException("Failed to evaluate expression '"
+ expr.getExpressionString() + "'", e);
}
}
}
Below are the screen shots which I captured by debugging in framework. Please also check the images mentioned in comment.
Code:
SecurityConfiguration.java :
import org.springframework.beans.factory.annotation.Autowired;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public ShaPasswordEncoder encoder() {
return new ShaPasswordEncoder(256);
}
#Override
public void configure(WebSecurity web) throws Exception {}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
.disable()
.headers()
.frameOptions().disable().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/hello/").permitAll()
.antMatchers("/secure3/").permitAll()
.antMatchers("/oauth/token/revoke/**").authenticated()
.antMatchers("/secure2/**").authenticated();
}
#Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
private static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
public GlobalSecurityConfiguration() {
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
}
Oauth2Configuration.java
#Configuration
public class OAuth2Configuration {
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
//private static final String PROP_CLIENTID = "clientid";
//private static final String PROP_SECRET = "secret";
private static final String PROP_ACCESS_TOKEN_VALIDITY_SECONDS = "accessTokenValidityInSeconds";
private static final String PROP_REFRESH_TOKEN_VALIDITY_SECONDS = "refreshTokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
#Autowired
private DataSource dataSource;
#Autowired
private CustomUserDetailService userDetailsService;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenStore(tokenStore())
.userDetailsService(userDetailsService)
.tokenEnhancer(tokenEnhancer())
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
public DefaultAccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("clientId")
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_ACCESS_TOKEN_VALIDITY_SECONDS, Integer.class, 80))
.refreshTokenValiditySeconds(propertyResolver.getProperty(PROP_REFRESH_TOKEN_VALIDITY_SECONDS, Integer.class, 180))
.and().inMemory()
.withClient("clientid")
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("client_credentials")
.secret("secret");
}
#Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
}
Controller:
#Controller
#RequestMapping("/secure2")
public class SecureController1 {
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String sayHello() {
return "Secure Hello secure2!";
}
}
What are the scenarios in which it raises access denied error message? Please let me know if any other information in needed.
I used these codes and they worked well.
OAuth2AuthorizationServerConfig.java:
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
// Configure the token store and authentication manager
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//#formatter:off
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter()) // added for JWT
.authenticationManager(authenticationManager);
//#formatter:on
}
// Configure a client store. In-memory for simplicity, but consider other
// options for real apps.
//It is not necessary.works even without this func:)
// #Override
// public void configure(AuthorizationServerSecurityConfigurer oauthServer)
// throws Exception {
// oauthServer
// .tokenKeyAccess("permitAll()")
// .checkTokenAccess("isAuthenticated()");
// }
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//#formatter:off
clients
.inMemory()
.withClient("myclient")//username in basic auth header
.secret ("{noop}123")//password in basic auth header;
.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token")
.scopes("read")
//.redirectUris("http://localhost:9191/x")
.accessTokenValiditySeconds(86400); // 24 hours
//#formatter:on
}
// A token store bean. JWT token store
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter()); // For JWT. Use in-memory, jdbc, or other if not JWT
}
// Token converter. Needed for JWT
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123"); // symmetric key
return converter;
}
// Token services. Needed for JWT
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
// #Bean
//
// public PasswordEncoder passwordEncoder () {
//
// return new BCryptPasswordEncoder();
//
// }
}
WebSecurityConfig:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
//It is not important to use this func. /oauth/token is the default path of spring security to use oauth2. she is so clever!! :)
// #Override
// protected void configure(HttpSecurity http) throws Exception {
//
//
// http.authorizeRequests()
// .antMatchers(HttpMethod.POST, "/oauth/token").permitAll()
// .anyRequest().authenticated();
// }
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}user").roles("ROLE");
}
//
// #Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(userDetailsService)
// .passwordEncoder(passwordEncoder());
// }
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
//
// #Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
}
Output:
Please notice that the values of username and password used in code and postman, must be the same.
enter image description here
enter image description here
Hope to be helpful:)

Why I'm getting AuthenticationCredentialsNotFoundException?

I want to configure OAuth2 authentication for my application.
I have next configurations:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
#Configuration
#EnableAuthorizationServer
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
private static final String[] GRANT_TYPES = {"password", "refresh_token"};
private static final String[] SCOPES = {"read", "write"};
private final SecurityConfigurationProperties securityConfigurationProperties;
private final AuthenticationProvider authenticationProvider;
private final OAuth2AccessTokenRepository oAuth2AccessTokenRepository;
private final OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;
#Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(securityConfigurationProperties.getClientId())
.authorizedGrantTypes(GRANT_TYPES)
.authorities(UserRole.USER.getName())
.scopes(SCOPES)
.secret(securityConfigurationProperties.getClientSecret())
.accessTokenValiditySeconds(securityConfigurationProperties.getAccessTokenTime())
.refreshTokenValiditySeconds(securityConfigurationProperties.getRefreshTokenTime());
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager())
.approvalStoreDisabled();
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Collections.singletonList(authenticationProvider));
}
#Bean
public TokenStore tokenStore() {
return new MongoTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository);
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setAuthenticationManager(authenticationManager());
return tokenServices;
}
}
#Configuration
#EnableResourceServer
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "api";
private final TokenStore tokenStore;
#Override
public void configure(final ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http.anonymous().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final ApiUserDetailsService apiUserDetailsService;
private final AuthenticationProvider authenticationProvider;
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/").authenticated();
}
}
Also I have my custom AuthenticationProvider:
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class UserAuthenticationProvider implements AuthenticationProvider {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
#Override
public Authentication authenticate(final Authentication authentication)
throws AuthenticationException {
final String email = authentication.getName();
final String password = authentication.getCredentials().toString();
return userRepository.findByEmail(email)
.filter(user -> passwordEncoder.matches(password, user.getPassword()))
.map(this::signInUser)
.orElseThrow(() -> new BadCredentialsException("Failed to authenticate"));
}
#Override
public boolean supports(final Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
private Authentication signInUser(final User user) {
final ApiUser springSecurityUser =
new ApiUser(user.getEmail(), user.getPassword(), user.getRoles());
final Authentication authentication = new UsernamePasswordAuthenticationToken(springSecurityUser,
user.getId(), springSecurityUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
return authentication;
}
}
Everything works for token I'm getting access and refresh tokens from /oauth/token endpoint, but when I'm trying to access resource with #PreAuthorize annotation I'm getting error.
Link for it http://localhost:8080/users/me?access_token=8450e2f3-2ecb-4e88-b304-685b22c2ad65 also I've tried to add "Authorization: Bearer 8450e2f3-2ecb-4e88-b304-685b22c2ad65" to headers
{
"timestamp": 1490358162182,
"status": 403,
"error": "Forbidden",
"exception": "org.springframework.security.authentication.AuthenticationCredentialsNotFoundException",
"message": "Access Denied",
"path": "/users/me"
}
My endpoint:
#PreAuthorize("hasRole('ROLE_USER')")
#RequestMapping(value = RestPath.Users.ME, method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity userInfo() {
return ResponseEntity.noContent().build();
}
Maybe someone had already such exception with same configuration.
Ok so the main problem in my configuration was in SecurityConfiguration class. I've added annotation #Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) according to this post https://stackoverflow.com/a/42836521/2055854.
Now it looks:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
And I've also changed a bit my configurations:
#Configuration
public class OAuth2Config {
#Configuration
#EnableResourceServer
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public static class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "api";
private static final String AUTHORIZATION = "Authorization";
private static final String BEARER = "Bearer";
private static final String ACCESS_TOKEN = "access_token";
private final TokenStore tokenStore;
#Override
public void configure(final ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().anyRequest().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
#Configuration
#EnableAuthorizationServer
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public static class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
private static final String[] GRANT_TYPES = {"password", "refresh_token"};
private static final String[] SCOPES = {"read", "write"};
private final SecurityConfigurationProperties securityConfigurationProperties;
private final AccessTokenRepository oAuth2AccessTokenRepository;
private final RefreshTokenRepository oAuth2RefreshTokenRepository;
private final AuthenticationProvider authenticationProvider;
private final UserDetailsService userDetailsService;
#Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(securityConfigurationProperties.getClientId())
.authorizedGrantTypes(GRANT_TYPES)
.authorities(UserRole.USER.getName())
.secret(securityConfigurationProperties.getClientSecret())
.scopes(SCOPES)
.resourceIds(OAuth2ResourceServerConfig.RESOURCE_ID)
.accessTokenValiditySeconds(securityConfigurationProperties.getAccessTokenTime())
.refreshTokenValiditySeconds(securityConfigurationProperties.getRefreshTokenTime());
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager())
.userDetailsService(userDetailsService);
}
public AuthenticationManager authenticationManager() {
return new ProviderManager(Collections.singletonList(authenticationProvider));
}
#Bean
public TokenStore tokenStore() {
return new MongoTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository);
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setAuthenticationManager(authenticationManager());
return tokenServices;
}
}
}
Now everything works as expected.

Resources