web-dev-qa-db-fra.com

Comment tester la sécurité du serveur de ressources spring-security-oauth2?

Suite à la publication de Spring Security 4 et à son _ { amélioration de la prise en charge des tests } _, je souhaite mettre à jour mes tests actuels du serveur de ressources Spring Security oauth2.

Actuellement, j'ai une classe d'assistance qui configure un OAuth2RestTemplate en utilisant ResourceOwnerPasswordResourceDetails avec un test ClientId se connectant à un AccessTokenUri réel pour demander un jeton valide pour mes tests. Ce resttemplate est ensuite utilisé pour faire des demandes dans mon @WebIntegrationTests.

J'aimerais abandonner la dépendance vis-à-vis du AuthorizationServer lui-même et l'utilisation de données d'identification utilisateur valides (si elles sont limitées) dans mes tests, en tirant parti du nouveau support de test fourni dans Spring Security 4.

Jusqu'à présent, toutes mes tentatives d'utilisation de @WithMockUser, @WithSecurityContext, SecurityMockMvcConfigurers.springSecurity() & SecurityMockMvcRequestPostProcessors.* n'ont pas réussi à passer des appels authentifiés via MockMvc, et je ne trouve aucun exemple de ce type dans les projets de Spring.

Quelqu'un peut-il m'aider à tester mon serveur de ressources oauth2 avec des identifiants fictifs, tout en testant les restrictions de sécurité imposées?

** EDIT ** Exemple de code disponible ici: https://github.com/timtebeek/resource-server-testing Pour chacune des classes de test I comprendre pourquoi cela ne fonctionnera pas comme cela, mais je cherche des moyens qui me permettraient de tester facilement la configuration de la sécurité.

Je pense maintenant créer un OAuthServer très permissif sous src/test/Java, ce qui pourrait aider un peu. Quelqu'un a-t-il d'autres suggestions?

39
Tim

Pour tester efficacement la sécurité du serveur de ressources, avec MockMvc et une RestTemplate, il est utile de configurer une AuthorizationServer sous src/test/Java:

AuthorizationServer

@Configuration
@EnableAuthorizationServer
@SuppressWarnings("static-method")
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() throws Exception {
        JwtAccessTokenConverter jwt = new JwtAccessTokenConverter();
        jwt.setSigningKey(SecurityConfig.key("rsa"));
        jwt.setVerifierKey(SecurityConfig.key("rsa.pub"));
        jwt.afterPropertiesSet();
        return jwt;
    }

    @Autowired
    private AuthenticationManager   authenticationManager;

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
        .authenticationManager(authenticationManager)
        .accessTokenConverter(accessTokenConverter());
    }

    @Override
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
        .withClient("myclientwith")
        .authorizedGrantTypes("password")
        .authorities("myauthorities")
        .resourceIds("myresource")
        .scopes("myscope")

        .and()
        .withClient("myclientwithout")
        .authorizedGrantTypes("password")
        .authorities("myauthorities")
        .resourceIds("myresource")
        .scopes(UUID.randomUUID().toString());
    }
}

Test d'intégration
Pour les tests d’intégration, on peut alors simplement utiliser la règle et les annotations de support de test OAuth2 intégrées:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApp.class)
@WebIntegrationTest(randomPort = true)
@OAuth2ContextConfiguration(MyDetails.class)
public class MyControllerIT implements RestTemplateHolder {
    @Value("http://localhost:${local.server.port}")
    @Getter
    String                      Host;

    @Getter
    @Setter
    RestOperations              restTemplate    = new TestRestTemplate();

    @Rule
    public OAuth2ContextSetup   context         = OAuth2ContextSetup.standard(this);

    @Test
    public void testHelloOAuth2WithRole() {
        ResponseEntity<String> entity = getRestTemplate().getForEntity(Host + "/hello", String.class);
        assertTrue(entity.getStatusCode().is2xxSuccessful());
    }
}

class MyDetails extends ResourceOwnerPasswordResourceDetails {
    public MyDetails(final Object obj) {
        MyControllerIT it = (MyControllerIT) obj;
        setAccessTokenUri(it.getHost() + "/oauth/token");
        setClientId("myclientwith");
        setUsername("user");
        setPassword("password");
    }
}

Test MockMvc
Tester avec MockMvc est également possible, mais nécessite une petite classe d'assistance pour obtenir une RequestPostProcessor qui définit l'en-tête Authorization: Bearer <token> sur les demandes:

