Search code examples
springspring-bootspring-junit

Client authorization not working for unit tests


Okay, so first thing that's important to know here is that I can use the actual web client as intended. I am able to register a user and login with it.

However, as I try to implement some unit tests, things are not working for me. This is how I am creating a user in my unit test:

@Autowired
private TestRestTemplate template;

@Value("${security.jwt.client-id}")
private String clientId;

@Value("${security.jwt.client-secret}")
private String clientSecret;

private static String USERS_ENDPOINT = "http://localhost:8081/users/";

public AppUser registerUser(String username, String password) {

    AppUser appUser = new AppUser();
    appUser.setUsername(username);
    appUser.setPassword(password);

    ResponseEntity<AppUser> appUserResponseEntity = template.withBasicAuth(clientId, clientSecret)
            .postForEntity(USERS_ENDPOINT, appUser, AppUser.class);

    AppUser registeredAppUser = appUserResponseEntity.getBody();

    assertNotNull("Trying to register new user but the user ID is null which indicates it didn't work.",
            registeredAppUser.getId());

    return registeredAppUser;
}

The problem is that the status I read in appUserResponseEntity is HTTP 401 and the returned AppUser is invalid (the user is not created in the database).

I am also getting aInsufficientScopeException:

Caused by: org.springframework.security.oauth2.common.exceptions.InsufficientScopeException: Insufficient scope for this resource
    at org.springframework.security.oauth2.provider.expression.OAuth2SecurityExpressionMethods.throwOnError(OAuth2SecurityExpressionMethods.java:71) ~[spring-security-oauth2-2.2.0.RELEASE.jar:na]
    ... 82 common frames omitted

Below you can find my AuthorizationServerConfigurerAdapter for the OAuth2 configuration.

@Configuration
@EnableAuthorizationServer
@EnableResourceServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    @Configuration
    @EnableResourceServer
    public class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .requestMatchers().antMatchers("/**")
                .and()
                .authorizeRequests().anyRequest().access("#oauth2.hasScope('write')");
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(resourceIds);
        }

    }

    @Value("${security.jwt.client-id}")
    private String clientId;

    @Value("${security.jwt.client-secret}")
    private String clientSecret;

    @Value("${security.jwt.grant-type}")
    private String grantType;

    @Value("${security.jwt.scope-read}")
    private String scopeRead;

    @Value("${security.jwt.scope-write}")
    private String scopeWrite;

    @Value("${security.jwt.resource-ids}")
    private String resourceIds;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
        configurer
                .inMemory()
                .withClient(clientId)
                .secret(clientSecret)
                .authorizedGrantTypes(grantType)
                .scopes(scopeRead, scopeWrite)
                .resourceIds(resourceIds);
    }


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        enhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
        endpoints.tokenStore(tokenStore)
                .accessTokenConverter(accessTokenConverter)
                .tokenEnhancer(enhancerChain)
                .authenticationManager(authenticationManager);
    }



}

I have no idea why this is not working. Does anybody have an idea what the problem might be?


What I think is weird is that it fails while asking for write access for an anonymous user. WebSecurity should actually ignore the /users endpoint:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/pub/**", "/users");
}

So I'm not quite sure why the security filter chain is actually being active here.

enter image description here


Update:

What I've tried now is I started the server on 8080 and used TestRestTemplate template during the same debug session and tried to POST an AppUser to 8080 and 8081 - take a look:

enter image description here

enter image description here

As you can see the very same call works on 8080 (an actual server instance running) but not on 8081 - the server instance started for unit tests.

Obviously there's a problem with my configuration or something but I can't pin it down ..


Solution

  • I have no more words for this one:

    http://localhost:8081/users