Returning bad credential in oauth2 implemention using spring boot 1.5 - spring

As i am trying to create simple login in oauth2 implementation using spring boot. Unfortunately its not working, as i am newbie in spring
My configuration
ApplicationStarter.java
#SpringBootApplication
#EnableAutoConfiguration
public class ApplicationStarter extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ApplicationStarter.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationStarter.class, args);
}
}
ResourceServerConfiguration.java
#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);
}
#Override
public void configure(HttpSecurity http) throws Exception {
System.out.println("Inside ResourceServerConfiguration");
http.
anonymous().disable()
.requestMatchers().antMatchers("/user/**")
.and().authorizeRequests()
.antMatchers("/user/**").access("hasRole('ADMIN')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
AuthorizationServerConfiguration.java
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static String REALM="MY_OAUTH_REALM";
#Autowired
private TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("Inside AuthorizationServerConfiguration");
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.secret("secret")
.accessTokenValiditySeconds(120).//Access token is only valid for 2 minutes.
refreshTokenValiditySeconds(600);//Refresh token is only valid for 10 minutes.
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm(REALM+"/client");
}
}
MethodSecurityConfig.java
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Autowired
private OAuth2SecurityConfiguration securityConfig;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
OAuth2SecurityConfiguration.java
#Configuration
#ComponentScan
#EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : globalUserDetails()");
auth.inMemoryAuthentication()
.withUser("bill").password("abc123").roles("ADMIN").and()
.withUser("bob").password("abc123").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : configure()");
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : authenticationManagerBean()");
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
System.out.println("inside OAuth2SecurityConfiguration : tokenStore()");
return new InMemoryTokenStore();
}
#Bean
#Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
System.out.println("inside OAuth2SecurityConfiguration : userApprovalHandler()");
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 {
System.out.println("inside OAuth2SecurityConfiguration : approvalStore()");
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}
Please do correct me where i am went wrong? whether any more configuration needed or not?
as i followed
http://websystique.com/spring-security/secure-spring-rest-api-using-oauth2/
as reference.
spring boot log
2017-10-26 11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.b.w.f.OrderedRequestContextFilter : Bound request context to
thread: org.apache.catalina.connector.RequestFacade#1f2fcd1 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/css/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/css/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/js/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/js/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/images/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/images/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/webjars/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/webjars/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='//favicon.ico'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '//favicon.ico'
2017-10-26 11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/error'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/error' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : No matches found 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Request
'/oauth/token' matched by universal pattern '/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : matched 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.security.web.FilterChainProxy :
/oauth/token?grant_type=password&username=bill&password=abc123 at
position 1 of 11 in additional filter chain; firing Filter:
'WebAsyncManagerIntegrationFilter' 2017-10-26 11:15:07.851 DEBUG 21456
--- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : /oauth/token?grant_type=password&username=bill&password=abc123 at
position 2 of 11 in additional filter chain; firing Filter:
'SecurityContextPersistenceFilter' 2017-10-26 11:15:07.852 DEBUG 21456
--- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : /oauth/token?grant_type=password&username=bill&password=abc123 at
position 3 of 11 in additional filter chain; firing Filter:
'HeaderWriterFilter' 2017-10-26 11:15:07.852 DEBUG 21456 ---
[nio-8080-exec-5] o.s.security.web.FilterChainProxy :
/oauth/token?grant_type=password&username=bill&password=abc123 at
position 4 of 11 in additional filter chain; firing Filter:
'LogoutFilter' 2017-10-26 11:15:07.852 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.web.util.matcher.OrRequestMatcher : Trying to
match using Ant [pattern='/logout', GET] 2017-10-26 11:15:07.852 DEBUG
21456 --- [nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher :
Request 'POST /oauth/token' doesn't match 'GET /logout 2017-10-26
11:15:07.852 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/logout', POST] 2017-10-26 11:15:07.852 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/logout' 2017-10-26
11:15:07.852 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/logout', PUT] 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Request
'POST /oauth/token' doesn't match 'PUT /logout 2017-10-26 11:15:07.869
DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/logout', DELETE] 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Request
'POST /oauth/token' doesn't match 'DELETE /logout 2017-10-26
11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : No matches found 2017-10-26
11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.security.web.FilterChainProxy :
/oauth/token?grant_type=password&username=bill&password=abc123 at
position 5 of 11 in additional filter chain; firing Filter:
'BasicAuthenticationFilter' 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.a.www.BasicAuthenticationFilter : Basic
Authentication Authorization header found for user 'my-trusted-client'
2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.authentication.ProviderManager : Authentication attempt
using
org.springframework.security.authentication.dao.DaoAuthenticationProvider
2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.a.dao.DaoAuthenticationProvider : User 'my-trusted-client'
not found 2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.w.a.www.BasicAuthenticationFilter : Authentication request for
failed:
org.springframework.security.authentication.BadCredentialsException:
Bad credentials 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.header.writers.HstsHeaderWriter : Not
injecting HSTS header since it did not match the requestMatcher
org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#1ff799
2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now
cleared, as request processing completed 2017-10-26 11:15:07.869 DEBUG
21456 --- [nio-8080-exec-5] o.s.b.w.f.OrderedRequestContextFilter :
Cleared thread-bound request context:
org.apache.catalina.connector.RequestFacade#1f2fcd1 2017-10-26
11:15:07.870 DEBUG 21456 --- [nio-8080-exec-5]
o.s.web.servlet.DispatcherServlet : DispatcherServlet with name
'dispatcherServlet' processing POST request for [/auth/error]
2017-10-26 11:15:07.870 DEBUG 21456 --- [nio-8080-exec-5]
s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method
for path /error 2017-10-26 11:15:07.870 DEBUG 21456 ---
[nio-8080-exec-5] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning
handler method [public
org.springframework.http.ResponseEntity>
org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2017-10-26 11:15:07.870 DEBUG 21456 --- [nio-8080-exec-5]
o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance
of singleton bean 'basicErrorController' 2017-10-26 11:15:07.874 DEBUG
21456 --- [nio-8080-exec-5] o.s.w.s.m.m.a.HttpEntityMethodProcessor :
Written [{timestamp=Thu Oct 26 11:15:07 IST 2017, status=401,
error=Unauthorized, message=Bad credentials, path=/auth/oauth/token}]
as "application/json" using
[org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#32886a]
2017-10-26 11:15:07.874 DEBUG 21456 --- [nio-8080-exec-5]
o.s.web.servlet.DispatcherServlet : Null ModelAndView returned
to DispatcherServlet with name 'dispatcherServlet': assuming
HandlerAdapter completed request handling 2017-10-26 11:15:07.874
DEBUG 21456 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet
: Successfully completed request
gradle.build
> /* * This build file was generated by the Gradle 'init' task. * *
> This generated file contains a sample Java Library project to get you
> started. * For more details take a look at the Java Libraries chapter
> in the Gradle * user guide available at
> https://docs.gradle.org/3.5/userguide/java_library_plugin.html */
> buildscript {
> ext { springBootVersion = '1.5.7.RELEASE' }
> repositories { mavenCentral() }
> dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
> } } // Apply the java-library plugin to add support for Java Library
> apply plugin: 'java' apply plugin: 'eclipse' apply plugin:
> 'org.springframework.boot' apply plugin: 'war'
>
>
> sourceCompatibility = 1.8 // In this section you declare where to find
> the dependencies of your project repositories {
> // Use jcenter for resolving your dependencies.
> // You can declare any Maven/Ivy/file repository here. // jcenter() mavenCentral() }
>
> dependencies {
> // This dependency is exported to consumers, that is to say found on their compile classpath.
> //api 'org.apache.commons:commons-math3:3.6.1'
> //providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.5.2.RELEASE'
> // This dependency is used internally, and not exposed to consumers on their own compile classpath.
> implementation 'com.google.guava:guava:21.0'
>
> // Use JUnit test framework
> testImplementation 'junit:junit:4.12'
>
>
> // compile("org.springframework.boot:spring-boot-starter-security:1.4.1.RELEASE")
> // compile("org.springframework.security.oauth:spring-security-oauth2:2.0.2.RELEASE")
> //
> compile("org.springframework.security:spring-security-config:3.2.0.RELEASE")
> // compile("org.gitlab4j:gitlab4j-api:4.6.0")
> // compile("org.springframework.boot:spring-boot-starter-tomcat:1.5.2.RELEASE")
>
> compile('org.springframework.boot:spring-boot-starter-actuator')
> compile('org.springframework.boot:spring-boot-starter-security')
> compile('org.springframework.security.oauth:spring-security-oauth2')
> compile('org.springframework.security:spring-security-config')
> compile('org.springframework.boot:spring-boot-starter-web')
> providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
>
> testCompile('org.springframework.boot:spring-boot-starter-test') }

Change your authorization server config like that
AuthorizationServerConfiguration.java
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("Inside AuthorizationServerConfiguration");
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust").resourceIds("my_rest_api")
.secret("secret")
.accessTokenValiditySeconds(120).//Access token is only valid for 2 minutes.
refreshTokenValiditySeconds(600);//Refresh token is only valid for 10 minutes.
}
Here changes is I put a resourceIds after scope and that resource id will be same as Resources server's RESOURCE_ID.
You declared in ResourceServerConfiguration such like that
private static final String RESOURCE_ID = "my_rest_api";
So putting the string in authorization server can solve your problem I believe.
Thanks.

Related

Keycloak integration with SpringDoc and spring boot

App stack: Spring boot / Spring Doc / Keycloak
I am trying to integrate the above stack together, everything works well till I am using keycloak policy enforcement.
At the bringing the app is running and I can access the Swagger UI served thanks to spring doc, but after like 20 or 30 seconds, I got HTTP ERROR 401 while I am trying to access the exact link of swagger and keycloak refuse all access to any URL or rest API
Console Error:
2022-05-22 23:31:55.650 DEBUG 92263 --- [io-8080-exec-10] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/swagger-ui/index.html
2022-05-22 23:31:55.650 DEBUG 92263 --- [io-8080-exec-10] o.k.adapters.PreAuthActionsHandler : checkCorsPreflight http://localhost:8080/swagger-ui/index.html
2022-05-22 23:31:55.651 DEBUG 92263 --- [io-8080-exec-10] .k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /swagger-ui/index.html
2022-05-22 23:31:55.651 DEBUG 92263 --- [io-8080-exec-10] o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:8080/swagger-ui/index.html
2022-05-22 23:31:55.651 DEBUG 92263 --- [io-8080-exec-10] o.k.a.AuthenticatedActionsHandler : Origin: null uri: http://localhost:8080/swagger-ui/index.html
2022-05-22 23:31:55.651 DEBUG 92263 --- [io-8080-exec-10] o.k.a.AuthenticatedActionsHandler : cors validation not needed as we are not a secure session or origin header was null: http://localhost:8080/swagger-ui/index.html
2022-05-22 23:31:55.651 DEBUG 92263 --- [io-8080-exec-10] o.k.a.authorization.PolicyEnforcer : Policy enforcement is enabled. Enforcing policy decisions for path [http://localhost:8080/swagger-ui/index.html].
2022-05-22 23:31:55.917 DEBUG 92263 --- [io-8080-exec-10] o.k.a.authorization.PolicyEnforcer : Policy enforcement result for path [http://localhost:8080/swagger-ui/index.html] is : DENIED
2022-05-22 23:31:55.917 DEBUG 92263 --- [io-8080-exec-10] o.k.a.authorization.PolicyEnforcer : Returning authorization context with permissions:
2022-05-22 23:31:55.917 DEBUG 92263 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : Securing GET /error
2022-05-22 23:31:55.917 DEBUG 92263 --- [io-8080-exec-10] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2022-05-22 23:31:55.917 DEBUG 92263 --- [io-8080-exec-10] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/error
2022-05-22 23:31:55.917 DEBUG 92263 --- [io-8080-exec-10] o.k.adapters.PreAuthActionsHandler : checkCorsPreflight http://localhost:8080/error
2022-05-22 23:31:55.917 TRACE 92263 --- [io-8080-exec-10] f.KeycloakAuthenticationProcessingFilter : Did not match request to Or [Ant [pattern='/sso/login'], RequestHeaderRequestMatcher [expectedHeaderName=Authorization, expectedHeaderValue=null], org.keycloak.adapters.springsecurity.filter.QueryParamPresenceRequestMatcher#1eab2ee7, org.keycloak.adapters.springsecurity.filter.AdapterStateCookieRequestMatcher#2ad76210]
2022-05-22 23:31:55.918 DEBUG 92263 --- [io-8080-exec-10] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2022-05-22 23:31:55.918 DEBUG 92263 --- [io-8080-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /error] with attributes [authenticated]
2022-05-22 23:31:55.918 DEBUG 92263 --- [io-8080-exec-10] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
My policy enforcement to swagger links here is my keycloak YAML file
keycloak:
realm: phelix
auth-server-url: https://keycloak-server-url/auth
ssl-required: none
resource: orders
use-resource-role-mappings: true
bearer-only: true
cors-exposed-headers: X-Total-Count
cors: true
principal-attribute: preferred_username
credentials:
secret: 111-111-111.....
policy-enforcer-config:
enforcement-mode: ENFORCING
lazy-load-paths: true
paths:
- path: /swagger-ui/*.html
enforcement-mode: DISABLED
- path: /actuator/*
enforcement-mode: DISABLED
- path: /swagger-ui/*
enforcement-mode: DISABLED
- path: /swagger-ui.html
enforcement-mode: DISABLED
- path: /v3/api-docs/*
enforcement-mode: DISABLED
Security config class which extends keycloak adapter
#KeycloakConfiguration
#ConditionalOnProperty(name = "security.config.use-keycloak", havingValue = "true", matchIfMissing = true)
#ConfigurationProperties(prefix = "keycloak")
#PropertySource(value = "classpath:keycloak-configs.yml", factory = YamlPropertySourceFactory.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
private static final String[] WHITELIST_URLS = {
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/actuator/**",
};
public KeycloakClientRequestFactory keycloakClientRequestFactory;
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable()
.authorizeRequests()
.antMatchers(WHITELIST_URLS).permitAll()
.anyRequest().authenticated();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider authenticationProvider = keycloakAuthenticationProvider();
SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
mapper.setPrefix("");
authenticationProvider.setGrantedAuthoritiesMapper(mapper);
auth.authenticationProvider(authenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy(); //for bearer-only services
}
#Bean
public KeycloakDeployment keycloakDeploymentBuilder(KeycloakSpringBootProperties configuration) {
return KeycloakDeploymentBuilder.build(configuration);
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public KeycloakRestTemplate keycloakRestTemplate() {
return new KeycloakRestTemplate(keycloakClientRequestFactory);
}
#Bean
#Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public AccessToken getAccessToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.getPrincipal() instanceof KeycloakPrincipal) {
return ((KeycloakPrincipal) authentication.getPrincipal()).getKeycloakSecurityContext().getToken();
} else {
return new AccessToken();
}
}
}
Dependencies:
'springboot': '2.7.0'
'keycloakVersion': '16.1.0'
'springdoc-openapi-ui': '1.6.8'
Any thoughts ?

How to handle custom exceptions thrown by a filter in Spring Security

I am new to Spring Security.
I have a piece of code where I check if an Authorization header is passed in a request and I throw an exception if it's missing.
public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String BEARER = "Bearer";
public TokenAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String username = request.getParameter("username");
String authorization = request.getHeader("AUTHORIZATION");
if (!request.getRequestURI().equals(UniversalConstants.LOGIN_PATH)) {
if (authorization == null || authorization.length() == 0 || !authorization.startsWith(BEARER)) {
throw new InvalidCredentialsException("Missing authentication token"); //<-----------------
}
}
String password = request.getParameter("password");
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
I am targeting to handle all exceptions globally so I'm using #ControllerAdvice.
Note: I know that #ControllerAdvice will not work for exceptions thrown outside of Controllers from this and this, so I have also followed the suggestions in these links.
RestAuthenticationEntryPoint.java
#Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
public RestAuthenticationEntryPoint() {
System.out.println("RestAuthenticationEntryPoint");
}
#Autowired
#Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
resolver.resolveException(request, response, null, authException);
}
}
This is how I configure the authenticationEntryPoint:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(new RestAuthenticationEntryPoint()).and().cors().and().csrf().disable().exceptionHandling().defaultAuthenticationEntryPointFor(new RestAuthenticationEntryPoint(), PROTECTED_URLS)
.and().authenticationProvider(customAuthenticationProvider())
.addFilterBefore(tokenAuthenticationFilter(), AnonymousAuthenticationFilter.class).authorizeRequests()
.requestMatchers(PROTECTED_URLS).authenticated().and().formLogin().disable().httpBasic().disable();
}
CustomExceptionHandler.java
#ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({InvalidCredentialsException.class, AuthenticationException.class})
public ResponseEntity<ErrorResponse> handleUnauthorizedError(InvalidCredentialsException e, WebRequest request) {
String errorMessage = e.getLocalizedMessage();
ErrorResponse errorResponse = new ErrorResponse(errorMessage, null);
return new ResponseEntity<>(errorResponse, HttpStatus.UNAUTHORIZED);
}
}
InvalidCredentialsException.java
#ResponseStatus(HttpStatus.UNAUTHORIZED)
public class InvalidCredentialsException extends RuntimeException {
public InvalidCredentialsException(String errorMessage) {
super(errorMessage);
}
}
Upon debugging, I've found that the resolver.resolveException(...) in RestAuthenticationEntryPoint and the handleUnauthorizedError(..) in CustomExceptionHandler never get called.
I wish to handle throw new InvalidCredentialsException("Missing authentication token") in an elegant way and show a decent JSON output in the response.
Any help would be appreciated.
Edit: The stack trace
2021-05-20 17:41:29.985 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/public/**']
2021-05-20 17:41:29.986 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/user/hello'; against '/public/**'
2021-05-20 17:41:29.986 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2021-05-20 17:41:29.986 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/error**']
2021-05-20 17:41:29.986 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/user/hello'; against '/error**'
2021-05-20 17:41:29.986 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2021-05-20 17:41:29.986 DEBUG 24808 --- [nio-8181-exec-3] o.s.security.web.FilterChainProxy : /user/hello?username=user&password=user at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2021-05-20 17:41:29.988 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /user/hello' doesn't match 'DELETE /logout'
2021-05-20 17:41:29.988 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2021-05-20 17:41:29.988 DEBUG 24808 --- [nio-8181-exec-3] o.s.security.web.FilterChainProxy : /user/hello?username=user&password=user at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.s.HttpSessionRequestCache : saved request doesn't match
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.security.web.FilterChainProxy : /user/hello?username=user&password=user at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.security.web.FilterChainProxy : /user/hello?username=user&password=user at position 8 of 12 in additional filter chain; firing Filter: 'TokenAuthenticationFilter'
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/public/**']
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/user/hello'; against '/public/**'
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2021-05-20 17:41:29.989 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.NegatedRequestMatcher : matches = true
2021-05-20 17:41:38.030 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#7fb6b4e0
2021-05-20 17:41:38.030 DEBUG 24808 --- [nio-8181-exec-3] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2021-05-20 17:41:38.030 DEBUG 24808 --- [nio-8181-exec-3] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2021-05-20 17:41:38.033 ERROR 24808 --- [nio-8181-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
com.spring.fieldSecurity.Exceptions.InvalidCredentialsException: Missing authentication token
at com.spring.fieldSecurity.Service.TokenAuthenticationFilter.attemptAuthentication(TokenAuthenticationFilter.java:44) ~[classes/:na]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
.
. // more error trace here
.
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/public/**']
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/error'; against '/public/**'
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/error**']
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/error'; against '/error**'
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : matched
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.security.web.FilterChainProxy : /error?username=user&password=user has an empty filter list
2021-05-20 17:41:38.034 DEBUG 24808 --- [nio-8181-exec-3] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error?username=user&password=user", parameters={masked}
2021-05-20 17:41:38.035 DEBUG 24808 --- [nio-8181-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2021-05-20 17:41:38.035 DEBUG 24808 --- [nio-8181-exec-3] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2021-05-20 17:41:38.724 DEBUG 24808 --- [nio-8181-exec-3] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [application/json] and supported [application/json, application/*+json, application/json, application/*+json]
2021-05-20 17:41:38.724 DEBUG 24808 --- [nio-8181-exec-3] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Thu May 20 17:41:38 IST 2021, status=500, error=Internal Server Error, message=, path=/us (truncated)...]
2021-05-20 17:41:38.726 DEBUG 24808 --- [nio-8181-exec-3] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2021-05-20 17:41:38.727 DEBUG 24808 --- [nio-8181-exec-3] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 500
Spring security has a filter which is called the ExceptionTranslationFilter which translates AccessDeniedException and AuthenticationException into responses. This filter catches these thrown exceptions in the spring security filter chain.
So if you want to return a custom exception, you could instead inherit from one of these classes instead of RuntimeException and add a custom message.
I just want to emphasis and it can never be said too many times:
Providing friendly error messages in production applications when it comes to authentication/authorization is in general bad practice from a security standpoint. These types of messages can benefit malicious actors, when trying out things so that they realize what they have done wrong and guide them in their hacking attempts.
Providing friendly messages in test environments may be okey, but make sure that they are disabled in production. In production all failed authentication attempts a recommendation is to return a 401 with no additional information. And in graphical clients, generalized error messages should be displayed for instance "failed to authenticate" with no given specifics.
Also:
Writing custom security as you have done is also in general bad practice. Spring security is battle tested with 100000 of applications running it in production environments. Writing a custom filter to handle token and passwords, is in general not needed. Spring security already has implemented filters to handle security and authentication using standards like BASIC authentication and TOKEN/JWT. If you implement a non standard login, one bug might expose your application to a huge risk.
Username and password authentication in spring
Oauth2 authentication in spring

Wrong Header of the API versioning of the Post Request does not come to handleNoHandlerFoundException?

I am using Spring Boot v2.1.7 + HATEOAS + Spring Rest + Spring Security. When consumer doesn't pass the correct Custom Header in the request, say passes X-Accept-Version=v5, it gives me below error.
Error:
2020-03-26 15:44:48.201 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : POST "/employee-catalog-api/reference-types", parameters={}
2020-03-26 15:44:48.216 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-03-26 15:44:48.217 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] .m.c.d.m.p.s.SAMLUserIdentityServiceImpl : Trying to get UserId from Security Context
2020-03-26 15:44:48.224 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2020-03-26 15:44:48.234 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found
2020-03-26 15:44:48.234 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#5c85f23b
2020-03-26 15:44:48.234 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-03-26 15:44:48.254 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2020-03-26 15:44:48.254 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND
2020-03-26 15:44:48.258 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2020-03-26 15:44:48.258 DEBUG [employee-service,14c23adbe2664530,14c23adbe2664530,false] 3608 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Code:
#PostMapping(path = "/employee-types", headers = {X-Accept-Version=v1})
public ResponseEntity<Integer> saveEmployeeType(#Valid #RequestBody EmployeeDto employeeDto) {
.....
......
......
return new ResponseEntity<>(HttpStatus.OK);
}
Why its not coming to handleNoHandlerFoundException of the #ControllerAdvice ?
#Override
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
...................
return handleExceptionInternal(ex, error, getHeaders(), HttpStatus.BAD_REQUEST, request);
}
I was able to solve this issue by taking a reference from : How to set default value of exported as false in rest resource spring data rest.
By adding below logic, it works greatly.
#Component
public class SpringRestConfiguration extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
config.setExposeRepositoryMethodsByDefault(false);
}
}

Spring boot rest api not failed in case of invalid Endpoint

I am writing a RESTful web services using spring boot. I am using jwt bearer token for authentication an authorisation.
Below is my RestController
#RestController("api/v1/users")
public class UserController {
#Autowired
UserService userService;
#PostMapping
public User saveUser(#RequestBody User user) {
return userService.saveUser(user);
}
#GetMapping
public List<User> getUsers(#RequestParam(required = false) String pageNumber, String pageSize, String role, String status) {
return userService.findAll(pageNumber, pageSize, role, status);
}
}
When I hit the api with request-url
http://localhost:8080/api/v1/users?pageNumber=0&pageSize=6&role=admin
Its work perfectly
but if I change the url endpoint to some invalid endpoint like
http://localhost:8080/api/v1/hhh?pageNumber=0&pageSize=6&role=admin
It still returning same results as per 1st correct endpoint.
Below are some logs statements from springframework debug logging
Checking match of request : '/api/v1/hhh'; against
'/api/test/secureTest'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
'/api/v1/hhh'; against 'api/authenticate'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
'/api/v1/hhh'; against '/api/v1/users/me'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
'/api/v1/hhh'; against '/api/v1/student'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
'/api/v1/hhh'; against '/api/v1/faculty'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
'/api/v1/hhh'; against '/api/v1/admin'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
'/api/v1/hhh'; against '/api/v1/users'
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.s.w.a.i.FilterSecurityInterceptor : Public object -
authentication not attempted
2019-12-28 19:16:47.601 DEBUG 5591 --- [nio-8080-exec-5]
o.s.security.web.FilterChainProxy :
/api/v1/hhh?pageNumber=0&pageSize=6&role=admin reached end of
additional filter chain; proceeding with original chain
2019-12-28 19:16:47.602 TRACE 5591 --- [nio-8080-exec-5]
o.s.web.servlet.DispatcherServlet : GET
"/api/v1/hhh?pageNumber=0&pageSize=6&role=admin", parameters={masked},
headers={masked} in DispatcherServlet 'dispatcherServlet'
2019-12-28 19:16:47.602 TRACE 5591 --- [nio-8080-exec-5]
o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance
of singleton bean 'api/v1/users'
2019-12-28 19:16:47.602 TRACE 5591 --- [nio-8080-exec-5]
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public
java.util.List
com.asset.app.user.UserController.getUsers(java.lang.String,java.lang.String,java.lang.String,java.lang.String)
2019-12-28 19:16:47.602 TRACE 5591 --- [nio-8080-exec-5]
.w.s.m.m.a.ServletInvocableHandlerMethod : Arguments: [0, 6, admin,
null]
I feel Spring cache the endpoint url and used if in case of no match found
Any Idea how to stop this?
if you read the api documentation for #RestController
You see that the annotation constructor takes in a value that is described as:
The value may indicate a suggestion for a logical component name, to
be turned into a Spring bean in case of an autodetected component.
So it is used to set a name for the Bean that vill be created.
It is not used to set a url-mapping like you have done.
#RestController("api/v1/users")
You need to annotate your class with #RequestMapping and also add mappings to the #PostMapping and #GetMapping.
#RestController
#RequestMapping("/api/v1") // Add request mapping
public class FooBar {
#PostMapping("/users") // Add mapping here
public User bar() {
...
}
#GetMapping("/users") // Add mapping here
public List<User> foo() {
...
}
}

spring boot oauth2 - cannot obtain access token when use Basic Auth

I have problem to get access token from my spring-boot server v.2.0.3.RELEASE. I use spring-security-oauth v.2.3.3.RELEASE.
When I use postman I can get access token and in log I see that BasicAuthenticateFilter is match. But when use angularjs/react, BasicAuthenticateFilter is ommited and I got 401 without any message.
AuthenticationServer
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
static final String CLIENT_ID = "client";
static final String CLIENT_SECRET = "$2a$04$AMTwWHtjscVAHH4gPHx04.82v/W80KVJptp0l/QUWrlkiWU7g7wbe";
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 int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60*60;
static final int REFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
#Autowired
private TokenStore tokenStore;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(CLIENT_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager);
}
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
return propertySourcesPlaceholderConfigurer;
}
}
SecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Resource(name = "userService")
private UserDetailsService userDetailsService;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(encoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated();
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#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(50);
return bean;
}
}
ResourceServer
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/user/register","/user/login").permitAll()
.antMatchers("/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler())
.and().headers().frameOptions().disable();
}
}
angularjs code
angular.module('myApp.view1', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}])
.controller('View1Ctrl', ['$http','$httpParamSerializer', function($http, $httpParamSerializer) {
var ctrl = this;
this.data = {
grant_type:"password",
username: "",
password: "",
client_id: "client"
};
this.encoded = btoa("client:secret");
this.login = function() {
var req = {
method: 'POST',
url: "http://localhost:8080/api/oauth/token",
headers: {
"Authorization": "Basic " + ctrl.encoded,
"Content-type": "application/x-www-form-urlencoded; charset=utf-8"
},
data: $httpParamSerializer(ctrl.data)
}
$http(req).then(function(data){
console.log(data);
$http.defaults.headers.common.Authorization =
'Bearer ' + data.data.access_token;
$cookies.put("access_token", data.data.access_token);
window.location.href="index";
}, function(error) {
console.log(error);
});
}
}]);
This is my log from spring-boot
2018-06-22 19:01:45.134 INFO 23778 --- [nio-8080-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/api] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-06-22 19:01:45.134 INFO 23778 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-06-22 19:01:45.143 INFO 23778 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 9 ms
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/token']
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/oauth/token'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : matched
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'GET /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'POST /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'PUT /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'DELETE /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#64454d87: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/oauth/token'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#64454d87: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2018-06-22 19:01:45.146 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#62efc6af, returned: -1
2018-06-22 19:01:45.153 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
I find out solution for my problem. Main problem was with send OPTIONS request to oauth/token. I change my CorsFilter and SecurityConfig.
SecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
}
SimpleCorsFilter.java
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
After this changes I got access token

Resources