Custom ConstraintValidator is called even if user role not listed in #PreAuthorize - spring

I have a Spring Boot app with POST endpoint, #PreAuthorize role definition and a custom validator for the request body:
#PreAuthorize("hasAnyRole('ROLE_OTHER')")
#RequestMapping(value = "post", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public String post(#RequestBody #Valid DummyDTO dummyDTO) {
...
}
1) When I call the endpoint with wrong role and non-valid request body the custom validation code i.e. ConstraintValidator.isValid() is executed and I got 400 Bad Request.
2) When I call the endpoint with wrong role and valid request body the custom validation code i.e. ConstraintValidator.isValid() is executed and I got 403 Forbidden.
Why is the custom validation code executed before the #PreAuthorize check? I would expect to get 403 in both cases.
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Successfully Authenticated: org.springframework.security.authentication.TestingAuthenticationToken#bbd5887f: Principal: key; Credentials: [PROTECTED]; Authenticated: false; Details: null; Granted Authorities: ROLE_USER
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#41ba74ef, returned: 1
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
DEBUG 12776 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /post reached end of additional filter chain; proceeding with original chain
INFO 12776 --- [nio-8080-exec-3] com.example.DummyValidator : > isValid(): [valid]
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.a.i.a.MethodSecurityInterceptor : Secure object: ReflectiveMethodInvocation: public java.lang.String com.example.MyController.post(com.example.DummyDTO); target is of class [com.example.MyController]; Attributes: [[authorize: 'hasAnyRole('ROLE_OTHER')', filter: 'null', filterTarget: 'null']]
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.TestingAuthenticationProvider
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.a.i.a.MethodSecurityInterceptor : Successfully Authenticated: org.springframework.security.authentication.TestingAuthenticationToken#bbd5887f: Principal: key; Credentials: [PROTECTED]; Authenticated: false; Details: null; Granted Authorities: ROLE_USER
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter#356a19a2, returned: -1
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.access.vote.RoleVoter#7290b3e0, returned: 0
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.access.vote.AuthenticatedVoter#16f3e525, returned: 0
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
...
My DTO:
public class DummyDTO {
#DummyConstraint
private String name;
...
}
constraint:
#Documented
#Retention(RUNTIME)
#Target({TYPE, FIELD, PARAMETER, ANNOTATION_TYPE})
#Constraint(validatedBy = {DummyValidator.class})
public #interface DummyConstraint {
...
}
and validator:
public class DummyValidator implements ConstraintValidator<DummyConstraint, String> {
private static final Logger LOGGER = LoggerFactory.getLogger(DummyValidator.class);
#Override
public void initialize(DummyConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
LOGGER.info("> isValid(): [{}]", value);
return "valid".equalsIgnoreCase(value);
}
}

Related

403 Forbidden when introducing authorization on spring boot rest

