Skip to content

Commit

Permalink
AUT-3691: Add integration test for ReverificationResultHandler and up…
Browse files Browse the repository at this point in the history
…date integration test for MfaResetAuthorizeHandler.

Updated the KmsAccessInterceptor to maintain a set of all keys used to sign.

Updated the MfaResetAuthorizeHandlerIntegrationTest to use the new version of the KmsAccessInterceptor and added missing check for second key used to sign during its request processing.

The ReverificationResultHandlerIntegrationTest follows the same pattern as the MfaResetAuthorizeHandlerIntegrationTest but also uses wiremock to simulate IPV.
  • Loading branch information
andrew-moores committed Jan 6, 2025
1 parent f422e0a commit 4877df0
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 10 deletions.
1 change: 1 addition & 0 deletions integration-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies {
testImplementation("uk.org.webcompere:system-stubs-jupiter:2.1.3")
testImplementation("com.google.guava:guava:33.3.1-jre")
testImplementation("org.awaitility:awaitility:4.2.0")
testImplementation('org.wiremock:wiremock-jetty12:3.10.0')
}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,14 @@ void shouldAuthenticateMfaReset() {
checkCorrectKeysUsedViaIntegrationWithKms();
checkStateIsStoredViaIntegrationWithRedis(sessionId);
checkTxmaEventPublishedViaIntegrationWithSQS();
checkExectionMetricsPublishedViaIntegrationWithCloudWatch();
checkExecutionMetricsPublishedViaIntegrationWithCloudWatch();
}

private static void checkCorrectKeysUsedViaIntegrationWithKms() {
var kmsAccessInterceptor = ConfigurationService.getKmsAccessInterceptor();
assertEquals(mfaResetJarSigningKey.getKeyId(), kmsAccessInterceptor.getAccessedKeyId());
assertTrue(kmsAccessInterceptor.wasKeyUsedToSign(mfaResetJarSigningKey.getKeyId()));
assertTrue(
kmsAccessInterceptor.wasKeyUsedToSign(mfaResetStorageTokenSigningKey.getKeyId()));
}

