Skip to content

Commit

Permalink
Merge pull request #1949 from govuk-one-login/PYIC-6527
Browse files Browse the repository at this point in the history
PYIC-6527 Update storeIdentity lambda to use EVCSService to store user VCs in EVCS
  • Loading branch information
rpayal authored Jun 5, 2024
2 parents 71526cc + 196527f commit b90ba72
Show file tree
Hide file tree
Showing 22 changed files with 446 additions and 88 deletions.
15 changes: 11 additions & 4 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@
"hashed_secret": "6afab4c634af2dd2b9c344a98f96667277c56df0",
"is_verified": false,
"line_number": 2021
},
{
"type": "Secret Keyword",
"filename": "deploy/template.yaml",
"hashed_secret": "38450ffe4ff65a68053ea5083d47521010709df2",
"is_verified": false,
"line_number": 2489
}
],
"lambdas/build-user-identity/src/test/java/uk/gov/di/ipv/core/builduseridentity/pact/BuildUserIdentityHandlerTest.java": [
Expand Down Expand Up @@ -278,21 +285,21 @@
"filename": "lambdas/initialise-ipv-session/src/test/java/uk/gov/di/ipv/core/initialiseipvsession/InitialiseIpvSessionHandlerTest.java",
"hashed_secret": "3524aaa7f36b6a777ed767b1f2f3cc0512783810",
"is_verified": false,
"line_number": 111
"line_number": 118
},
{
"type": "Base64 High Entropy String",
"filename": "lambdas/initialise-ipv-session/src/test/java/uk/gov/di/ipv/core/initialiseipvsession/InitialiseIpvSessionHandlerTest.java",
"hashed_secret": "76141ecdf327788c3f946f0d1a665cb945cff8ab",
"is_verified": false,
"line_number": 111
"line_number": 118
},
{
"type": "Base64 High Entropy String",
"filename": "lambdas/initialise-ipv-session/src/test/java/uk/gov/di/ipv/core/initialiseipvsession/InitialiseIpvSessionHandlerTest.java",
"hashed_secret": "904f06efe10138ecd43c7cf5ca8dacbc91cb8119",
"is_verified": false,
"line_number": 111
"line_number": 118
}
],
"lambdas/issue-client-access-token/src/test/java/uk/gov/di/ipv/core/issueclientaccesstoken/IssueClientAccessTokenHandlerTest.java": [
Expand Down Expand Up @@ -1914,5 +1921,5 @@
}
]
},
"generated_at": "2024-05-31T11:42:22Z"
"generated_at": "2024-06-04T11:43:36Z"
}
1 change: 1 addition & 0 deletions deploy/journeyEngineStepFunction.asl.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
"ipvSessionId.$": "$$.Execution.Input.ipvSessionId",
"ipAddress.$": "$$.Execution.Input.ipAddress",
"featureSet.$": "$$.Execution.Input.featureSet",
"lambdaInput.$": "$.lambdaInput",
"deviceInformation.$": "$$.Execution.Input.deviceInformation"
},
"Next": "ProcessNextJourney"
Expand Down
2 changes: 2 additions & 0 deletions deploy/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,8 @@ Resources:
KeyId: !Ref DynamoDBKmsKey
- SSMParameterReadPolicy:
ParameterName: !Sub ${Environment}/core/*
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Sub arn:aws:secretsmanager:eu-west-2:*:secret:/${Environment}/core/evcs/api-key-*
- SQSSendMessagePolicy:
QueueName: !ImportValue AuditEventQueueName
- DynamoDBCrudPolicy:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
import org.apache.logging.log4j.message.StringMapMessage;
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.tracing.Tracing;
import uk.gov.di.ipv.core.initialiseipvsession.domain.InheritedIdentityJwtClaim;
import uk.gov.di.ipv.core.initialiseipvsession.domain.JarClaims;
import uk.gov.di.ipv.core.initialiseipvsession.domain.JarUserInfo;
import uk.gov.di.ipv.core.initialiseipvsession.domain.StringListClaim;
import uk.gov.di.ipv.core.initialiseipvsession.exception.JarValidationException;
import uk.gov.di.ipv.core.initialiseipvsession.exception.RecoverableJarValidationException;
import uk.gov.di.ipv.core.initialiseipvsession.service.KmsRsaDecrypter;
Expand Down Expand Up @@ -70,6 +70,8 @@
import static uk.gov.di.ipv.core.library.auditing.helpers.AuditExtensionsHelper.getExtensionsForAudit;
import static uk.gov.di.ipv.core.library.auditing.helpers.AuditExtensionsHelper.getRestrictedAuditDataForInheritedIdentity;
import static uk.gov.di.ipv.core.library.config.ConfigurationVariable.JAR_KMS_ENCRYPTION_KEY_ID;
import static uk.gov.di.ipv.core.library.config.CoreFeatureFlag.EVCS_READ_ENABLED;
import static uk.gov.di.ipv.core.library.config.CoreFeatureFlag.EVCS_WRITE_ENABLED;
import static uk.gov.di.ipv.core.library.config.CoreFeatureFlag.MFA_RESET;
import static uk.gov.di.ipv.core.library.domain.CriConstants.HMRC_MIGRATION_CRI;
import static uk.gov.di.ipv.core.library.helpers.LogHelper.LogField.LOG_LAMBDA_RESULT;
Expand All @@ -87,6 +89,8 @@ public class InitialiseIpvSessionHandler
private static final List<Vot> HMRC_PROFILES_BY_STRENGTH = List.of(Vot.PCL250, Vot.PCL200);
private static final ErrorObject INVALID_INHERITED_IDENTITY_ERROR_OBJECT =
new ErrorObject("invalid_inherited_identity");
private static final ErrorObject EVCS_ACCESS_TOKEN_ERROR_OBJECT =
new ErrorObject("invalid_evcs_access_token");
private final ConfigService configService;
private final IpvSessionService ipvSessionService;
private final ClientOAuthSessionDetailsService clientOAuthSessionService;
Expand Down Expand Up @@ -133,6 +137,7 @@ public InitialiseIpvSessionHandler(
this.auditService = auditService;
}

@SuppressWarnings("java:S3776") // Cognitive Complexity of methods should not be too high
@Override
@Tracing
@Logging(clearState = true)
Expand Down Expand Up @@ -188,11 +193,21 @@ public APIGatewayProxyResponseEvent handleRequest(
ipvSessionService.generateIpvSession(
clientOAuthSessionId, null, emailAddress, isReverification);

Optional<JarUserInfo> jarUserInfoClaim = getJarUserInfo(claimsSet);
String evcsAccessToken = null;
if ((configService.enabled(EVCS_READ_ENABLED)
|| configService.enabled(EVCS_WRITE_ENABLED))
&& (jarUserInfoClaim.isPresent())) {
evcsAccessToken =
validateEvcsAccessToken(
jarUserInfoClaim.map(JarUserInfo::evcsAccessToken), claimsSet);
}
ClientOAuthSessionItem clientOAuthSessionItem =
clientOAuthSessionService.generateClientSessionDetails(
clientOAuthSessionId,
claimsSet,
sessionParams.get(CLIENT_ID_PARAM_KEY));
sessionParams.get(CLIENT_ID_PARAM_KEY),
evcsAccessToken);

AuditEventUser auditEventUser =
new AuditEventUser(
Expand All @@ -201,11 +216,11 @@ public APIGatewayProxyResponseEvent handleRequest(
govukSigninJourneyId,
ipAddress);

var inheritedIdentityJwtClaim = getInheritedIdentityClaim(claimsSet);
if (inheritedIdentityJwtClaim.isPresent()) {
if (configService.enabled(CoreFeatureFlag.INHERITED_IDENTITY)
&& (jarUserInfoClaim.isPresent())) {
validateAndStoreHMRCInheritedIdentity(
clientOAuthSessionItem.getUserId(),
inheritedIdentityJwtClaim.get(),
jarUserInfoClaim.map(JarUserInfo::inheritedIdentityClaim),
claimsSet,
ipvSessionItem,
auditEventUser,
Expand Down Expand Up @@ -291,17 +306,13 @@ public APIGatewayProxyResponseEvent handleRequest(
}
}

private Optional<InheritedIdentityJwtClaim> getInheritedIdentityClaim(JWTClaimsSet claimsSet)
private Optional<JarUserInfo> getJarUserInfo(JWTClaimsSet claimsSet)
throws ParseException, RecoverableJarValidationException {
if (!configService.enabled(CoreFeatureFlag.INHERITED_IDENTITY)) {
return Optional.empty();
}
try {
return Optional.ofNullable(
OBJECT_MAPPER.convertValue(
claimsSet.getJSONObjectClaim(CLAIMS_CLAIM), JarClaims.class))
.map(JarClaims::userInfo)
.map(JarUserInfo::inheritedIdentityClaim);
.map(JarClaims::userInfo);
} catch (IllegalArgumentException | ParseException e) {
throw new RecoverableJarValidationException(
OAuth2Error.INVALID_REQUEST_OBJECT.setDescription(
Expand All @@ -324,7 +335,7 @@ private static boolean isListEmpty(List<String> list) {
@Tracing
private void validateAndStoreHMRCInheritedIdentity(
String userId,
InheritedIdentityJwtClaim inheritedIdentityJwtClaim,
Optional<StringListClaim> inheritedIdentityJwtClaim,
JWTClaimsSet claimsSet,
IpvSessionItem ipvSessionItem,
AuditEventUser auditEventUser,
Expand All @@ -350,12 +361,54 @@ private void validateAndStoreHMRCInheritedIdentity(
}
}

@Tracing
private String validateEvcsAccessToken(
Optional<StringListClaim> evcsAccessTokenClaim, JWTClaimsSet claimsSet)
throws RecoverableJarValidationException, ParseException {
try {
// Validate JAR claims structure is valid
var evcsAccessTokenList =
Optional.ofNullable(
evcsAccessTokenClaim
.orElseThrow(
() ->
new JarValidationException(
EVCS_ACCESS_TOKEN_ERROR_OBJECT
.setDescription(
"Evcs access token jwt claim not received")))
.values())
.orElseThrow(
() ->
new JarValidationException(
EVCS_ACCESS_TOKEN_ERROR_OBJECT.setDescription(
"Evcs access token jwt claim received but value is null")));
if (evcsAccessTokenList.size() != 1) {
throw new JarValidationException(
EVCS_ACCESS_TOKEN_ERROR_OBJECT.setDescription(
String.format(
"%d EVCS access token received - one expected",
evcsAccessTokenList.size())));
}
return evcsAccessTokenList.get(0);
} catch (JarValidationException e) {
throw new RecoverableJarValidationException(e.getErrorObject(), claimsSet, e);
}
}

private VerifiableCredential validateHmrcInheritedIdentity(
String userId, InheritedIdentityJwtClaim inheritedIdentityJwtClaim)
String userId, Optional<StringListClaim> inheritedIdentityJwtClaim)
throws JarValidationException, ParseException, VerifiableCredentialException {
// Validate JAR claims structure is valid
var inheritedIdentityJwtList =
Optional.ofNullable(inheritedIdentityJwtClaim.values())
Optional.ofNullable(
inheritedIdentityJwtClaim
.orElseThrow(
() ->
new JarValidationException(
INVALID_INHERITED_IDENTITY_ERROR_OBJECT
.setDescription(
"Inherited identity jwt claim not received")))
.values())
.orElseThrow(
() ->
new JarValidationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import static uk.gov.di.ipv.core.library.domain.VocabConstants.ADDRESS_CLAIM_NAME;
import static uk.gov.di.ipv.core.library.domain.VocabConstants.CORE_IDENTITY_JWT_CLAIM_NAME;
import static uk.gov.di.ipv.core.library.domain.VocabConstants.EVCS_ACCESS_TOKEN_CLAIM_NAME;
import static uk.gov.di.ipv.core.library.domain.VocabConstants.INHERITED_IDENTITY_JWT_CLAIM_NAME;
import static uk.gov.di.ipv.core.library.domain.VocabConstants.PASSPORT_CLAIM_NAME;

Expand All @@ -13,5 +14,6 @@ public record JarUserInfo(
@JsonProperty(value = ADDRESS_CLAIM_NAME) Essential addressClaim,
@JsonProperty(value = CORE_IDENTITY_JWT_CLAIM_NAME) Essential coreIdentityJwtClaim,
@JsonProperty(value = INHERITED_IDENTITY_JWT_CLAIM_NAME)
InheritedIdentityJwtClaim inheritedIdentityClaim,
StringListClaim inheritedIdentityClaim,
@JsonProperty(value = EVCS_ACCESS_TOKEN_CLAIM_NAME) StringListClaim evcsAccessToken,
@JsonProperty(value = PASSPORT_CLAIM_NAME) Essential passportClaim) {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

import java.util.List;

public record InheritedIdentityJwtClaim(List<String> values) {}
public record StringListClaim(List<String> values) {}
Loading

0 comments on commit b90ba72

Please sign in to comment.