I have got some problem about when I wanna get "access token", I using spring security in my project
WebSecurity Config
I set user in memory for authentication in this class and I am using memory token
#Configuration
public class WebSecurityConfig {
#Bean
public static BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Configuration
#EnableWebSecurity
public static class ApiLoginConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().csrf().disable().antMatcher("/oauth/token").authorizeRequests().anyRequest().permitAll();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("sencer").password("123").roles("ADMIN");
}
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
AuthorizationServerConfig
I define client_id and client_secret in configure(ClientDetailsServiceConfigurer configurer) for API security
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter {
static final String CLIEN_ID = "devglan-client";
static final String CLIENT_SECRET = "$2a$04$P5rlxlVjNvO2VROrwktmrevMV/XQr7LSkF6aJveL4R7k/0SAR8VQu";
static final String GRANT_TYPE = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60*60;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
#Autowired
private TokenStore tokenStore;
#Autowired
#Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(CLIEN_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT )
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager);
}
}
ResourceServerConfig
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/users/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
I send grant_type , client_id , client_secret , username and password correctly but not response "access token" on API
If you want to disable basic authentication for default Token Endpoint, then preferable way is to allow form authentication for client allowFormAuthenticationForClients()
Try removing this http security configuration
http.httpBasic().disable().csrf().disable().antMatcher("/oauth/token").authorizeRequests().anyRequest().permitAll();
and configure this
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
Related
I have a hard time on a personal study project. Difficulty implementing oauth2, whenever I try to get access token it returns me
2019-11-19 22:01:35.398 ERROR 4705 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:448) ~[spring-security-config-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:449) ~[spring-security-config-5.2.0.RELEASE.jar:5.2.0.RELEASE]
2019-11-19 22:01:35.426 WARN 4705 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound : No mapping for POST /error
my project uses Version Spring Boot v2.2.0.RELEASE and Java 1.8
Application.propeties
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=test
spring.datasource.password=test123
spring.jpa.hibernate.ddl-auto=update
spring.datasource.testWhileIdle = true
spring.datasource.timeBetweenEvictionRunsMillis = 3600000
spring.datasource.validationQuery = SELECT 1
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
spring.jpa.show-sql=true
AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("angular")
.secret(passwordEncoder.encode("angular"))
.scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(1800)
.refreshTokenValiditySeconds(3600 * 24)
.and()
.withClient("admin")
.secret("admin")
.scopes("read")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(1800)
.refreshTokenValiditySeconds(3600 * 24);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
.reuseRefreshTokens(false)
.authenticationManager(authenticationManager);
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("financas");
return accessTokenConverter;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
ResourceServerConfig
#Configuration
#EnableWebSecurity
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/pagamento").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.csrf().disable();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.stateless(true);
}
#Bean
public static PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
public MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
SecurityConfig
#EnableWebSecurity
#EnableAuthorizationServer
#EnableResourceServer
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}
now my refresh token classes
RefreshTokenPostProcessor
#ControllerAdvice
public class RefreshTokenPostProcessor implements ResponseBodyAdvice<OAuth2AccessToken> {
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return returnType.getMethod().getName().equals("postAccessToken");
}
#Override
public OAuth2AccessToken beforeBodyWrite(OAuth2AccessToken body,
MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest request, ServerHttpResponse response) {
HttpServletRequest req = ((ServletServerHttpRequest)request).getServletRequest();
HttpServletResponse resp = ((ServletServerHttpResponse)response).getServletResponse();
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) body;
String refreshToken = body.getRefreshToken().getValue();
adicionaRefreshTokenNoCookie(refreshToken, req, resp);
removerRefreshTokenDoBody(token);
return body;
}
private void removerRefreshTokenDoBody(DefaultOAuth2AccessToken token) {
token.setRefreshToken(null);
}
private void adicionaRefreshTokenNoCookie(String refreshToken, HttpServletRequest req, HttpServletResponse resp) {
Cookie refreshTokenCookie = new Cookie("refreshToken", refreshToken);
refreshTokenCookie.setHttpOnly(true);
refreshTokenCookie.setSecure(false); //TODO: change in production
refreshTokenCookie.setPath(req.getContextPath() + "/oauth/token");
refreshTokenCookie.setMaxAge(2592000);
resp.addCookie(refreshTokenCookie);
}
}
RefreshTokenPreProcessorFilter
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class RefreshTokenPreProcessorFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if ("/oauth/token".equalsIgnoreCase(req.getRequestURI())
&& "refresh_token".equals(req.getParameter("grant_type"))
&& req.getCookies() != null) {
for (Cookie cookie : req.getCookies()) {
if (cookie.getName().equals("refreshToken")) {
String refreshToken = cookie.getValue();
req = new MyServletRequestWrapper(req, refreshToken);
}
}
}
chain.doFilter(req, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
static class MyServletRequestWrapper extends HttpServletRequestWrapper {
private String refreshToken;
public MyServletRequestWrapper(HttpServletRequest request, String refreshToken) {
super(request);
}
#Override
public Map<String, String[]> getParameterMap() {
ParameterMap<String, String[]> map = new ParameterMap<>(getRequest().getParameterMap());
map.put("refresh_token", new String[] {refreshToken});
map.setLocked(true);
return map;
}
}
}
SpringBootApplication
#SpringBootApplication
#WebAppConfiguration
public class FinancaApplication {
public static void main(String[] args) {
SpringApplication.run(FinancaApplication.class, args);
}
}
Remembering that my authentication is in the database and I am using PasswordEncoder on the database password and authentication passwords, I would like some help setting up the server and where my error is because I cannot generate an access token, the error returned is just this one in the console. thankful
I like your code Felipe - it's a very nicely written API - the problem is that it attempts to issue tokens also, which an API should not do.
I'd recommend walking through my tutorial, to understand the roles of API, UI and Authorization Server:
https://authguidance.com/2017/09/24/basicspa-overview/
Once you've done that I think you'll be able to adapt your API and fix your own problems - feel free to post back any follow up questions though.
In the real world almost all companies use a third party (cloud) system as the Authorization Server:
https://authguidance.com/2019/09/15/developer-domain-setup/
You will learn OAuth much faster this way - and it is free.
You then only need to focus on integrating your APIs and UIs with standards compliant endpoints like this:
https://authguidance.com/2019/03/24/java-spring-boot-api-oauth-coding/
Happy to answer follow up questions if it helps ..
I got stucked on this authorization problem, no matter what i do i can't forward.
If i protect my resource with #PreAuthorize, i receive an access_denied in response.
The Rest Controller:
#RestController
#RequestMapping("/api/users")
public class UserRestController {
private UserService userService;
#GetMapping
#PreAuthorize("hasRole('USER')")
public ResponseEntity<Collection<User>> findAll() {
return ResponseEntity.status(HttpStatus.OK).body(userService.findAll());
}
}
The Websecurity:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().disable() // disable form authentication
.anonymous().disable() // disable anonymous user
.authorizeRequests().anyRequest().denyAll(); // denying all access
}
}
The Authorization server config:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private ApplicationConfigurationProperties configuration;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailOath2Service userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.tokenServices(tokenServices())
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(configuration.getClientId())
.secret(configuration.getClientSecret())
.scopes("read", "write")
.authorizedGrantTypes("client_credentials", "password", "refresh_token")
.resourceIds(RestApiResourceServerConfiguration.RESOURCE_ID);
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setTokenEnhancer(accessTokenConverter());
return defaultTokenServices;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("abcd");
return converter;
}
}
The resource server:
#Configuration
#EnableResourceServer
public class RestApiResourceServerConfiguration extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "restservice";
#Autowired
private DefaultTokenServices tokenServices;
#Autowired
private TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID)
.tokenServices(tokenServices)
.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll().and().csrf().disable();
}
}
The User detail service:
#Service
public class UserDetailOath2Service implements UserDetailsService {
private final Logger LOGGER = Logger.getLogger(UserDetailOath2Service.class);
#Autowired
private UserRepository repository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) {
LOGGER.info("Entering in loadUserByUsername " + username);
final User user = repository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
final List<SimpleGrantedAuthority> authorities = user.getAuthorities().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
}
When i ask for http://localhost:8090/oauth/token i receive the token:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzdHNlcnZpY2UiXSwidXNlcl9uYW1lIjoiYWxlcyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJleHAiOjE1NDgxMTExNjcsImF1dGhvcml0aWVzIjpbIlVTRVIiXSwianRpIjoiNGZjODNiOTktMjZiNC00NWZkLWIxMGQtZDgxMzAzZDM2MjM4IiwiY2xpZW50X2lkIjoiZGF0YXJlc3RjbGllbnQifQ.rZAB_LmKuAN6R7i-7dUvYv4Q6vr8LhTNKgPMDVufFTc",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzdHNlcnZpY2UiXSwidXNlcl9uYW1lIjoiYWxlcyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdGkiOiI0ZmM4M2I5OS0yNmI0LTQ1ZmQtYjEwZC1kODEzMDNkMzYyMzgiLCJleHAiOjE1NTA2NTk5NjcsImF1dGhvcml0aWVzIjpbIlVTRVIiXSwianRpIjoiNGNiYWYyZWUtOTFhOC00N2Q2LTllZmEtYzA4ODI1NTI5MmQ3IiwiY2xpZW50X2lkIjoiZGF0YXJlc3RjbGllbnQifQ.41tdJ3Qc4nodc4ZAOr6dhYOa8XTqBOFQc9X1yM7NrGE",
"expires_in": 43199,
"scope": "read write",
"jti": "4fc83b99-26b4-45fd-b10d-d81303d36238"
}
So i take the token and try to call the protected resource:
GET /api/users HTTP/1.1
Host: localhost:8090
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzdHNlcnZpY2UiXSwidXNlcl9uYW1lIjoiYWxlcyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJleHAiOjE1NDgxMTExNjcsImF1dGhvcml0aWVzIjpbIlVTRVIiXSwianRpIjoiNGZjODNiOTktMjZiNC00NWZkLWIxMGQtZDgxMzAzZDM2MjM4IiwiY2xpZW50X2lkIjoiZGF0YXJlc3RjbGllbnQifQ.rZAB_LmKuAN6R7i-7dUvYv4Q6vr8LhTNKgPMDVufFTc
The result is this:
{
"error": "access_denied",
"error_description": "Access is denied"
}
The user i have generate the token has a USER role.
Please, can someone help me to find what i doing wrong?
Thanks.
The generated token has a USER authority, not a USER role.
There is a subtle but significant difference between a role and a authority: https://www.baeldung.com/spring-security-granted-authority-vs-role
Change #PreAuthorize("hasRole('USER')") to #PreAuthorize("hasAuthority('USER')") or grant the authority ROLE_USER to get the role USER
It seems that you haven't provided the resource access to the role.
public void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.csrf().disable().authorizeRequests()
// This is needed to enable swagger-ui interface.
.antMatchers("/swagger-ui.html","/swagger-resources/**","/webjars/**", "/v2/api-docs/**").permitAll()
.antMatchers("/api/v1/**").hasAuthority("ROLE_TRUSTED_CLIENT")
// #formatter:on
}
Ensure that you are not overwriting the authority to some other role/permission. So configuration like
public void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.csrf().disable().authorizeRequests()
// This is needed to enable swagger-ui interface.
.antMatchers("/swagger-ui.html","/swagger-resources/**","/webjars/**", "/v2/api-docs/**").permitAll()
.antMatchers("/api/v1/**").hasAuthority("ROLE_TRUSTED_CLIENT")
.antMatchers("/api/v1/**").hasAuthority("ROLE_USER");
// #formatter:on
}
will have a problem. The permission is only now granted to ROLE_USER and the ROLE_TRUSTED_CLIENT.
To provide multiple roles access please use following
http.csrf().disable().authorizeRequests()
.antMatchers("/swagger-ui.html","/swagger-resources/**","/webjars/**", "/v2/api-docs/**").permitAll()
.antMatchers("/api/v1/**").hasAnyAuthority("ROLE_TRUSTED_CLIENT", "ROLE_USER")
.anyRequest().authenticated();
I have a Spring Cloud (Edgeware.SR3) OAuth2 Authorization server configured with Custom JWT tokens. I'm getting an IllegalStateException, UserDetailsService is required error when I hit the token_refresh endpoint.
Does anyone have an example of doing a UserDetails Service for Active Directory for this scenario? I presume the call for refreshing the token is actually checking against AD if the user is still valid such as not disabled since last successful login.
Not shown is I'm also doing integrations to AWS Cognito in the custom token enhancer which is also all working. Just the refresh token is what remains.
#Configuration
public class ServiceConfig extends GlobalAuthenticationConfigurerAdapter {
#Value("${ldap.domain}")
private String DOMAIN;
#Value("${ldap.url}")
private String URL;
#Override
public void init(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
}
--------
#Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
#Autowired
public AuthorizationServerConfiguration(AuthenticationManager authenticationManager){
super();
this.authenticationManager = authenticationManager;
}
#Value("${signing.key}")
private String signingKey;
#Bean
public JwtAccessTokenConverter accessTokenConverter(){
final JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey(signingKey);
return accessTokenConverter;
}
#Bean
public TokenStore tokenStore(){
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Primary
public DefaultTokenServices tokenServices(){
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
return tokenServices;
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("${client.id}")
.secret("${client.secret}")
.authorizedGrantTypes("password","refresh_token","authorization_code","client_credentials")
.refreshTokenValiditySeconds(3600 *24)
.scopes("xx","xx")
.autoApprove("xxxx")
.accessTokenValiditySeconds(3600);
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints){
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(
Arrays.asList(tokenEnhancer(),accessTokenConverter()));
endpoints
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST)
.accessTokenConverter(accessTokenConverter());
}
#Override//oauth/check_token?token={access_token}
public void configure(final AuthorizationServerSecurityConfigurer security)throws Exception {
security.checkTokenAccess("permitAll()");
super.configure(security);
}
#Bean
public TokenEnhancer tokenEnhancer(){
return new CustomTokenEnhancer();
}
}
I have the below application configured
#SpringBootApplication
#EnableResourceServer
#RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#RequestMapping("/home")
public String home() {
return "Hello World";
}
#RequestMapping("/reg/a")
public String reg() {
return "REGISTERED";
}
#RequestMapping(value = "/", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public String create(#RequestBody MultiValueMap<String, String> map) {
return "OK";
}
#Configuration
#EnableAuthorizationServer
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-client-with-secret")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_CLIENT")
.scopes("read")
.resourceIds("oauth2-resource")
.secret("secret");
}
}}
and
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean(name="authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String password = "pass";
String user = "user";
auth.inMemoryAuthentication()
.withUser(user).password(password).roles("USER")
.and().withUser("admin").password("admin").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/reg/**")
.and()
.authorizeRequests()
.antMatchers("/reg/**").access("hasRole('ADMIN')");
}
}
I am able to generate access token using below url with user/pass
http://localhost:8080/oauth/token
And later
http://localhost:8080/reg/a?access_token=bd280b8e-b0b0-47a7-96d9-b4f3bfa60692
is never blocked/thrown authorization error based on roles, I tried different ways like below, but nothing worked
hasAccess("#oauth2.hasRole('ADMIN')"), hasAuthority('ADMIIN'),
hasRole('ADMIIN')
Any help is much appreciated, thanks in advance.
I am trying to secure my Spring Boot Rest API using OAuth2.0 with Spring security and want to store OAuth tokens (Access Token and Refresh Token) in JDBC database.
For Username and Password validation i have created CustomUserDetailService.
I am getting following error-
{
"timestamp": 1480042650103,
"status": 401,
"error": "Unauthorized",
"message": "Bad credentials",
"path": "/oauth/token"
}
My Code is -
Oauth2Config
#Configuration
#EnableAuthorizationServer
#EnableResourceServer
public class AuthorizationServerConfiguration {
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.authorizeRequests().anyRequest().authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class OAuth2ServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Autowired
private CustomUserDetailService customUserDetailService;
#Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.approvalStoreDisabled()
.userDetailsService(customUserDetailService);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.jdbc(dataSource);
}
}
}
WebSecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
CustomUserDetailService
#Service
public class CustomUserDetailService
implements UserDetailsService {
#Override
public UserDetailsService loadUserByUsername(String username) throws UsernameNotFoundException {
// I tested this logic and works fine so i avoid this lines
return userDetailsService;
}
}
application.properties
security.oauth2.client.client-id=my-trusted-client
security.oauth2.client.client-secret=secret
security.oauth2.client.authorized-grant-types=password,refresh_token,authorization_code,implicit
security.oauth2.client.scope=read,write,trust
security.oauth2.client.resource-ids=oauth2-resource
security.oauth2.client.access-token-validity-seconds=120
security.oauth2.client.refresh-token-validity-seconds=600
Please suggest me how can i solve this error ??