private static void checkStateIsStoredViaIntegrationWithRedis(String sessionId) {
Expand All @@ -182,7 +184,7 @@ private static void checkTxmaEventPublishedViaIntegrationWithSQS() {
.until(() -> txmaAuditQueue.getApproximateMessageCount() > 0);
}

private static void checkExectionMetricsPublishedViaIntegrationWithCloudWatch() {
private static void checkExecutionMetricsPublishedViaIntegrationWithCloudWatch() {
assertTrue(cloudwatchExtension.hasLoggedMetric(MFA_RESET_HANDOFF.getValue()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package uk.gov.di.authentication.api;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.nimbusds.oauth2.sdk.id.Subject;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import software.amazon.awssdk.services.kms.model.KeyUsageType;
import uk.gov.di.authentication.frontendapi.entity.ReverificationResultRequest;
import uk.gov.di.authentication.frontendapi.lambda.ReverificationResultHandler;
import uk.gov.di.authentication.shared.helpers.ClientSubjectHelper;
import uk.gov.di.authentication.shared.helpers.SaltHelper;
import uk.gov.di.authentication.shared.serialization.Json;
import uk.gov.di.authentication.shared.services.ConfigurationService;
import uk.gov.di.authentication.sharedtest.basetest.ApiGatewayHandlerIntegrationTest;
import uk.gov.di.authentication.sharedtest.extensions.KmsKeyExtension;
import uk.org.webcompere.systemstubs.environment.EnvironmentVariables;
import uk.org.webcompere.systemstubs.jupiter.SystemStub;
import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;

import java.net.URI;
import java.util.Map;
import java.util.Optional;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static uk.gov.di.authentication.sharedtest.matchers.APIGatewayProxyResponseEventMatcher.hasStatus;

@ExtendWith(SystemStubsExtension.class)
class ReverificationResultHandlerIntegrationTest extends ApiGatewayHandlerIntegrationTest {
private static final String USER_EMAIL = "[email protected]";
private static final String USER_PASSWORD = "Password123!";
private static final String USER_PHONE_NUMBER = "+447712345432";

public static final String SUCCESSFUL_TOKEN_RESPONSE =
"""
{
"access_token": "access-token",
"token_type": "bearer",
"expires_in": 3600,
"scope": "openid"
}
""";

private static final String SUCCESSFUL_USER_INFO_HTTP_RESPONSE_CONTENT =
"""
{
"sub": "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
"success": true"
}
""";

private String sessionId;

@SystemStub static EnvironmentVariables environment = new EnvironmentVariables();

@RegisterExtension
private static final KmsKeyExtension mfaResetJarSigningKey =
new KmsKeyExtension("mfa-reset-jar-signing-key", KeyUsageType.SIGN_VERIFY);

@BeforeAll
static void setupEnvironment() {
environment.set("MFA_RESET_JAR_SIGNING_KEY_ALIAS", mfaResetJarSigningKey.getKeyId());
environment.set("IPV_AUTHORISATION_CLIENT_ID", "test-client-id");
environment.set("IPV_AUDIENCE", "test-audience");
environment.set("TXMA_AUDIT_QUEUE_URL", txmaAuditQueue.getQueueUrl());

WireMockServer wireMockServer =
new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort());
wireMockServer.start();
configureFor("localhost", wireMockServer.port());
URI ipvUri = URI.create("http://localhost:" + wireMockServer.port());

environment.set("IPV_BACKEND_URI", ipvUri);
}

@BeforeEach
void setup() throws Json.JsonException {
handler = new ReverificationResultHandler();
sessionId = redis.createAuthenticatedSessionWithEmail(USER_EMAIL);
var internalCommonSubjectId =
ClientSubjectHelper.calculatePairwiseIdentifier(
new Subject().getValue(),
"test.account.gov.uk",
SaltHelper.generateNewSalt());
redis.addInternalCommonSubjectIdToSession(sessionId, internalCommonSubjectId);

String subjectId = "test-subject-id";
userStore.signUp(USER_EMAIL, USER_PASSWORD, new Subject(subjectId));
userStore.addVerifiedPhoneNumber(USER_EMAIL, USER_PHONE_NUMBER);
}

@Test
void shouldSuccessfullyProcessAReverificationResult() {
stubFor(
post(urlPathMatching("/token"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody(SUCCESSFUL_TOKEN_RESPONSE)));

stubFor(
get(urlPathMatching("/reverification"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody(SUCCESSFUL_USER_INFO_HTTP_RESPONSE_CONTENT)));

var response =
makeRequest(
Optional.of(new ReverificationResultRequest("code", "eamil")),
constructFrontendHeaders(sessionId, sessionId),
Map.of());

assertThat(response, hasStatus(200));
checkIntegrationWithTxmaViaSQS();
checkCorrectKeyUsedToSignRequestToIPVViaIntegrationWithKms();
checkIntegrationWithIPV();
}

private static void checkIntegrationWithTxmaViaSQS() {
assertEquals(2, txmaAuditQueue.getRawMessages().size());
}

private static void checkCorrectKeyUsedToSignRequestToIPVViaIntegrationWithKms() {
var kmsAccessInterceptor = ConfigurationService.getKmsAccessInterceptor();
assertTrue(kmsAccessInterceptor.wasKeyUsedToSign(mfaResetJarSigningKey.getKeyId()));
}

private static void checkIntegrationWithIPV() {
WireMock.verify(1, postRequestedFor(urlPathMatching("/token")));
WireMock.verify(1, getRequestedFor(urlPathMatching("/reverification")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
import software.amazon.awssdk.services.kms.model.SignRequest;

import java.util.HashSet;

public class KmsAccessInterceptor implements ExecutionInterceptor {
public String getAccessedKeyId() {
return accessedKeyId;
}
private HashSet<String> signingKeysUsed = new HashSet<>();

private String accessedKeyId = "";
public boolean wasKeyUsedToSign(String keyId) {
return signingKeysUsed.contains(keyId);
}

@Override
public void beforeExecution(
Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
String operation = executionAttributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
if (operation != null && (operation.equals("Sign"))) {
SignRequest encryptRequest = (SignRequest) context.request();
accessedKeyId = encryptRequest.keyId();
SignRequest signRequest = (SignRequest) context.request();
signingKeysUsed.add(signRequest.keyId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ private SignedJWT generateSignedJWT(
.message(
SdkBytes.fromByteArray(
message.getBytes(StandardCharsets.UTF_8)))
.keyId(signingKeyId)
.keyId(signingKey)
.signingAlgorithm(signingAlgorithm)
.build();
SignResponse signResult = kmsConnectionService.sign(signRequest);
Expand Down

0 comments on commit 4877df0

Please sign in to comment.