@Component
public class OAuthHelper {
    // For use with MockMvc
    public RequestPostProcessor bearerToken(final String clientid) {
        return mockRequest -> {
            OAuth2AccessToken token = createAccessToken(clientid);
            mockRequest.addHeader("Authorization", "Bearer " + token.getValue());
            return mockRequest;
        };
    }

    @Autowired
    ClientDetailsService                clientDetailsService;
    @Autowired
    AuthorizationServerTokenServices    tokenservice;

    OAuth2AccessToken createAccessToken(final String clientId) {
        // Look up authorities, resourceIds and scopes based on clientId
        ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
        Collection<GrantedAuthority> authorities = client.getAuthorities();
        Set<String> resourceIds = client.getResourceIds();
        Set<String> scopes = client.getScope();

        // Default values for other parameters
        Map<String, String> requestParameters = Collections.emptyMap();
        boolean approved = true;
        String redirectUrl = null;
        Set<String> responseTypes = Collections.emptySet();
        Map<String, Serializable> extensionProperties = Collections.emptyMap();

        // Create request
        OAuth2Request oAuth2Request = new OAuth2Request(requestParameters, clientId, authorities, approved, scopes,
                resourceIds, redirectUrl, responseTypes, extensionProperties);

        // Create OAuth2AccessToken
        User userPrincipal = new User("user", "", true, true, true, true, authorities);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities);
        OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
        return tokenservice.createAccessToken(auth);
    }
}

Vos tests MockMvc doivent ensuite obtenir une RequestPostProcessor de la classe OauthHelper et la réussir lors de la création de requêtes:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApp.class)
@WebAppConfiguration
public class MyControllerTest {
    @Autowired
    private WebApplicationContext   webapp;

    private MockMvc                 mvc;

    @Before
    public void before() {
        mvc = MockMvcBuilders.webAppContextSetup(webapp)
                .apply(springSecurity())
                .alwaysDo(print())
                .build();
    }

    @Autowired
    private OAuthHelper helper;

    @Test
    public void testHelloWithRole() throws Exception {
        RequestPostProcessor bearerToken = helper.bearerToken("myclientwith");
        mvc.perform(get("/hello").with(bearerToken)).andExpect(status().isOk());
    }

    @Test
    public void testHelloWithoutRole() throws Exception {
        RequestPostProcessor bearerToken = helper.bearerToken("myclientwithout");
        mvc.perform(get("/hello").with(bearerToken)).andExpect(status().isForbidden());
    }
}

Un exemple de projet complet est disponible sur GitHub:
https://github.com/timtebeek/resource-server-testing

34
Tim

J'ai trouvé un moyen beaucoup plus facile de faire ceci en suivant les instructions que je lis ici: http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#test-method-withsecuritycontext . Cette solution est spécifique au test de @PreAuthorize avec #oauth2.hasScope, mais je suis sûr qu’elle pourrait également être adaptée à d’autres situations.

Je crée une annotation qui peut être appliquée à @Tests:

WithMockOAuth2Scope

import org.springframework.security.test.context.support.WithSecurityContext;

import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockOAuth2ScopeSecurityContextFactory.class)
public @interface WithMockOAuth2Scope {

    String scope() default "";
}

WithMockOAuth2ScopeSecurityContextFactory

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.test.context.support.WithSecurityContextFactory;

import Java.util.HashSet;
import Java.util.Set;

public class WithMockOAuth2ScopeSecurityContextFactory implements WithSecurityContextFactory<WithMockOAuth2Scope> {

    @Override
    public SecurityContext createSecurityContext(WithMockOAuth2Scope mockOAuth2Scope) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();

        Set<String> scope = new HashSet<>();
        scope.add(mockOAuth2Scope.scope());

        OAuth2Request request = new OAuth2Request(null, null, null, true, scope, null, null, null, null);

        Authentication auth = new OAuth2Authentication(request, null);

        context.setAuthentication(auth);

        return context;
    }
}

Exemple de test utilisant MockMvc:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class LoadScheduleControllerTest {

    private MockMvc mockMvc;

    @Autowired
    LoadScheduleController loadScheduleController;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(loadScheduleController)
                    .build();
    }

    @Test
    @WithMockOAuth2Scope(scope = "dataLicense")
    public void testSchedule() throws Exception {
        mockMvc.perform(post("/schedule").contentType(MediaType.APPLICATION_JSON_UTF8).content(json)).andDo(print());
    }
}

Et voici le contrôleur sous test:

@RequestMapping(value = "/schedule", method = RequestMethod.POST)
@PreAuthorize("#oauth2.hasScope('dataLicense')")
public int schedule() {
    return 0;
}
19
mclaassen

Spring Boot 1.5 introduit test des tranches like @WebMvcTest. En utilisant ces tranches de test et en chargeant manuellement le OAuth2AutoConfiguration, vos tests sont moins chauds et ils s'exécutent plus rapidement que les solutions proposées basées sur le @SpringBootTest. Si vous importez également votre configuration de sécurité de production, vous pouvez vérifier que les chaînes de filtres configurées fonctionnent pour vos services Web.

Voici la configuration avec quelques classes supplémentaires que vous trouverez probablement bénéfiques:

Manette:

@RestController
@RequestMapping(BookingController.API_URL)
public class BookingController {

    public static final String API_URL = "/v1/booking";

    @Autowired
    private BookingRepository bookingRepository;

    @PreAuthorize("#oauth2.hasScope('myapi:write')")
    @PatchMapping(consumes = APPLICATION_JSON_UTF8_VALUE, produces = APPLICATION_JSON_UTF8_VALUE)
    public Booking patchBooking(OAuth2Authentication authentication, @RequestBody @Valid Booking booking) {
        String subjectId = MyOAuth2Helper.subjectId(authentication);
        booking.setSubjectId(subjectId);
        return bookingRepository.save(booking);
    }
}

Test:

@RunWith(SpringRunner.class)
@AutoConfigureJsonTesters
@WebMvcTest
@Import(DefaultTestConfiguration.class)
public class BookingControllerTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private JacksonTester<Booking> json;

    @MockBean
    private BookingRepository bookingRepository;

    @MockBean
    public ResourceServerTokenServices resourceServerTokenServices;

    @Before
    public void setUp() throws Exception {
        // Stub the remote call that loads the authentication object
        when(resourceServerTokenServices.loadAuthentication(anyString())).thenAnswer(invocation -> SecurityContextHolder.getContext().getAuthentication());
    }

    @Test
    @WithOAuthSubject(scopes = {"myapi:read", "myapi:write"})
    public void mustHaveValidBookingForPatch() throws Exception {
        mvc.perform(patch(API_URL)
            .header(AUTHORIZATION, "Bearer foo")
            .content(json.write(new Booking("myguid", "aes")).getJson())
            .contentType(MediaType.APPLICATION_JSON_UTF8)
        ).andExpect(status().is2xxSuccessful());
    }
}

DefaultTestConfiguration:

@TestConfiguration
@Import({MySecurityConfig.class, OAuth2AutoConfiguration.class})
public class DefaultTestConfiguration {

}

MySecurityConfig (pour la production):

