unitarias test pruebas integracion hacer curso como automaticas java spring authentication spring-boot integration-testing

java - test - Autenticación de arranque de primavera para pruebas de integración



test en java (7)

Por qué se aplica la configuración de seguridad

De acuerdo con la documentation Spring Boot, cuando realiza anotaciones en su clase con @SpringBootTest , y no tiene una alternativa de configuración específica, entonces Spring con la búsqueda de una clase @SpringBootApplication para que sirva como su configuración principal. Spring inicia la búsqueda en el paquete de su clase de prueba, luego busca el paquete de búsqueda. Presumiblemente, está encontrando su configuración principal, y todo lo que esto trae consigo, incluida su configuración de seguridad no deseada.

Solución

La solución más sencilla, verificada en Spring Boot 2.0.3, es cambiar @EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class) por @SpringBootApplication(exclude = SecurityAutoConfiguration.class) . Cuando realice este cambio, Spring registrará su clase de prueba como la clase de configuración principal y, por lo tanto, reconocerá su exclusión. Alternativamente, cree una clase de configuración separada para compartir a través de todas sus pruebas de integración que se encuentra en un paquete base y todas sus pruebas de integración encontrarán.

Estoy intentando ejecutar una prueba de integración para mi controlador, pero tengo problemas si no me autentico. Aquí está mi controlador:

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @TestPropertySource(properties = {"security.basic.enabled=false", "management.security.enabled=false"}) @EnableAutoConfiguration(exclude = {org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class}) public class HelloControllerIT { private final ObjectMapper mapper = new ObjectMapper(); @Autowired private TestRestTemplate template; @Test public void test1() throws Exception { ObjectNode loginRequest = mapper.createObjectNode(); loginRequest.put("username","name"); loginRequest.put("password","password"); JsonNode loginResponse = template.postForObject("/authenticate", loginRequest.toString(), JsonNode.class); HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); headers.add("X-Authorization", "Bearer " + loginResponse.get("token").textValue()); headers.add("Content-Type", "application/json"); return new HttpEntity<>(null, headers); HttpEntity request = getRequestEntity(); ResponseEntity response = template.exchange("/get", HttpMethod.GET, request, new ParameterizedTypeReference<List<Foo>>() {}); //assert stuff } }

Cuando corro esto, todo funciona. Pero si comento fuera de la línea:

headers.add("X-Authorization", "Bearer " + loginResponse.get("token").textValue());

Me sale el error

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON document: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at [Source: java.io.PushbackInputStream@272a5bc6; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at [Source: java.io.PushbackInputStream@272a5bc6; line: 1, column: 1] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:234) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:219) at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95) at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917) at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:559) at org.springframework.boot.test.web.client.TestRestTemplate.exchange(TestRestTemplate.java:812) at com.test.HelloControllerIT.test1(HelloControllerIT.java:75) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at [Source: java.io.PushbackInputStream@272a5bc6; line: 1, column: 1] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270) at com.fasterxml.jackson.databind.DeserializationContext.reportMappingException(DeserializationContext.java:1234) at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1122) at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1075) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:338) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:269) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2922) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:231) ... 38 more

Obviamente las anotaciones de seguridad en la parte superior no funcionan. Entonces, ¿cuál es exactamente el problema y cómo lo soluciono?

Edición 1 : Intenté hacer:

Object response = template.exchange("/get", HttpMethod.GET, request, Object.class);

Y consiguió:

<401 Unauthorized,{status=401, message=Authentication failed, errorCode=10, timestamp=1497654855545},{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=ISO-8859-1], Content-Length=[89], Date=[Fri, 16 Jun 2017 23:14:15 GMT]}>

Para nuestra seguridad, estamos usando org.springframework.security.authentication.AuthenticationProvider y org.springframework.security.authentication.AuthenticationManager

Edit 2: Según la sugerencia de skadya, creé una nueva clase así:

@Configuration public class AnonymousConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity web) throws Exception { web.antMatcher("**/*").anonymous(); } }

Pero ahora, cuando ejecuto mi prueba de integración, obtengo el siguiente error:

java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:47) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ''org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration'': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: @Order on WebSecurityConfigurers must be unique. Order of 100 was already used on config.AnonymousConfig$$EnhancerBySpringCGLIB$$ba18b8d7@6291f725, so it cannot be used on security.WebSecurityConfig$$EnhancerBySpringCGLIB$$9d88e7e@1bfaaae1 too. at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) ... 23 more Caused by: java.lang.IllegalStateException: @Order on WebSecurityConfigurers must be unique. Order of 100 was already used on config.AnonymousConfig$$EnhancerBySpringCGLIB$$ba18b8d7@6291f725, so it cannot be used on security.WebSecurityConfig$$EnhancerBySpringCGLIB$$9d88e7e@1bfaaae1 too. at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.setFilterChainProxySecurityConfigurer(WebSecurityConfiguration.java:148) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:701) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ... 40 more