I am with my first spring-boot project. I did succesfully configure it to check for authentication; if the user/password was wrong the method was not invoked (status 401 unauthorized), if it was right it succeeded.
Now I have added authorization with JSR250 and I am only getting 403 Access denied.
The WS:
#RestController
#RequestMapping("/password")
public class ServicioPassword {
#GetMapping(path = "ldap")
public ResponseEntity<String> getLdap() {
var authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println("EN LDAP " + authentication.getPrincipal() + " - " + authentication.isAuthenticated());
for (var authority : authentication.getAuthorities()) {
System.out.println("Authority= " + authority);
}
return ResponseEntity.ok("DE LDAP");
}
When invoked, I get this on console:
EN LDAP LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]] - true
Authority= AGNI_OIMIVR
Yet, if I add #RolesAllowed("AGNI_OIMIVR"), when I invoke it I get a 403 Forbidden.
The MethodSecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
public class MethodSecurityConfig
extends GlobalMethodSecurityConfiguration{
}
I have kept the WebSecurityConfig:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Autowired
private Environment environment;
#Bean
BindAuthenticator bindAuthenticator(
final BaseLdapPathContextSource contextSource) {
var bindAuthenticator = new BindAuthenticator(contextSource);
bindAuthenticator.setUserDnPatterns(new String[]{environment.getRequiredProperty("spring.ldap.userdnpattern")});
return bindAuthenticator;
}
#Bean
AuthenticationProvider ldapAuthenticationProvider(
final LdapAuthenticator ldapAuthenticator) {
var ldapAuthenticationProvider = new LdapAuthenticationProvider(ldapAuthenticator);
var ldapUserDetailsMapper = new CustomUserDetailsMapper();
var ldapMemberRoles = environment.getRequiredProperty("spring.ldap.roleattributes");
ldapUserDetailsMapper.setRoleAttributes(ldapMemberRoles.split(","));
ldapUserDetailsMapper.setRolePrefix("");
ldapAuthenticationProvider.setUserDetailsContextMapper(ldapUserDetailsMapper);
return ldapAuthenticationProvider;
}
#Bean
SecurityFilterChain filterChain(
final HttpSecurity http)
throws Exception {
http.csrf().disable()
.cors().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.httpBasic();
return http.build();
}
UPDATE: Adding log after setting logging.level.org.springframework.security=TRACE:
Note that the line: 2022-07-07 13:04:27.464 WARN 81968 --- [nio-8080-exec-2] e.s.d.o.s.ws.CustomUserDetailsMapper : createAuthority agni_oimivr comes from a log from one of my custom classes.
2022-07-07 13:04:27.441 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter : Found username 'ivr_apl_user' in Basic Authorization header
2022-07-07 13:04:27.442 TRACE 81968 --- [nio-8080-exec-2] o.s.s.authentication.ProviderManager : Authenticating request with LdapAuthenticationProvider (1/1)
2022-07-07 13:04:27.444 TRACE 81968 --- [nio-8080-exec-2] o.s.s.l.a.BindAuthenticator : Attempting to bind as cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.444 TRACE 81968 --- [nio-8080-exec-2] s.s.l.DefaultSpringSecurityContextSource : Removing pooling flag for user cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.463 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.l.a.BindAuthenticator : Bound cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.463 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.l.u.LdapUserDetailsMapper : Mapping user details from context with DN cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.464 WARN 81968 --- [nio-8080-exec-2] e.s.d.o.s.ws.CustomUserDetailsMapper : createAuthority agni_oimivr
2022-07-07 13:04:27.464 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.l.a.LdapAuthenticationProvider : Authenticated user
2022-07-07 13:04:27.465 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]]
2022-07-07 13:04:27.465 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking RequestCacheAwareFilter (7/12)
2022-07-07 13:04:27.465 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.s.HttpSessionRequestCache : No saved request
2022-07-07 13:04:27.465 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderAwareRequestFilter (8/12)
2022-07-07 13:04:27.466 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking AnonymousAuthenticationFilter (9/12)
2022-07-07 13:04:27.466 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Did not set SecurityContextHolder since already authenticated UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]]
2022-07-07 13:04:27.466 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking SessionManagementFilter (10/12)
2022-07-07 13:04:27.467 TRACE 81968 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Preparing session with ChangeSessionIdAuthenticationStrategy (1/1)
2022-07-07 13:04:27.467 DEBUG 81968 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : The HttpSession is currently null, and the HttpSessionSecurityContextRepository is prohibited from creating an HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request
2022-07-07 13:04:27.467 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking ExceptionTranslationFilter (11/12)
2022-07-07 13:04:27.467 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking FilterSecurityInterceptor (12/12)
2022-07-07 13:04:27.468 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Did not re-authenticate UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]] before authorizing
2022-07-07 13:04:27.468 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Authorizing filter invocation [GET /password/ldap] with attributes [authenticated]
2022-07-07 13:04:27.469 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Authorized filter invocation [GET /password/ldap] with attributes [authenticated]
2022-07-07 13:04:27.470 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Did not switch RunAs authentication since RunAsManager returned null
2022-07-07 13:04:27.470 DEBUG 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Secured GET /password/ldap
2022-07-07 13:04:27.471 TRACE 81968 --- [nio-8080-exec-2] o.s.s.a.i.a.MethodSecurityInterceptor : Did not re-authenticate UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]] before authorizing
2022-07-07 13:04:27.472 TRACE 81968 --- [nio-8080-exec-2] o.s.s.a.i.a.MethodSecurityInterceptor : Authorizing ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword.getLdap(); target is of class [es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword] with attributes [ROLE_AGNI_OIMIVR]
2022-07-07 13:04:27.475 TRACE 81968 --- [nio-8080-exec-2] o.s.s.a.i.a.MethodSecurityInterceptor : Failed to authorize ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword.getLdap(); target is of class [es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword] with attributes [ROLE_AGNI_OIMIVR] using AffirmativeBased [DecisionVoters=[org.springframework.security.access.annotation.Jsr250Voter#6797e2e2, org.springframework.security.access.vote.RoleVoter#2ab76862, org.springframework.security.access.vote.AuthenticatedVoter#152f6a2e], AllowIfAllAbstainDecisions=false]
2022-07-07 13:04:27.484 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Sending UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]] to access denied handler since access is denied
org.springframework.security.access.AccessDeniedException: Acceso denegado
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.7.1.jar:5.7.1]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:239) ~[spring-security-core-5.7.1.jar:5.7.1]
[...]
2022-07-07 13:04:27.497 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.w.access.AccessDeniedHandlerImpl : Responding with 403 status code
What am I doing wrong?
The Authentication object of your authenticated user is:
UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]]
Note that the GrantedAuthorities is Granted Authorities=[AGNI_OIMIVR], there is no ROLE_ prefix there. When you add #RolesAllowed("AGNI_OIMIVR") to the method, the ROLE_ prefix will be added automatically to the authority that you passed as an argument to the annotation, becoming ROLE_AGNI_OIMIVR.
Spring Security will try to match ROLE_AGNI_OIMIVR that is in the annotation with AGNI_OIMIVR that is in the granted authorities' property, but they do not match.
You have three options:
Change the role in LDAP to have the ROLE_ prefix
Expose a Bean of GrantedAuthorityDefaults removing the rolePrefix, like so:
#Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("");
}
Use #PreAuthorize("hasAuthority('AGNI_OIMIVR')")
Another tip would be to use the new #EnableMethodSecurity(jsr250Enabled = true) which uses the simplified AuthorizationManager API, improve logging, amongst others.

