Я пытаюсь отключить безопасность для интеграционных тестов, но пока ничего не работает.
Это мой pom.xml:
Я пытаюсь протестировать этот контроллер отдыха:< /p>
С этим тестовым классом:
Я пробовал разные вещи, но ни один из них не сработал:
У меня есть SecurityConfig и TestSecurityConfig
Также попробовал это на @BeforeEach:
А также попробовал @WebMvcTest(PatientRestController.class) вместо @SpringBootTest и @MockBean в необходимых зависимостях, но этот подход заставил бы меня высмеивать результат операции в базе данных , что, по моему мнению, противоречит подходу testcontainers.
Я получаю следующую ошибку:
В моем application.yaml у меня есть это:
< p>И в моем application-test-integration.yaml у меня есть это:<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kaiho</groupId>
<artifactId>diagnomanager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>DiagnoManager</name>
<description>Software de gestion asistencial domiciliaria y hospitalaria</description>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mapstruct.version>1.6.0.Beta1</mapstruct.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<org.projectlombok.version>1.18.30</org.projectlombok.version>
<!-- JaCoCo Properties -->
<jacoco.version>0.8.6</jacoco.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.15.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency> <!-- This dependency will help us start our docker-compose file when the application starts up.-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
</dependencies>
<build>
...
</build>
</project>
@RestController
@RequestMapping(value = "/api/v1/patients", produces = APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class PatientRestController {
private final PatientHandler patientHandler;
@Operation(summary = "Creates a new patient")
@PostMapping(consumes = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAuthority('WRITE_PATIENTS')")
public ResponseEntity<ApiGenericResponse<PatientResponseDto>> createPatient(@RequestBody @Valid ApiGenericRequest
<PatientRequestDto> request) {
PatientRequestDto data = request.getData();
return new ResponseEntity<>(patientHandler.createPatient(data), HttpStatus.CREATED);
}
}
@SpringBootTest
@Testcontainers
@AutoConfigureMockMvc(addFilters = false)
@ActiveProfiles("test-integration")
@Import({TestSecurityConfig.class})
@TestPropertySource(locations = "classpath:application-test-integration.yaml")
class PatientRestControllerTest {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:latest");
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private PatientEntityRepository patientEntityRepository;
@BeforeEach
void setUp() {
patientEntityRepository.deleteAll();
}
@AfterEach
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test
void shouldCreatePatientAndReturnCreatedStatus() throws Exception {
// given
MetaRequest meta = new MetaRequest();
PatientRequestDto data = new PatientRequestDto(IdType.CC, "987654321", "XXX",
"YYY", "ZZZ", "AAA",
LocalDate.of(1993, 5, 18), Gender.FEMALE, BloodType.Aneg, MaritalStatus.SINGLE,
"123456789", "[email protected]", "05", "005", Zone.URBAN,
"Random Address", "57", "asdf",
"BBB", "CCC", "1234567");
ApiGenericRequest<PatientRequestDto> request = new ApiGenericRequest<>(meta, data);
// when
ResultActions perform = mockMvc.perform(post("/api/v1/patients")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
);
// then
perform.andExpect(status().isCreated());
assertThat(patientEntityRepository.findAll()).hasSize(1);
}
}
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
"/actuator/prometheus",
"/api/v1/auth/**",
"/api/v1/patients/**").permitAll()
.requestMatchers("/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
@Configuration
@Profile("test-integration")
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = false)
public class TestSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().anyRequest();
}
@Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new DenyAllPermissionEvaluator());
return expressionHandler;
}
private static class DenyAllPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return true;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return true;
}
}
@BeforeEach
void setUp() {
patientEntityRepository.deleteAll();
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Authentication authentication = Mockito.mock(Authentication.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
Mockito.when(authentication.isAuthenticated()).thenReturn(true);
SecurityContextHolder.setContext(securityContext);
System.out.println(SecurityContextHolder.getContext());
}
jakarta.servlet.ServletException: Request processing failed: org.springframework.security.access.AccessDeniedException: Access Denied
Caused by: org.springframework.security.access.AccessDeniedException: Access Denied
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.attemptAuthorization(AuthorizationManagerBeforeMethodInterceptor.java:256)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.invoke(AuthorizationManagerBeforeMethodInterceptor.java:197)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)
at com.kaiho.diagnomanager.infrastructure.patient.input.rest.PatientRestController$$SpringCGLIB$$0.createPatient(<generated>)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at ...
spring:
application:
name: diagnomanager
sql:
init:
mode: always
jpa:
properties:
hibernate:
format_sql: true
hibernate:
ddl-auto: create-drop
show-sql: true
logging:
level:
org:
hibernate:
SQL: DEBUG
type:
descriptor:
sql:
BasicBinder: TRACE
---
spring:
config:
activate:
on-profile: test-integration
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
logging:
level:
org.springframework.security: TRACE
spring:
jpa:
hibernate:
ddl-auto: create
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
logging:
level:
org.springframework.security: TRACE
security:
ignored: /**
Вячеслав
Вопрос задан22 февраля 2024 г.