@Configuration
@EnableOAuth2Client
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/v1/**").authenticated();
    }

}

Annotation personnalisée pour l'injection de portées à partir de tests:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithOAuthSubjectSecurityContextFactory.class)
public @interface WithOAuthSubject {

    String[] scopes() default {"myapi:write", "myapi:read"};

    String subjectId() default "a1de7cc9-1b3a-4ecd-96fa-dab6059ccf6f";

}

Classe d'usine pour gérer l'annotation personnalisée:

public class WithOAuthSubjectSecurityContextFactory implements WithSecurityContextFactory<WithOAuthSubject> {

    private DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();

    @Override
    public SecurityContext createSecurityContext(WithOAuthSubject withOAuthSubject) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();

        // Copy of response from https://myidentityserver.com/identity/connect/accesstokenvalidation
        Map<String, ?> remoteToken = ImmutableMap.<String, Object>builder()
            .put("iss", "https://myfakeidentity.example.com/identity")
            .put("aud", "oauth2-resource")
            .put("exp", OffsetDateTime.now().plusDays(1L).toEpochSecond() + "")
            .put("nbf", OffsetDateTime.now().plusDays(1L).toEpochSecond() + "")
            .put("client_id", "my-client-id")
            .put("scope", Arrays.asList(withOAuthSubject.scopes()))
            .put("sub", withOAuthSubject.subjectId())
            .put("auth_time", OffsetDateTime.now().toEpochSecond() + "")
            .put("idp", "idsrv")
            .put("amr", "password")
            .build();

        OAuth2Authentication authentication = defaultAccessTokenConverter.extractAuthentication(remoteToken);
        context.setAuthentication(authentication);
        return context;
    }
}

J'utilise une copie de la réponse de notre serveur d'identité pour créer un OAuth2Authentication réaliste. Vous pouvez probablement simplement copier mon code. Si vous souhaitez répéter le processus pour votre serveur d'identité, placez un point d'arrêt dans org.springframework.security.oauth2.provider.token.RemoteTokenServices#loadAuthentication ou org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices#extractAuthentication, selon que vous ayez configuré une variable ResourceServerTokenServices personnalisée ou non. 

8
gogstad

D'accord, je n'ai pas encore pu tester mon serveur de ressources protégé par jeton oauth2 JWT autonome à l'aide du nouveau @WithMockUser ou des annotations associées.

En guise de solution de contournement, j'ai pu tester l'intégration de la sécurité de mon serveur de ressources en configurant une AuthorizationServer permissive sous src/test/Java et en définissant deux clients que j'utilise via une classe d'assistance . Cela me donne une partie du chemin, mais ce n'est pas encore aussi facile que j'aimerais tester différents utilisateurs, rôles, champs d'application, etc.

Je suppose qu’à partir de maintenant, il devrait être plus facile de mettre en œuvre ma propre WithSecurityContextFactory qui crée un OAuth2Authentication, au lieu de la UsernamePasswordAuthentication habituelle. Cependant, je n'ai pas encore été en mesure de déterminer en détail comment le configurer facilement. Tous les commentaires ou suggestions sur la façon de mettre cela en place sont les bienvenus.

4
Tim

J'ai trouvé un moyen simple et rapide de tester le serveur de ressources de sécurité Spring avec n'importe quel magasin de jetons. Je suis dans mon exemple @EnabledResourceServeruses jwt Token Store. 

La magie ici est que j'ai remplacé JwtTokenStore par InMemoryTokenStore lors du test d'intégration.

@RunWith (SpringRunner.class)
@SpringBootTest (classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles ("test")
@TestPropertySource (locations = "classpath:application.yml")
@Transactional
public class ResourceServerIntegrationTest {

@Autowired
private TokenStore tokenStore;

@Autowired
private ObjectMapper jacksonObjectMapper;

@LocalServerPort
int port;

@Configuration
protected static class PrepareTokenStore {

    @Bean
    @Primary
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

}

private OAuth2AccessToken token;
private OAuth2Authentication authentication;

@Before
public void init() {

    RestAssured.port = port;

    token = new DefaultOAuth2AccessToken("FOO");
    ClientDetails client = new BaseClientDetails("client", null, "read", "client_credentials", "ROLE_READER,ROLE_CLIENT");

    // Authorities
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority("ROLE_READER"));
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("writer", "writer", authorities);

    authentication = new OAuth2Authentication(new TokenRequest(null, "client", null, "client_credentials").createOAuth2Request(client), authenticationToken);
    tokenStore.storeAccessToken(token, authentication);

}

@Test
public void gbsUserController_findById() throws Exception {

    RestAssured.given().log().all().when().headers("Authorization", "Bearer FOO").get("/gbsusers/{id}", 2L).then().log().all().statusCode(HttpStatus.OK.value());

}
2
talipkorkmaz

J'ai une autre solution pour cela. Voir ci-dessous.

@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
@ActiveProfiles("test")
public class AccountContollerTest {

    public static Logger log =  LoggerFactory.getLogger(AccountContollerTest.class);


    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mvc;

    @Autowired
    FilterChainProxy springSecurityFilterChain;

    @Autowired
    UserRepository users;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    CustomClientDetailsService clientDetialsService;

    @Before
    public void setUp() {
         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("[email protected]"));

         users.deleteAll();
         users.save(user);

    }

    @Test
    public void shouldRetriveAccountDetailsWithValidAccessToken() throws Exception {
        mvc.perform(get("/api/me")
                .header("Authorization", "Bearer " + validAccessToken())
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andDo(print())
                .andExpect(jsonPath("$.userAuthentication.name").value("testuser"))
                .andExpect(jsonPath("$.authorities[0].authority").value("ROLE_USER"));
    }

    @Test
    public void shouldReciveHTTPStatusUnauthenticatedWithoutAuthorizationHeader() throws Exception{
        mvc.perform(get("/api/me")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isUnauthorized());
    }

    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;
    }
}

J'espère que ça va aider!

2
Rocks360

Il existe une approche alternative qui, à mon avis, est plus propre et plus significative.

L'approche consiste à autoriser automatiquement le magasin de jetons, puis à ajouter un jeton de test pouvant être utilisé par le client restant.

Un exemple de test:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class UserControllerIT {

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Autowired
    private TokenStore tokenStore;

    @Before
    public void setUp() {

        final OAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
        final ClientDetails client = new BaseClientDetails("client", null, "read", "client_credentials", "ROLE_CLIENT");
        final OAuth2Authentication authentication = new OAuth2Authentication(
                new TokenRequest(null, "client", null, "client_credentials").createOAuth2Request(client), null);

        tokenStore.storeAccessToken(token, authentication);

    }

    @Test
    public void testGivenPathUsersWhenGettingForEntityThenStatusCodeIsOk() {

        final HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.AUTHORIZATION, "Bearer FOO");
        headers.setContentType(MediaType.APPLICATION_JSON);

        // Given Path Users
        final UriComponentsBuilder uri = UriComponentsBuilder.fromPath("/api/users");

        // When Getting For Entity
        final ResponseEntity<String> response = testRestTemplate.exchange(uri.build().toUri(), HttpMethod.GET,
                new HttpEntity<>(headers), String.class);

        // Then Status Code Is Ok
        assertThat(response.getStatusCode(), is(HttpStatus.OK));
    }

}

Personnellement, j'estime qu'il n'est pas approprié de tester un contrôleur avec la sécurité activée car la sécurité est une couche distincte de celle du contrôleur. Je créerais un test d'intégration qui teste toutes les couches ensemble. Cependant, l'approche ci-dessus peut facilement être modifiée pour créer un test unitaire avec MockMvc.

Le code ci-dessus est inspiré d'un Spring Security test écrit par Dave Syer.

Notez que cette approche concerne les serveurs de ressources partageant le même magasin de jetons que le serveur d'autorisation. Si votre serveur de ressources ne partage pas le même magasin de jetons que le serveur d'autorisations, je vous recommande d'utiliser wiremock pour simuler les réponses http .

2

Une autre solution que j'ai essayé de détailler suffisamment :-D

Il est basé sur la définition d'un en-tête d'autorisation, comme certains ci-dessus, mais je voulais:

  • Ne pas créer de jetons JWT réellement valides et utiliser toute la pile d'authentification JWT (tests unitaires ...)
  • Authentification de test pour contenir les portées et les autorités définies par le scénario de test

Alors j'ai:

  • création d'annotations personnalisées pour la configuration d'un test OAuth2Authentication: @WithMockOAuth2Client (connexion directe au client) & @WithMockOAuth2User (le client agissant pour le compte d'un utilisateur final => inclut à la fois my custom @ WithMockOAuth2Client et Spring @WithMockUser)
  • @MockBean TokenStore pour renvoyer l'OAuth2Authentication configurée avec les annotations personnalisées ci-dessus
  • fournit les usines MockHttpServletRequestBuilder qui définissent un en-tête d'autorisation spécifique intercepté par TokenStore fausse pour injecter l'authentification attendue.

Le résultat pour vous faire tester:

@WebMvcTest(MyController.class) // Controller to unit-test
@Import(WebSecurityConfig.class) // your class extending WebSecurityConfigurerAdapter
public class MyControllerTest extends OAuth2ControllerTest {

    @Test
    public void testWithUnauthenticatedClient() throws Exception {
        api.post(payload, "/endpoint")
                .andExpect(...);
    }

    @Test
    @WithMockOAuth2Client
    public void testWithDefaultClient() throws Exception {
        api.get("/endpoint")
                .andExpect(...);
    }

    @Test
    @WithMockOAuth2User
    public void testWithDefaultClientOnBehalfDefaultUser() throws Exception {
            MockHttpServletRequestBuilder req = api.postRequestBuilder(null, "/uaa/refresh")
                .header("refresh_token", JWT_REFRESH_TOKEN);

        api.perform(req)
                .andExpect(status().isOk())
                .andExpect(...)
    }

    @Test
    @WithMockOAuth2User(
        client = @WithMockOAuth2Client(
                clientId = "custom-client",
                scope = {"custom-scope", "other-scope"},
                authorities = {"custom-authority", "ROLE_CUSTOM_CLIENT"}),
        user = @WithMockUser(
                username = "custom-username",
                authorities = {"custom-user-authority"}))
    public void testWithCustomClientOnBehalfCustomUser() throws Exception {
        api.get(MediaType.APPLICATION_ATOM_XML, "/endpoint")
                .andExpect(status().isOk())
                .andExpect(xpath(...));
    }
}
0
ch4mp