Spring boot OAuth2RestTemplate client setup, authorization_request_not_found error

I try to setup an OAuth2RestTemplate in a spring boot project. I tried to follow a custom setup, but for some reason I always get authorization_request_not_found error when trying to access a secured resource.
My AppConfig:
#EnableOAuth2Client
#SpringBootApplication
public class AppConfig {
public static void main(String[] args) {
SpringApplication.run(AppConfig.class, args);
}
#Bean
RestTemplate restTemplate(OAuth2ProtectedResourceDetails oauth2RemoteResource) {
return new OAuth2RestTemplate(oauth2RemoteResource);
}
}
SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.mvcMatchers("/", "/login/**").permitAll()
.mvcMatchers("/secure").authenticated()
.anyRequest().permitAll()
.and()
.oauth2Login()
.and()
.oauth2Client();
}
}
Controller:
#GetMapping("/secure")
public String secure() {
Object result = restTemplate.getForObject("https://esi.evetech.net/latest/alliances", Object.class);
return "/";
}
application.yml:
security:
oauth2:
client:
id: eve
client-id: clientId
client-secret: secret
grant-type: authorization_code
user-authorization-uri: https://login.eveonline.com/v2/oauth/authorize
access-token-uri: https://login.eveonline.com/v2/oauth/token
pre-established-redirect-uri: http://localhost:8080/login/oauth2/code/eve
use-current-uri: false
scope:
- esi-characters.read_blueprints.v1
resource:
user-info-uri: https://login.eveonline.com/oauth/verify
spring:
security:
oauth2:
client:
registration:
eve:
authorization-grant-type: authorization_code
client-id: clientId
client-secret: secret
redirect-uri: http://localhost:8080/login/oauth2/code/eve
client-authentication-method: basic
scope:
- esi-characters.read_blueprints.v1
provider:
eve:
authorization-uri: https://login.eveonline.com/v2/oauth/authorize
token-uri: https://login.eveonline.com/v2/oauth/token
user-info-uri: https://login.eveonline.com/oauth/verify
user-name-attribute: CharacterID
Now I find this also interesting since I am not sure why I have to declare these properties twice.
I mean the OAuth2RestTemplate takes an AuthorizationCodeResourceDetails instance in the constructor in AppConfig which reads the security.oatuh2.client properties, while the DefaultOAuth2ClientContext inside the OAuth2RestTemplate constructor reads the other, I just don't understand why is it like that? Is there a simple setup?
Anyway going back to the original problem, when I access /secure it redirects me to the login page, where I login successfully which then redirects me back to the /secure page, so far so good.
Just before calling the restTemplate, I have this in the log:
2020-05-06 22:55:31.528 DEBUG 29177 --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /secure; Attributes: [authenticated]
2020-05-06 22:55:31.528 DEBUG 29177 --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken#3bb07c9: Principal: Name: [<ID>], Granted Authorities: [[ROLE_USER, SCOPE_esi-characters.read_blueprints.v1]], User Attributes: [{CharacterID=<ID>, CharacterName=<Name>, ExpiresOn=2020-05-06T22:15:31, Scopes=esi-characters.read_blueprints.v1, TokenType=Character, CharacterOwnerHash=<Hash>, IntellectualProperty=EVE}]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 472A39D41FE34AC90781A80E39E4A52D; Granted Authorities: ROLE_USER, SCOPE_esi-characters.read_blueprints.v1
2020-05-06 22:55:31.529 DEBUG 29177 --- [nio-8080-exec-4] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#47a65378, returned: 1
But after the restTemplate is called:
2020-05-06 23:00:31.482 DEBUG 29177 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Failed to complete request: org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: A redirect is required to get the users approval
2020-05-06 23:00:31.483 DEBUG 29177 --- [nio-8080-exec-4] 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#205366de
2020-05-06 23:00:31.483 DEBUG 29177 --- [nio-8080-exec-4] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-05-06 23:00:31.484 DEBUG 29177 --- [nio-8080-exec-4] o.s.s.web.DefaultRedirectStrategy : Redirecting to 'https://login.eveonline.com/v2/oauth/authorize?client_id=<clientId>&redirect_uri=http://localhost:8080/login/oauth2/code/eve&response_type=code&scope=esi-characters.read_blueprints.v1&state=<state>'
As you can see it takes me back to the login page, so I login back again and this time I get the error: [authorization_request_not_found]
log:
2020-05-06 23:02:27.285 DEBUG 29177 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login/oauth2/code/eve?code=<code>&state=<state> at position 8 of 17 in additional filter chain; firing Filter: 'OAuth2LoginAuthenticationFilter'
2020-05-06 23:02:27.285 DEBUG 29177 --- [nio-8080-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/eve'; against '/login/oauth2/code/*'
2020-05-06 23:02:27.285 DEBUG 29177 --- [nio-8080-exec-6] .s.o.c.w.OAuth2LoginAuthenticationFilter : Request is to process authentication
2020-05-06 23:02:27.287 DEBUG 29177 --- [nio-8080-exec-6] .s.o.c.w.OAuth2LoginAuthenticationFilter : Authentication request failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: [authorization_request_not_found]
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [authorization_request_not_found]
at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:163) ~[spring-security-oauth2-client-5.2.2.RELEASE.jar:5.2.2.RELEASE]
I am lost at this point, not sure why I am getting this.
I also uploaded the project to github in case it's easier to check out what's wrong with it.
Thanks

Spring Security loadUserByUsername() method is not called and authentication is sucess for incorrect password

I am implementing HTTP Basic auth scheme for my REST services using custom DAO UserDetailsService. However this overridden method is not getting called and authentication succeeds even if i send incorrect password to the API (through POSTMAN). Any inputs will be helpful.
My Application class
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
#EnableNeo4jRepositories("galaxy.spring.data.neo4j.repositories")
#EnableWebSecurity
public class SampleMovieApplication extends WebSecurityConfigurerAdapter {
public static String REALM = "REALM";
#Autowired
private static UserService userService;
public static void main(String[] args) {
ConfigurableApplicationContext configContext =
SpringApplication.run(SampleMovieApplication.class, args);
configContext.getBean(RepoInit.class).fillWithTestdata();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().and()
.authorizeRequests().anyRequest().fullyAuthenticated()
.antMatchers("/galaxy/appuser/**").hasAnyRole("ADMIN","USER")
.antMatchers("/galaxy/appadmin/**").hasRole("ADMIN")
.and().csrf().disable()
.httpBasic().realmName("REALM").authenticationEntryPoint(getBasicAuthEntryPoint());
}
#Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
return new CustomBasicAuthenticationEntryPoint();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("Calling authenticator");
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
#Bean
public UserDetailsService userDetailsService() {
System.out.println(userService == null ? " userservice is null " : "userservice is not null");
return new UserDetailsServiceImp(userService);
};
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
};
}
My custom UserDetailsService class
public class UserDetailsServiceImp implements UserDetailsService {
private UserService userService;
public UserDetailsServiceImp(UserService userService) {
this.userService = userService;
}
/*#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
DomainUser user = findUserbyUername(username);
UserBuilder builder = null;
if (user != null) {
builder = org.springframework.security.core.userdetails.User.withUsername(username);
builder.password(new BCryptPasswordEncoder().encode(user.getPassword()));
builder.roles("ROLE_" + user.getBelongsTo().get(0).getDomainUserGroup().getAuthorityname());
} else {
throw new UsernameNotFoundException("User not found.");
}
return builder.build();
} */
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("called load method");
DomainUser user = null;
Set<GrantedAuthority> grantedAuthorities = null;
try
{
user = findUserbyUername(username);
if(user == null)
throw new UsernameNotFoundException("User " + username + " not available");
grantedAuthorities = new HashSet<>();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" +
user.getBelongsTo().get(0).getDomainUserGroup().getAuthorityname()));
}
catch(Exception exp) {
exp.printStackTrace();
}
System.out.println("Returning new userdetails");
return new
org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), grantedAuthorities);
}
private DomainUser findUserbyUername(String username) {
return userService.findByName(username);
}
}
The SPRING SECURITY DEBUG LOG after posting a request
2020-05-03 11:06:12.884 INFO 19868 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-05-03 11:06:12.884 INFO 19868 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-05-03 11:06:12.906 INFO 19868 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 22 ms
2020-05-03 11:06:12.930 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-05-03 11:06:12.930 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-05-03 11:06:12.930 DEBUG 19868 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#452579c9: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#452579c9: Principal: org.springframework.security.core.userdetails.User#586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; 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_ADMIN'
2020-05-03 11:06:12.930 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-05-03 11:06:12.930 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 4 of 12 in additional filter chain; firing Filter: 'CorsFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'POST /galaxy/appadmin/usergroup' doesn't match 'GET /logout'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/galaxy/appadmin/usergroup'; against '/logout'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'POST /galaxy/appadmin/usergroup' doesn't match 'PUT /logout'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'POST /galaxy/appadmin/usergroup' doesn't match 'DELETE /logout'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 6 of 12 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter : Basic Authentication Authorization header found for user 'admin'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.s.HttpSessionRequestCache : saved request doesn't match
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#452579c9: Principal: org.springframework.security.core.userdetails.User#586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; 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_ADMIN'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /galaxy/appadmin/usergroup; Attributes: [fullyAuthenticated]
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#452579c9: Principal: org.springframework.security.core.userdetails.User#586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; 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_ADMIN
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#6a8bc4e6, returned: 1
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
2020-05-03 11:06:12.945 DEBUG 19868 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /galaxy/appadmin/usergroup reached end of additional filter chain; proceeding with original chain
DomainUserGroup request is testgroup3
2020-05-03 11:06:13.126 DEBUG 19868 --- [nio-8080-exec-1] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2020-05-03 11:06:13.126 DEBUG 19868 --- [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#4aaae30c
2020-05-03 11:06:13.126 DEBUG 19868 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Add this in SampleMovieApplication class...
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
Remove this:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("Calling authenticator");
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
Solved the problem. It is very funny that we have to invalidate the session in the controller (like we are logging out) and clear the secuirty context programatically. Now it is consistent and authenticates every request.
#PostMapping("/galaxy/appadmin/usergroup")
public ResponseEntity<Object> createDomainUserGroup(#RequestBody
DomainUserGroup domainusergrp,HttpServletRequest request, HttpServletResponse response) {
System.out.println(" DomainUserGroup request is "+ domainusergrp.getName());
DomainUserGroup domainc = userGroupService.save(domainusergrp);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").
buildAndExpand(domainc.getId()).toUri();
SecurityContextHolder.clearContext();
HttpSession session= request.getSession(false);
if(session != null) {
session.invalidate();
}
return ResponseEntity.created(location).build();
}

Restricted Access Using Scope in JWT and Spring

Well, i have a JWT with scope definied in a claim called scp, see the peace of jwt:
"scp": "xpto_role user_impersonation",
So, in my Spring application i have the following Configuration:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/urlabc/**").hasAuthority("abc")
.antMatchers("/urlabc/**").authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("xpto");
}
}
ANd in my restController:
#RestController
public class TestResourceOne {
#RequestMapping(value = "/endpoint001")
public Double endpoint001(#RequestParam("value") Double value) {
return Math.sqrt(value);
}
}
Look, my scope passed by JWT is "xpto_role" in claim scp. In my SpringApp i want to force a Access Denied so i putted a "abc" role in "hasAuthority" method, but user is allowed to access my endpoint anyway.
The configuration is correct ?
Edit 1:
After remove the "authenticated()" line and putted the correct role i got Access Denied yet, see the error:
2018-07-20 16:57:36.732 DEBUG 6828 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /calcsqrt?value=10.0 at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2018-07-20 16:57:36.732 DEBUG 6828 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.oauth2.provider.OAuth2Authentication#8f785707: Principal: null; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>; Not granted any authorities'
2018-07-20 16:57:36.732 DEBUG 6828 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /calcsqrt?value=10.0 at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2018-07-20 16:57:36.732 DEBUG 6828 --- [nio-8080-exec-1] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy#63dfada0
2018-07-20 16:57:36.732 DEBUG 6828 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /calcsqrt?value=10.0 at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2018-07-20 16:57:36.733 DEBUG 6828 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /calcsqrt?value=10.0 at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2018-07-20 16:57:36.733 DEBUG 6828 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/calcsqrt'; against '/calcsqrt/**'
2018-07-20 16:57:36.733 DEBUG 6828 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /calcsqrt?value=10.0; Attributes: [#oauth2.throwOnError(hasRole('ROLE_EXEC_CALCSQRT'))]
2018-07-20 16:57:36.733 DEBUG 6828 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.oauth2.provider.OAuth2Authentication#8f785707: Principal: null; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>; Not granted any authorities
2018-07-20 16:57:36.733 DEBUG 6828 --- [nio-8080-exec-1] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#7475b738, returned: -1
2018-07-20 16:57:36.734 DEBUG 6828 --- [nio-8080-exec-1] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.2.7.RELEASE.jar:4.2.7.RELEASE]

Spring Cloud Contract: Can the verifier Test not be run with SpringRunner.class ?

Hello I set up a basic Api Test like below:
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
#ActiveProfiles("test")
public abstract class BaseMockMvcSpec {
public static Logger log = LoggerFactory.getLogger(BaseMockMvcSpec.class);
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mvc;
#Autowired
FilterChainProxy springSecurityFilterChain;
#Autowired
UserRepository users;
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
CustomClientDetailsService clientDetialsService;
#Mock SecurityContext mockSecurityContext;
#Before
public void setUp() {
RestAssuredMockMvc.standaloneSetup(new AccountDetailsController());
mvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurity(springSecurityFilterChain))
.build();
BaseClientDetails testClient = new ClientBuilder("testclient")
.secret("testclientsecret")
.authorizedGrantTypes("password")
.scopes("read", "wirte")
.autoApprove(true)
.build();
clientDetialsService.addClient(testClient);
User user = createDefaultUser("testuser", passwordEncoder.encode("testpassword"), "max", "Mustermann", new Email("test#lokata.de"));
users.deleteAll();
users.save(user);
log.info("setup BaseMockMvcSpec");
}
public String oauth(){
String token = "notValidToken";
try {
token = validAccessToken();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "Bearer " + token;
}
private String validAccessToken() throws Exception {
String username = "testuser";
String password = "testpassword";
MockHttpServletResponse response = mvc
.perform(post("/oauth/token")
.header("Authorization", "Basic "
+ new String(Base64Utils.encode(("testclient:testclientsecret")
.getBytes())))
.param("username", username)
.param("password", password)
.param("grant_type", "password"))
.andDo(print())
.andReturn().getResponse();
return new ObjectMapper()
.readValue(response.getContentAsByteArray(), OAuthToken.class)
.accessToken;
}
#JsonIgnoreProperties(ignoreUnknown = true)
private static class OAuthToken {
#JsonProperty("access_token")
public String accessToken;
}
}
I get the following output of the Test run:
2017-06-27 01:36:23.379 INFO 47446 --- [ Test worker] .b.t.c.SpringBootTestContextBootstrapper : Neither #ContextConfiguration nor #ContextHierarchy found for test class [de.example.microservice.authservice.verifier.tests.OauthserviceTest], using SpringBootContextLoader
2017-06-27 01:36:23.379 INFO 47446 --- [ Test worker] o.s.t.c.support.AbstractContextLoader : Could not detect default resource locations for test class [de.example.microservice.authservice.verifier.tests.OauthserviceTest]: no resource found for suffixes {-context.xml, Context.groovy}.
2017-06-27 01:36:23.379 INFO 47446 --- [ Test worker] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [de.example.microservice.authservice.verifier.tests.OauthserviceTest]: OauthserviceTest does not declare any static, non-private, non-final, nested classes annotated with #Configuration.
2017-06-27 01:36:23.383 INFO 47446 --- [ Test worker] .b.t.c.SpringBootTestContextBootstrapper : Found #SpringBootConfiguration de.example.microservice.authservice.AuthserverApplication for test class de.example.microservice.authservice.verifier.tests.OauthserviceTest
2017-06-27 01:36:23.385 INFO 47446 --- [ Test worker] .b.t.c.SpringBootTestContextBootstrapper : Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener]
2017-06-27 01:36:23.386 INFO 47446 --- [ Test worker] .b.t.c.SpringBootTestContextBootstrapper : Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener#2efec58d, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener#65dbe1b, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener#4d31ce57, org.springframework.test.context.support.DirtiesContextTestExecutionListener#750239e7, org.springframework.test.context.transaction.TransactionalTestExecutionListener#2d885867, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener#464e86ab, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener#54eab43, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener#6167770c, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener#ec35027, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener#3c0ae48a, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener#4cee44fb, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener#166b957d, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener#2bdadff]
2017-06-27 01:36:23.459 INFO 47446 --- [ Test worker] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring FrameworkServlet ''
2017-06-27 01:36:23.459 INFO 47446 --- [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : FrameworkServlet '': initialization started
2017-06-27 01:36:23.462 INFO 47446 --- [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : FrameworkServlet '': initialization completed in 3 ms
2017-06-27 01:36:23.540 INFO 47446 --- [ Test worker] d.l.m.authservice.BaseMockMvcSpec : setup BaseMockMvcSpec
2017-06-27 01:36:23.564 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/token']
2017-06-27 01:36:23.564 DEBUG 47446 --- [ Test worker] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/oauth/token'
2017-06-27 01:36:23.564 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : matched
2017-06-27 01:36:23.564 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-06-27 01:36:23.564 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] 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#79e774c0
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'POST /oauth/token' doesn't match 'GET /logout
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/logout'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'POST /oauth/token' doesn't match 'PUT /logout
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'POST /oauth/token' doesn't match 'DELETE /logout
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 5 of 12 in additional filter chain; firing Filter: 'ClientCredentialsTokenEndpointFilter'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 6 of 12 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.w.a.www.BasicAuthenticationFilter : Basic Authentication Authorization header found for user 'testclient'
2017-06-27 01:36:23.565 DEBUG 47446 --- [ Test worker] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.s.w.a.www.BasicAuthenticationFilter : Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#7e2b6867: Principal: org.springframework.security.core.userdetails.User#81d402dd: Username: testclient; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Not granted any authorities
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#7e2b6867: Principal: org.springframework.security.core.userdetails.User#81d402dd: Username: testclient; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Not granted any authorities'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy#b7217c5
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/oauth/token'
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
2017-06-27 01:36:23.567 DEBUG 47446 --- [ Test worker] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#7e2b6867: Principal: org.springframework.security.core.userdetails.User#81d402dd: Username: testclient; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Not granted any authorities
2017-06-27 01:36:23.568 DEBUG 47446 --- [ Test worker] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#6b9626fc, returned: 1
2017-06-27 01:36:23.568 DEBUG 47446 --- [ Test worker] o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
2017-06-27 01:36:23.568 DEBUG 47446 --- [ Test worker] o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
2017-06-27 01:36:23.568 DEBUG 47446 --- [ Test worker] o.s.security.web.FilterChainProxy : /oauth/token reached end of additional filter chain; proceeding with original chain
2017-06-27 01:36:23.569 DEBUG 47446 --- [ Test worker] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /oauth/token
2017-06-27 01:36:23.569 DEBUG 47446 --- [ Test worker] .s.o.p.e.FrameworkEndpointHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException]
2017-06-27 01:36:23.572 DEBUG 47446 --- [ Test worker] .o.p.p.ResourceOwnerPasswordTokenGranter : Getting access token for: testclient
2017-06-27 01:36:23.572 DEBUG 47446 --- [ Test worker] o.s.s.authentication.ProviderManager : Authentication attempt using de.example.microservice.authservice.authentication.behavior.CustomAuthenticationProvider
2017-06-27 01:36:23.656 DEBUG 47446 --- [ Test worker] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2017-06-27 01:36:23.656 DEBUG 47446 --- [ Test worker] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
MockHttpServletRequest:
HTTP Method = POST
Request URI = /oauth/token
Parameters = {username=[testuser], password=[testpassword], grant_type=[password]}
Headers = {Authorization=[Basic dGVzdGNsaWVudDp0ZXN0Y2xpZW50c2VjcmV0]}
Handler:
Type = org.springframework.security.oauth2.provider.endpoint.TokenEndpoint
Method = public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY], Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body = {"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOiJmZjgwODA4MTVjZTZjMzBkMDE1Y2U2YzM2MmYzMDAyNyIsInVzZXJfbmFtZSI6InRlc3R1c2VyIiwic2NvcGUiOlsicmVhZCIsIndpcnRlIl0sIm9yZ2FuaXNhdGlvbiI6ImRlZmF1bHQiLCJleHAiOjE0OTg1NjMzODMsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiJlZGRmZWUyZS01NTU2LTQ1YWItOTIwMC02NThiM2FkNmRiNWYiLCJjbGllbnRfaWQiOiJ0ZXN0Y2xpZW50In0.bL9mLo1Ao6oUBA3BxrIIEWTEXVlTml5GqeoeAKqA_pXDFBn-gIRafRH8ji3BceTg-cjih_-cYYAbRiVmjsCAUd0nE-chwIwhwPp2WSAfgz9OHd531VsDOX7l8-vkR_BUKY5X02pIf2W9ZlsqCZ-isarRzWI_AQpNgqwoIDcICDeuB1lNWqkwtwmI_f0cF3u0J2FuQBvye3Sj4xXmrQU0awCj0F891v6bPqkM0Wc5G6i8Mm-n-OnRbMqcckfxAsSqtDEYrDe3T6otFfREZ6AYTefMzQWYbYXDK0tCkohH46hNmKlbrXNWUrnwYLDeCZyOGm8bCrOihDzjYJgw5RshKQ","token_type":"bearer","expires_in":43199,"scope":"read wirte","accountId":"ff8080815ce6c30d015ce6c362f30027","organisation":"default","jti":"eddfee2e-5556-45ab-9200-658b3ad6db5f"}
Forwarded URL = null
Redirected URL = null
Cookies = []
2017-06-27 01:36:23.684 INFO 47446 --- [ Test worker] ilder$StaticRequestMappingHandlerMapping : Mapped "{[/api/me],methods=[GET],produces=[application/json;charset=UTF-8]}" onto public java.security.Principal de.example.microservice.authservice.rest.behavior.AccountDetailsController.user(java.security.Principal)
2017-06-27 01:36:23.692 INFO 47446 --- [ Test worker] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for #ControllerAdvice: org.springframework.test.web.servlet.setup.StubWebApplicationContext#734a6c74
2017-06-27 01:36:23.696 INFO 47446 --- [ Test worker] o.s.mock.web.MockServletContext : Initializing Spring FrameworkServlet ''
2017-06-27 01:36:23.696 INFO 47446 --- [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : FrameworkServlet '': initialization started
2017-06-27 01:36:23.696 INFO 47446 --- [ Test worker] o.s.t.web.servlet.TestDispatcherServlet : FrameworkServlet '': initialization completed in 0 ms
The TestException is
java.lang.IllegalArgumentException: json string can not be null or empty
at com.jayway.jsonpath.internal.Utils.notEmpty(Utils.java:386)
at com.jayway.jsonpath.internal.JsonContext.parse(JsonContext.java:81)
at com.jayway.jsonpath.JsonPath.parse(JsonPath.java:596)
at de.example.microservice.authservice.verifier.tests.OauthserviceTest.validate_shouldReturnAccountDetails(OauthserviceTest.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method
I guess the autogenerated Test is not executed but didn't know how to debug them. The get Oauth2 token works perfect and also the execution of the oath() method in the verifier Class.
I ended up with the following test setup:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#ContextConfiguration
#WebAppConfiguration
#ActiveProfiles("test")
public abstract class UserDetailsControllerTestBase {
public static Logger log = LoggerFactory.getLogger(UserDetailsControllerTestBase.class);
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mvc;
#Autowired
FilterChainProxy springSecurityFilterChain;
#Mock SecurityContext mockSecurityContext;
#Before
public void setUp() {
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
//RestAssured.baseURI="http://localhost";
//RestAssured.port = port;
mvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.defaultRequest(get("/api/me").with(user("user").roles("USER")))
.apply(springSecurity(springSecurityFilterChain))
.build();
RestAssuredMockMvc.mockMvc(mvc);
}
public String oauth(){
String token = "notValidToken";
try {
token = validAccessToken();
} catch (Exception e) {
e.printStackTrace();
}
return "Bearer " + token;
}
public void assertIsNull(Object value){
assertThat(value, is(nullValue()));
}
private String validAccessToken() throws Exception {
String username = "user";
String password = "password";
MockHttpServletResponse response = mvc
.perform(post("/oauth/token")
.header("Authorization", "Basic "
+ new String(Base64Utils.encode(("client:clientsecret")
.getBytes())))
.param("username", username)
.param("password", password)
.param("grant_type", "password"))
.andDo(print())
.andReturn().getResponse();
return new ObjectMapper()
.readValue(response.getContentAsByteArray(), OAuthToken.class)
.accessToken;
}
#JsonIgnoreProperties(ignoreUnknown = true)
private static class OAuthToken {
#JsonProperty("access_token")
public String accessToken;
}
}
Check out the example Solution Repository for more details
Yes. Just run the plugin in EXPLICIT mode. That way you can configure restassured to shoot any URL and you'll be able to setup your base class however you want to. Example https://cloud.spring.io/spring-cloud-contract/reference/html/project-features.html#features-context-paths

Resources