Skip to content

Commit

Permalink
Merge pull request #67 from pagopa/original-url-as-regex
Browse files Browse the repository at this point in the history
Define Original URL as regex
  • Loading branch information
pp-ps authored Jun 6, 2023
2 parents 2986736 + f3f7e9b commit d2fd61b
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

# Ignore Gradle build output directory
build
bin

# Ignore newman node modules and test reports
e2e/newman
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ public class LollipopConsumerRequestConfig {
@Builder.Default private String expectedFirstLcOriginalMethod = "POST";

@Builder.Default
private String expectedFirstLcOriginalUrl = "https://api-app.io.pagopa.it/first-lollipop/sign";
private String expectedFirstLcOriginalUrl =
"^https://api-app.io.pagopa.it/first-lollipop/sign$";

// assertion validation parameters
@Builder.Default private int assertionExpireInDays = 30;
@Builder.Default private int assertionExpireInDays = 365;
@Builder.Default private String assertionNotBeforeDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
@Builder.Default private String assertionInstantDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ private void validateOriginalURLHeader(String originalURL)
"Invalid Original URL Header value");
}

if (!originalURL.equals(this.config.getExpectedFirstLcOriginalUrl())) {
if (!Pattern.compile(this.config.getExpectedFirstLcOriginalUrl())
.matcher(originalURL)
.matches()) {
String errMsg = String.format("Unexpected original url: %s", originalURL);
throw new LollipopRequestContentValidationException(
LollipopRequestContentValidationException.ErrorCode.UNEXPECTED_ORIGINAL_URL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class LollipopConsumerRequestValidationServiceImplTest {
+ " \"x-pagopa-lollipop-original-url\");created=1678293988;nonce=\"aNonce\";alg=\"ecdsa-p256-sha256\";keyid=\"sha256-a7qE0Y0DyqeOFFREIQSLKfu5WlbckdxVXKFasfcI-Dg\"";
public static final String VALID_SIGNATURE =
"sig1=:lTuoRytp53GuUMOB4Rz1z97Y96gfSeEOm/xVpO39d3HR6lLAy4KYiGq+1hZ7nmRFBt2bASWEpen7ov5O4wU3kQ==:";
public static final String VALID_ORIGINAL_URL =
"https://api-app.io.pagopa.it/first-lollipop/sign";

@BeforeEach
void setUp() {
Expand Down Expand Up @@ -362,6 +364,63 @@ void validateOriginalURLFailureDifferentFromExpectedMethod() {
e.getErrorCode());
}

@Test
void validateOriginalURLFailureWithSameSubstring() {
HashMap<String, String> headers = new HashMap<>();
headers.put(config.getPublicKeyHeader(), VALID_EC_PUBLIC_KEY);
headers.put(config.getAssertionRefHeader(), VALID_ASSERTION_REF);
headers.put(config.getAssertionTypeHeader(), AssertionType.SAML.name());
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL + "/another-path");
LollipopConsumerRequest request =
LollipopConsumerRequest.builder().headerParams(headers).build();

LollipopRequestContentValidationException e =
assertThrows(
LollipopRequestContentValidationException.class,
() -> sut.validateLollipopRequest(request));

assertEquals(
LollipopRequestContentValidationException.ErrorCode.UNEXPECTED_ORIGINAL_URL,
e.getErrorCode());
}

@Test
void validateOriginalURLFailureRegexPatter() {

LollipopConsumerRequestConfig new_config =
spy(LollipopConsumerRequestConfig.builder().build());

new_config.setExpectedFirstLcOriginalUrl(
"^https://api-app.io.pagopa.it/first-lollipop/[a-zA-Z0-9]{8}/sign$");
LollipopConsumerRequestValidationService new_sut =
new LollipopConsumerRequestValidationServiceImpl(new_config);

HashMap<String, String> headers = new HashMap<>();
headers.put(config.getPublicKeyHeader(), VALID_EC_PUBLIC_KEY);
headers.put(config.getAssertionRefHeader(), VALID_ASSERTION_REF);
headers.put(config.getAssertionTypeHeader(), AssertionType.SAML.name());
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(
config.getOriginalURLHeader(),
"https://api-app.io.pagopa.it/first-lollipop/0123_ABCD*/sign");
LollipopConsumerRequest request =
LollipopConsumerRequest.builder().headerParams(headers).build();

LollipopRequestContentValidationException e =
assertThrows(
LollipopRequestContentValidationException.class,
() -> new_sut.validateLollipopRequest(request));

assertEquals(
LollipopRequestContentValidationException.ErrorCode.UNEXPECTED_ORIGINAL_URL,
e.getErrorCode());
}

@Test
void validateSignatureInputFailureHeaderNotPresent() {
HashMap<String, String> headers = new HashMap<>();
Expand All @@ -371,7 +430,7 @@ void validateSignatureInputFailureHeaderNotPresent() {
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), config.getExpectedFirstLcOriginalUrl());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL);
LollipopConsumerRequest request =
LollipopConsumerRequest.builder().headerParams(headers).build();

Expand All @@ -394,7 +453,7 @@ void validateSignatureInputFailureInvalidFormat() {
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), config.getExpectedFirstLcOriginalUrl());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL);
headers.put(config.getSignatureInputHeader(), generateRandomString());
LollipopConsumerRequest request =
LollipopConsumerRequest.builder().headerParams(headers).build();
Expand All @@ -418,7 +477,7 @@ void validateSignatureFailureHeaderNotPresent() {
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), config.getExpectedFirstLcOriginalUrl());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL);
headers.put(config.getSignatureInputHeader(), VALID_SIGNATURE_INPUT);
LollipopConsumerRequest request =
LollipopConsumerRequest.builder().headerParams(headers).build();
Expand All @@ -442,7 +501,7 @@ void validateSignatureFailureInvalidFormat() {
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), config.getExpectedFirstLcOriginalUrl());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL);
headers.put(config.getSignatureInputHeader(), VALID_SIGNATURE_INPUT);
headers.put(config.getSignatureHeader(), generateRandomString());
LollipopConsumerRequest request =
Expand All @@ -467,7 +526,7 @@ void validateRequestSuccessWithECPublicKey() {
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), config.getExpectedFirstLcOriginalUrl());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL);
headers.put(config.getSignatureInputHeader(), VALID_SIGNATURE_INPUT);
headers.put(config.getSignatureHeader(), VALID_SIGNATURE);
LollipopConsumerRequest request =
Expand All @@ -485,7 +544,7 @@ void validateRequestSuccessWithRSAPublicKey() {
headers.put(config.getUserIdHeader(), VALID_FISCAL_CODE);
headers.put(config.getAuthJWTHeader(), VALID_JWT);
headers.put(config.getOriginalMethodHeader(), config.getExpectedFirstLcOriginalMethod());
headers.put(config.getOriginalURLHeader(), config.getExpectedFirstLcOriginalUrl());
headers.put(config.getOriginalURLHeader(), VALID_ORIGINAL_URL);
headers.put(config.getSignatureInputHeader(), VALID_SIGNATURE_INPUT);
headers.put(config.getSignatureHeader(), VALID_SIGNATURE);
LollipopConsumerRequest request =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class ServletIntegrationTest {
+ " \"x-pagopa-lollipop-original-url\");created=1678293988;nonce=\"aNonce\";alg=\"ecdsa-p256-sha256\";keyid=\"sha256-a7qE0Y0DyqeOFFREIQSLKfu5WlbckdxVXKFasfcI-Dg\"";
private static final String SIGNATURE =
"sig123=:6scl8sMzJdyG/OrnJXHRM9ajmIjrJ/zrLUDqvfOxj2h51DUKztTua3vR1kSUj/c/VT1ioDlt1QIMARABhquewg==:";
public static final String VALID_ORIGINAL_URL =
"https://api-app.io.pagopa.it/first-lollipop/sign";

@BeforeAll
public static void startServer() {
Expand All @@ -59,6 +61,7 @@ public static void startServer() {
void testWithValidRequestReturnsSuccess() throws IOException {
SimpleClientsTestUtils.createExpectationAssertionFound();
SimpleClientsTestUtils.createExpectationIdpFound();
lollipopConsumerRequestConfig.setAssertionExpireInDays(365);
lollipopConsumerRequestConfig.setAssertionNotBeforeDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
lollipopConsumerRequestConfig.setAssertionInstantDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
idpCertSimpleClientConfig.setBaseUri("http://localhost:3001");
Expand All @@ -74,8 +77,7 @@ void testWithValidRequestReturnsSuccess() throws IOException {
request.getHeaders()
.add(
lollipopConsumerRequestConfig.getOriginalURLHeader(),
lollipopConsumerRequestConfig
.getExpectedFirstLcOriginalUrl());
VALID_ORIGINAL_URL);
request.getHeaders()
.add(
lollipopConsumerRequestConfig.getOriginalMethodHeader(),
Expand Down Expand Up @@ -131,8 +133,7 @@ void testWithInvalidPayloadRequestReturnsUnauthorized() throws IOException {
request.getHeaders()
.add(
lollipopConsumerRequestConfig.getOriginalURLHeader(),
lollipopConsumerRequestConfig
.getExpectedFirstLcOriginalUrl());
VALID_ORIGINAL_URL);
request.getHeaders()
.add(
lollipopConsumerRequestConfig.getOriginalMethodHeader(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
import it.pagopa.tech.lollipop.consumer.spring.config.HttpVerifierConfiguration;
import it.pagopa.tech.lollipop.consumer.spring.config.SpringLollipopConsumerRequestConfig;
import java.io.IOException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockserver.integration.ClientAndServer;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -34,7 +31,7 @@
public class HttpVerifierHandlerInterceptorIntegrationTest {

@LocalServerPort private int port;
@Autowired private TestRestTemplate restTemplate;
private TestRestTemplate restTemplate;
@Autowired private SpringLollipopConsumerRequestConfig springLollipopConsumerRequestConfig;
@Autowired private HttpVerifierHandlerInterceptor interceptor;
@Autowired private IdpCertSimpleClientConfig idpCertSimpleClientConfig;
Expand All @@ -49,9 +46,12 @@ public class HttpVerifierHandlerInterceptorIntegrationTest {
+ " \"x-pagopa-lollipop-original-url\");created=1678293988;nonce=\"aNonce\";alg=\"ecdsa-p256-sha256\";keyid=\"sha256-a7qE0Y0DyqeOFFREIQSLKfu5WlbckdxVXKFasfcI-Dg\"";
private static final String SIGNATURE =
"sig123=:6scl8sMzJdyG/OrnJXHRM9ajmIjrJ/zrLUDqvfOxj2h51DUKztTua3vR1kSUj/c/VT1ioDlt1QIMARABhquewg==:";
public static final String VALID_ORIGINAL_URL =
"https://api-app.io.pagopa.it/first-lollipop/sign";

@BeforeAll
public static void startServer() {
@BeforeEach
public void startServer() {
restTemplate = new TestRestTemplate();
mockServer = startClientAndServer(3000, 3001);
}

Expand All @@ -78,8 +78,7 @@ void testWithValidRequestReturnsSuccess() throws IOException {
.add(
springLollipopConsumerRequestConfig
.getOriginalURLHeader(),
springLollipopConsumerRequestConfig
.getExpectedFirstLcOriginalUrl());
VALID_ORIGINAL_URL);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
Expand Down Expand Up @@ -147,8 +146,7 @@ void testWithInvalidPayloadRequestReturnsUnauthorized() throws IOException {
.add(
springLollipopConsumerRequestConfig
.getOriginalURLHeader(),
springLollipopConsumerRequestConfig
.getExpectedFirstLcOriginalUrl());
VALID_ORIGINAL_URL);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
Expand Down Expand Up @@ -199,8 +197,86 @@ void testWithInvalidPayloadRequestReturnsUnauthorized() throws IOException {
Assertions.assertEquals(401, response.getStatusCodeValue());
}

@AfterAll
public static void stopServer() {
@Test
void testWithInvalidURLRequestReturnsUnauthorized() throws IOException {
SimpleClientsTestUtils.createExpectationAssertionFound();
SimpleClientsTestUtils.createExpectationIdpFound();
springLollipopConsumerRequestConfig.setAssertionExpireInDays(365);
springLollipopConsumerRequestConfig.setAssertionNotBeforeDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'Z'");
springLollipopConsumerRequestConfig.setAssertionInstantDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'Z'");
idpCertSimpleClientConfig.setBaseUri("http://localhost:3001");

RestTemplate exec = restTemplate.getRestTemplate();
exec.getClientHttpRequestInitializers()
.add(
request -> {
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getContentDigestHeader(),
CONTENT_DIGEST);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getOriginalURLHeader(),
VALID_ORIGINAL_URL + "/another-path");
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getOriginalMethodHeader(),
springLollipopConsumerRequestConfig
.getExpectedFirstLcOriginalMethod());
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getPublicKeyHeader(),
VALID_PUBLIC_KEY);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getAssertionRefHeader(),
ASSERTION_REF);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getAssertionTypeHeader(),
"SAML");
request.getHeaders()
.add(
springLollipopConsumerRequestConfig.getAuthJWTHeader(),
JWT);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig.getUserIdHeader(),
USER_ID);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getSignatureInputHeader(),
SIGNATURE_INPUT);
request.getHeaders()
.add(
springLollipopConsumerRequestConfig
.getSignatureHeader(),
SIGNATURE);
});

ResponseEntity<String> response =
exec.postForEntity(
"http://localhost:" + port,
"{\"message\":\"a valid message payload\"}",
String.class);
Assertions.assertNotNull(response);
Assertions.assertEquals(
"^" + VALID_ORIGINAL_URL + "$",
springLollipopConsumerRequestConfig.getExpectedFirstLcOriginalUrl());
Assertions.assertEquals(401, response.getStatusCodeValue());
}

@AfterEach
public void stopServer() {
mockServer.stop();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public LollipopLoggerServiceFactory lollipopLoggerServiceFactory() {

@Bean
public SpringLollipopConsumerRequestConfig verifierConfiguration() {
return new SpringLollipopConsumerRequestConfig();
SpringLollipopConsumerRequestConfig springLollipopConsumerRequestConfig =
new SpringLollipopConsumerRequestConfig();
springLollipopConsumerRequestConfig.setAssertionExpireInDays(365);
return springLollipopConsumerRequestConfig;
}

@Bean
Expand Down

0 comments on commit d2fd61b

Please sign in to comment.