Parece que está chocando con la configuración de seguridad web que tenemos en el proyecto normal. Aquí está ese archivo:

@EnableWebSecurity @EnableWebMvc @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { //configuration }

Intenté agregar @Order(1000) que solucionó el problema anterior, pero aún así terminó en un 401 Unauthorized


Descubrí cómo hacer esto sin autenticación y / o burla en la memoria.

public class TestConf extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.csrf() .disable() .authorizeRequests() .anyRequest() .permitAll(); } }

Y use los perfiles activos de primavera para ejecutar la configuración anterior solo cuando se ejecuten casos de prueba.


Parece que la autenticación funciona, pero usted maneja la respuesta de manera incorrecta.

Aquí está el código a continuación, donde está intentando analizar la respuesta como List<Foo>

ResponseEntity response = template.exchange("/get", HttpMethod.GET, request, new ParameterizedTypeReference<List<Foo>>() {} );

Pero como no ha proporcionado el encabezado de autenticación, el servidor responde con un error personalizado (obviamente envuelto en el objeto Json) y obtiene esta excepción en la prueba diciendo que no puede analizar ArrayList desde el objeto Json (que comienza con el token START_OBJECT , como { ).

Could not read JSON document: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token

Trate de manejar la respuesta como Objeto para que pueda ver lo que realmente viene allí.

template.exchange("/get", HttpMethod.GET, request, Object.class);

Pero esto no funcionará como una solución final. Creo que debería manejar el cuerpo de respuesta basado en el código de respuesta Http , si es 200 - analizar como List<> , de lo contrario analizar como Map<> o cualquier estructura que devuelva el servidor.


Parece que la configuración de seguridad predeterminada está siendo activada. A menos que vea su configuración completa, es difícil confirmar esto. Si es posible, ¿podría publicar su proyecto mínimo (en github?).

Como no desea aplicar la autenticación durante las ejecuciones de las pruebas de integración, puede habilitar el acceso anónimo de los recursos de su aplicación.

Para habilitar el acceso anónimo, puede agregar la clase debajo de su directorio de origen de prueba . Configurará el acceso anónimo durante el arranque de la aplicación web. (no debería ver el código de respuesta 401)

@Configuration public class AllowAnonymousWebAccess extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity web) throws Exception { web.antMatcher("**/*").anonymous(); } }


Puedes intentar excluir algunas configuraciones automáticas más:

@EnableAutoConfiguration(exclude = { org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class, org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration.class, org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration.class, org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration.class })

Por cierto, una forma más elegante de excluir cosas es definiendo application-test.properties en sus fuentes de prueba y marcando su prueba con @Profile("test") . Luego simplemente agregue esto a su configuración:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration

Puede encontrar todas las configuraciones posibles que pueden excluirse aquí : spring.factories


Se enfrentó a este problema durante mucho tiempo. Finalmente lo resolví. Debe burlarse del servidor de Autorización para crear un perfil de prueba y también deberá simular el servicio de detalles de usuario de Spring Security. Aquí está el código que encontré en un blog .

Servidor de Autorización de Pruebas

