Commit 4977d6a8 authored by Jujube Orange's avatar Jujube Orange
Browse files

refactor(clea-ws): replace custom JWT filter with spring oauth2-jwt

parent 18f09c05
<?xml version="1.0" encoding="UTF-8" ?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>
......@@ -31,51 +31,37 @@
<version>${springfox-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${io.jsonwebtoken.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${io.jsonwebtoken.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${io.jsonwebtoken.version}</version>
<scope>runtime</scope>
<groupId>fr.inria.clea</groupId>
<artifactId>clea-crypto</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>kafka</artifactId>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>fr.inria.clea</groupId>
<artifactId>clea-crypto</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
......@@ -83,12 +69,14 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<groupId>org.testcontainers</groupId>
<artifactId>kafka</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
......@@ -102,11 +90,6 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
......
package fr.gouv.clea.ws.configuration;
import fr.inria.clea.lsp.LocationSpecificPartDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CleaCryptoConfiguration {
@Bean
public LocationSpecificPartDecoder getLocationSpecificPartDecoder() {
return new LocationSpecificPartDecoder();
}
}
package fr.gouv.clea.ws.configuration;
import fr.gouv.clea.ws.exception.CleaForbiddenException;
import fr.gouv.clea.ws.exception.CleaUnauthorizedException;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.web.filter.GenericFilterBean;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PublicKey;
@RequiredArgsConstructor
@Slf4j
public class JwtValidationFilter extends GenericFilterBean {
private final boolean checkAuthorization;
private final PublicKey robertJwtPublicKey;
private final HandlerExceptionResolver handlerExceptionResolver;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
if (this.checkAuthorization) {
String auth = ((HttpServletRequest) request).getHeader(HttpHeaders.AUTHORIZATION);
this.checkAuthorization(auth);
}
chain.doFilter(request, response);
} catch (Exception e) {
handlerExceptionResolver
.resolveException((HttpServletRequest) request, (HttpServletResponse) response, null, e);
}
}
public void checkAuthorization(String jwtToken) throws CleaForbiddenException {
if (jwtToken == null) {
log.warn("Missing Authorisation header!");
throw new CleaUnauthorizedException();
}
jwtToken = jwtToken.replace("Bearer ", "");
this.verifyJWT(jwtToken);
}
private void verifyJWT(String token) throws CleaForbiddenException {
try {
Jwts.parserBuilder().setSigningKey(robertJwtPublicKey).build().parseClaimsJws(token);
} catch (Exception e) {
log.warn("Failed to verify JWT token!", e);
throw new CleaForbiddenException();
}
}
}
package fr.gouv.clea.ws.configuration;
import fr.inria.clea.lsp.LocationSpecificPartDecoder;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
import static org.springframework.security.oauth2.jose.jws.SignatureAlgorithm.RS256;
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CleaWsProperties properties;
private final HandlerExceptionResolver handlerExceptionResolver;
@Bean
public LocationSpecificPartDecoder getLocationSpecificPartDecoder() {
return new LocationSpecificPartDecoder();
}
private PublicKey initPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] encoded = Decoders.BASE64.decode(this.properties.getRobertJwtPublicKey());
KeyFactory keyFactory = KeyFactory.getInstance(SignatureAlgorithm.RS256.getFamilyName());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return keyFactory.generatePublic(keySpec);
}
private final CleaWsProperties cleaWsProperties;
@Override
protected void configure(HttpSecurity http) throws Exception {
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/clea/**").permitAll()
.and()
.addFilterAfter(
new JwtValidationFilter(
this.properties.isAuthorizationCheckActive(), this.initPublicKey(),
handlerExceptionResolver
), BasicAuthenticationFilter.class
)
.httpBasic().disable()
.csrf().disable()
.cors();
.sessionManagement().sessionCreationPolicy(STATELESS);
http.oauth2ResourceServer()
.jwt();
http.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.anyRequest().authenticated();
}
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(
// Swagger UI v2
"/v2/api-docs",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**",
// Swagger UI v3
"/v3/api-docs/**",
"/swagger-ui/**",
// other public endpoints
"/actuator/**"
);
@Bean
public JwtDecoder jwtDecoder() throws NoSuchAlgorithmException, InvalidKeySpecException {
final var keySpec = Base64.getMimeDecoder()
.decode(cleaWsProperties.getRobertJwtPublicKey());
final var publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(keySpec));
return NimbusJwtDecoder.withPublicKey(publicKey)
.signatureAlgorithm(RS256)
.build();
}
}
package fr.gouv.clea.ws.configuration;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.gouv.clea.ws.dto.ApiError;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.testcontainers.shaded.org.apache.commons.lang.RandomStringUtils;
import java.io.IOException;
import java.security.KeyPair;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class JwtValidationFilterTest {
private final MockHttpServletRequest request = new MockHttpServletRequest(
"POST", "/api/clea/v1/wreport"
);
private final MockHttpServletResponse response = new MockHttpServletResponse();
private final MockFilterChain chain = new MockFilterChain();
private KeyPair keyPair;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private HandlerExceptionResolver handlerExceptionResolver;
@BeforeEach
void init() {
keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
}
@Test
@DisplayName("if authorization check is active, a valid token should not cause filter to reject request")
void testEnabledAuthWithValidToken() {
long jwtLifeTime = 5;
Instant now = Instant.now();
Instant expiration = now.plus(jwtLifeTime, ChronoUnit.MINUTES);
JwtValidationFilter jwtValidationFilter = new JwtValidationFilter(
true, keyPair.getPublic(), handlerExceptionResolver
);
request.addHeader(HttpHeaders.AUTHORIZATION, this.newJwtToken(now, expiration));
jwtValidationFilter.doFilter(request, response, chain);
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
@DisplayName("if authorization check is active, a token with an expired date should cause filter to return 403")
void testEnabledAuthWithExpiredToken() {
Instant now = Instant.now();
JwtValidationFilter jwtValidationFilter = new JwtValidationFilter(
true, keyPair.getPublic(), handlerExceptionResolver
);
request.addHeader(HttpHeaders.AUTHORIZATION, this.newJwtToken(now, now));
jwtValidationFilter.doFilter(request, response, chain);
assertThat(response.getStatus()).isEqualTo(403);
}
@Test
@DisplayName("if authorization check is active, a null token should cause filter to return 401")
void testEnabledAuthWithNullToken() throws IOException {
JwtValidationFilter jwtValidationFilter = new JwtValidationFilter(
true, keyPair.getPublic(), handlerExceptionResolver
);
jwtValidationFilter.doFilter(request, response, chain);
ApiError apiError = objectMapper.readValue(response.getContentAsString(), ApiError.class);
assertThat(response.getStatus()).isEqualTo(401);
assertThat(apiError.getMessage()).isEqualTo("Could not be authorized (Missing authorisation header/token)");
}
@Test
@DisplayName("if authorization check is inactive, a null token should have no impact")
void testDisabledAuthWithNullToken() {
JwtValidationFilter jwtValidationFilter = new JwtValidationFilter(
false, keyPair.getPublic(), handlerExceptionResolver
);
jwtValidationFilter.doFilter(request, response, chain);
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
@DisplayName("if authorization check is active, an invalid token should cause filter to return 403")
void testEnabledAuthWithInvalidToken() throws IOException {
JwtValidationFilter jwtValidationFilter = new JwtValidationFilter(
true, keyPair.getPublic(), handlerExceptionResolver
);
request.addHeader(HttpHeaders.AUTHORIZATION, RandomStringUtils.randomAlphanumeric(9));
jwtValidationFilter.doFilter(request, response, chain);
ApiError apiError = objectMapper.readValue(response.getContentAsString(), ApiError.class);
assertThat(response.getStatus()).isEqualTo(403);
assertThat(apiError.getMessage()).isEqualTo("Could not be authenticated (Authorisation header/token invalid)");
}
@Test
@DisplayName("if authorization check is inactive, an invalid token should have no impact")
void testDisabledAuthWithInvalidToken() {
JwtValidationFilter jwtValidationFilter = new JwtValidationFilter(
false, keyPair.getPublic(), handlerExceptionResolver
);
request.addHeader(HttpHeaders.AUTHORIZATION, RandomStringUtils.randomAlphanumeric(9));
jwtValidationFilter.doFilter(request, response, chain);
assertThat(response.getStatus()).isEqualTo(200);
}
private String newJwtToken(Instant now, Instant expiration) {
return Jwts.builder()
.setHeaderParam("type", "JWT")
.setIssuedAt(Date.from(now))
.setExpiration(Date.from(expiration))
.signWith(keyPair.getPrivate(), SignatureAlgorithm.RS256)
.compact();
}
}
package fr.gouv.clea.ws.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.gouv.clea.ws.dto.ApiError;
import fr.gouv.clea.ws.service.impl.ReportService;
import fr.gouv.clea.ws.vo.ReportRequest;
import fr.gouv.clea.ws.vo.Visit;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = { "clea.conf.authorizationCheckActive=true" })
class CleaControllerAuthEnabledTest {
/*
* needed to generate a jwt key, that we can decrypt using public key in test
* confs
*/
private static final String privateJwtKet = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCSnywoJusbV6UYYbyf8KrQ5V5MD1X8zo40oCuF5IRYQ4mb+9brS11BbuEn6UJDUuCDiAs0vcunwa71Hv6dakKcqfAZaIvQEpacbfVJDY7TX9QxrbJYUlEkJsbj2zOA+3g+G+taw007I74rPUfA7axN9eRGknl2+pkXQS3bConLZR5U7MT/9r9me4HPC4Z8kRcE5Pvvh4US9Bad9fZkRY5q+KaI8qxvjoeqDgumZVHRDuIfwOPcPTkefTc7zTr3a2Y2MaXidafk/9v1gR0kgBYdxMEWJEyBuwpEbYo0CD7TitxmfH/D7Fw2qyQq9xHXVMLNS40+woEKlniisC2vg7/tAgMBAAECggEAZbIhXngf+gcAa7jeq9CxqdJtZTP94CskVzwA9A1b/hxaBebXWrwbIpdVc+lGHIwPTSu/GgXKi8C7KSkmUOiy6xazgewRjXBXJojd6J2Owu1ksFBZswjlXr3GlaQkRQImlG2pAHsVxj80V6lZa2dua2RxwME3nl6ScJ60v4i/qmKbNxcAcHOjK1mvtcOiyViCkJHG+qq+koVxTQ7se9hfXG6wLtVUpCQgKgkhuIUg1IwgkKoyOt9OKMhiJp+E1IwUOg3XazL3PA2pBIrp8mxhB/I75s9un7cBjOuv1ywZO3KfYLYD6hSq6RWeywRIVSH7vn2lAJtivrxBJAKDB6jZwQKBgQDN1YvgwSJYiFnSi+4S+Hoheh7qHHiXKaL4nubAhZlW1DKeh79OpUrbVMwHZdSQzf46TrFBnhQ0t4kFWgLxgqldY8lO/Hndly2i5c04EEEeCzcWaXcWv24omUMpbYD7JpRsj6JjS08zS2X8nkJjj2OgcUb4HcVCKof8Jj3i5GRzpwKBgQC2Wzt0MqRacDdWsCDTxP6nGJS8yA4oDBONFjdYaTuypqTM0SQ1XiyUvBwx1o79PZAhknb4/UXkMApj5e0BKmmtmNDypWgthQfPK7RamKu2FpcEMSnM4HSFvDYzWCrmddbWdGwm7FsU7W4FCMTKnMRBQ6K0UQPlEc1tnds6yW7ySwKBgQCZjbSjQBGaUGYJ7z/1QQ8DiHIlnoXL51Df/tMQTtp87yKwJ37tcdwtUc4/upTgTfxZjTkpRX+3cDA1INhPSXWF6RpV5X4YdF6kRqFZMK8TdbRr8NPZ0Yehm+yBrGJrenWBo4m2X4k/MAFuerX2RhNBryANm0/8M3RtBC5o5I+XwwKBgBCuWcrwUv5+42EHrYkRrSXF5t06A6mAKU2vqZJp1e8qtUqTGxfSrItShdW9Rck+l2+qwT1Xlcwg5OJshvijU5VwtDRuExCO6b72xYHAE30NpfTZNnSqV55gMCkUOKBqSSPG9Jm+5zoL2hOV0MKkAoPh1wFdo9iRf1Q2q3Y+NOrvAoGAU2RldX35DEub3EtWl70wEvNx1DuGPCBPL5OyMsJzJh3x5cpzHZc5B9TLjIT3YeRjKiaZxtJ/evulCw/ugScEFph4GtvJZgZYutVRO8LdsqYlb+1ikE/Hd9sqhp7PhDJhfQSV3uLGrfX5fd+bizNAr8swwAFxu35N8vdKOKHtnp8=";
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private ReportService reportService;
@Captor
private ArgumentCaptor<ReportRequest> reportRequestArgumentCaptor;
@Test
void testWhenReportRequestWithMissingAuthenticationThenUNAUTHORIZED() throws JsonProcessingException {
List<Visit> visits = List.of(
new Visit(RandomStringUtils.randomAlphanumeric(20), RandomUtils.nextLong()),
new Visit(RandomStringUtils.randomAlphanumeric(20), RandomUtils.nextLong()),
new Visit(RandomStringUtils.randomAlphanumeric(20), RandomUtils.nextLong())
);
HttpEntity<ReportRequest> request = new HttpEntity<>(
new ReportRequest(visits, 0L), CleaControllerTest.newJsonHeader()
);
ResponseEntity<String> response = restTemplate
.postForEntity("/api/clea/v1/wreport", request, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
ApiError apiError = objectMapper.readValue(response.getBody(), ApiError.class);
assertThat(apiError.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
assertThat(apiError.getTimestamp()).isBefore(Instant.now());
assertThat(apiError.getMessage()).isEqualTo("Could not be authorized (Missing authorisation header/token)");
assertThat(apiError.getValidationErrors()).isEmpty();
}
@Test
void testWhenReportRequestWithNonValidAuthenticationThenGetFORBIDDEN() throws JsonProcessingException {
List<Visit> visits = List.of(
new Visit(RandomStringUtils.randomAlphanumeric(20), RandomUtils.nextLong()),
new Visit(RandomStringUtils.randomAlphanumeric(20), RandomUtils.nextLong()),
new Visit(RandomStringUtils.randomAlphanumeric(20), RandomUtils.nextLong())
);
HttpHeaders headers = CleaControllerTest.newJsonHeader();
headers.setBearerAuth("invalid JWT token");
HttpEntity<ReportRequest> reportEntity = new HttpEntity<>(new ReportRequest(visits, 0L), headers);
ResponseEntity<String> response = restTemplate
.postForEntity("/api/clea/v1/wreport", reportEntity, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
ApiError apiError = objectMapper.readValue(response.getBody(), ApiError.class);
assertThat(apiError.getHttpStatus()).isEqualTo(HttpStatus.FORBIDDEN.value());
assertThat(apiError.getTimestamp()).isBefore(Instant.now());
assertThat(apiError.getMessage()).isEqualTo("Could not be authenticated (Authorisation header/token invalid)");
assertThat(apiError.getValidationErrors()).isEmpty();
}
@Test
@DisplayName("unsecured apis should return 200 when called without auth token")
void testUnsecuredApiWithoutToken() {
ResponseEntity<String> response = restTemplate.getForEntity("/actuator", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
response = restTemplate.getForEntity("/swagger-ui/", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
@DisplayName("unsecured apis should return 200 when called with an invalid auth token")
void testUnsecuredApiWithInvalidToken() {
HttpHeaders headers = CleaControllerTest.newJsonHeader();
headers.setBearerAuth(RandomStringUtils.randomAlphanumeric(20));
ResponseEntity<String> response = restTemplate
.exchange("/actuator", HttpMethod.GET, new HttpEntity<>(headers), String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
response = restTemplate.exchange("/swagger-ui/", HttpMethod.GET, new HttpEntity<>(headers), String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
@DisplayName("secured apis should return 200 when called with a valid auth token")
void validRequestWithAuthEnabledAndValidToken() throws NoSuchAlgorithmException, InvalidKeySpecException {
Instant now = Instant.now();
Instant yesterday = now.minus(1, ChronoUnit.DAYS);
Instant tomorrow = now.plus(1, ChronoUnit.DAYS);
HttpHeaders headers = CleaControllerTest.newJsonHeader();
headers.setBearerAuth(this.newJwtToken(yesterday, tomorrow));