@Configuration @EnableAuthorizationServer @ActiveProfiles("test") public class AuthorizationTestServer extends AuthorizationServerConfigurerAdapter { private AuthenticationManager authenticationManager; @Autowired public AuthorizationTestServer(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.checkTokenAccess("permitAll()"); oauthServer.allowFormAuthenticationForClients(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { super.configure(clients); clients.inMemory() .withClient("user") .secret("password") .authorizedGrantTypes("password") .scopes("openid"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { super.configure(endpoints); endpoints.authenticationManager(this.authenticationManager); } }

Servicio de detalles de usuario de prueba

@Service @ActiveProfiles("test") public class UserDetailTestService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { return new User("dummyUser","dummyPassword",true,true, true,true, AuthorityUtils.createAuthorityList("USER")); } }

Clase de prueba principal

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("test") @AutoConfigureMockMvc public class JmStudentServiceApplicationTests { @Autowired private WebApplicationContext wac; @Autowired private MockMvc mockMvc; @Autowired private TestRestTemplate restTemplate; @Autowired private StudentRepository studentRepository; @Test public void test() throws Exception{ String accessToken = obtainAccessToken("dummyUser", "dummyPassword"); Student student = new Student(); student.setId("2222"); student.setName("test student"); studentRepository.createStudent(student); assertTrue(studentRepository.getStudentById("2222").getName().equals("test student")); MvcResult result = mockMvc.perform(get("/students/by-id/2222") .header("Authorization", "Bearer " + accessToken) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn(); String str = result.getResponse().getContentAsString(); assertTrue(str.contains("/"id/":/"2222/"")); } private String obtainAccessToken(String username, String password) throws Exception { MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("grant_type", "password"); params.add("username", username); params.add("password", password); params.add("scope", "openid"); String base64ClientCredentials = new String(Base64.encodeBase64("user:password".getBytes())); ResultActions result = mockMvc.perform(post("/oauth/token") .params(params) .header("Authorization","Basic " + base64ClientCredentials) .accept("application/json;charset=UTF-8")) .andExpect(status().isOk()); String resultString = result.andReturn().getResponse().getContentAsString(); JacksonJsonParser jsonParser = new JacksonJsonParser(); return jsonParser.parseMap(resultString).get("access_token").toString(); } }


Tiene un par de opciones para proporcionar autenticación en la prueba de integración de arranque de primavera. Es posible que deba ajustar algunas cosas para que todo funcione al final.

Enfoque basado en simulacros

Esto utiliza la prueba WebApplicationContext inyectada en MockMvc con la anotación @WithMockUser para proporcionar al usuario de autenticación y WithMockUserSecurityContextFactory creando el contexto de seguridad para el usuario simulado.

SecurityMockMvcConfigurers registra el filtro de seguridad springSecurityFilterChain con MockMvc .

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class HelloControllerIT { @Autowired private WebApplicationContext context; private MockMvc mvc; @Before public void setup() { mvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) // enable security for the mock set up .build(); } @WithMockUser(value = "test", password = "pass") @Test public void test() throws Exception { String contentType = MediaType.APPLICATION_JSON + ";charset=UTF-8"; String authzToken = mvc .perform( post("/authenticate") .contentType( MediaType.APPLICATION_JSON). content("")). andExpect(status().isOk()) .andExpect(content().contentType(contentType)) .andExpect(jsonPath("$.token", is(notNullValue()))) .andReturn().getResponse().getContentAsString(); System.out.print(authzToken);//{"token":"1a3434a"} } }

Enfoque basado en el proveedor de autenticación en la memoria

Esto utiliza el proveedor de autenticación en memoria con el usuario de autenticación básica.

Registre el proveedor de autenticación en memoria y habilite la autenticación básica, deshabilite el acceso anónimo en HttpSecurity en WebSecurityConfigurerAdapter .

Cuando el proveedor en memoria está registrado, DefaultInMemoryUserDetailsManagerConfigurer crea el usuario de autenticación básico en la memoria.

Cuando la autenticación básica está habilitada, HttpBasicConfigurer configura BasicAuthenticationFilter . Autentica al usuario de prueba y crea el contexto de seguridad.

Configuración de seguridad

@EnableWebSecurity @EnableWebMvc @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { // register test user with in memory authentication provider auth.inMemoryAuthentication().withUser("test").password("pass").roles("ROLES"); } @Override public void configure(HttpSecurity http) throws Exception { // enable basic authentication & disable anoymous access http.authorizeRequests().anyRequest().authenticated().and().httpBasic().and().anonymous().disable(); } }

Punto final de autenticación

@Controller @RequestMapping("/authenticate") public class AuthenticationController { @RequestMapping(method = RequestMethod.POST) @ResponseBody public TokenClass getToken() { TokenClass tokenClass = new TokenClass(); tokenClass.setToken("1a3434a"); return tokenClass; } }

Pojo

public class TokenClass { private String token; public String getToken() { return token; } public void setToken(String token) { this.token = token; } }

Controlador de prueba

import com.fasterxml.jackson.databind.JsonNode; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.*; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; import java.util.Base64; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class HelloControllerIT { @Autowired private TestRestTemplate template; @Test public void test() throws Exception { HttpHeaders authHeaders = new HttpHeaders(); String token = new String(Base64.getEncoder().encode( ("test" + ":" + "pass").getBytes())); authHeaders.set("Authorization", "Basic " + token); JsonNode loginResponse = template.postForObject("/authenticate", new HttpEntity<>(null, authHeaders), JsonNode.class); HttpHeaders authzHeaders = new HttpHeaders(); authzHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); authzHeaders.add("X-Authorization", "Bearer " + loginResponse.get("token").textValue()); authzHeaders.add("Content-Type", "application/json"); ResponseEntity response = template.exchange("/secure", HttpMethod.GET, new HttpEntity<>(null, authzHeaders), String.class ); } }