Search in sources :

Example 61 with Subject

use of com.nimbusds.oauth2.sdk.id.Subject in project di-authentication-api by alphagov.

the class TokenHandler method handleRequest.

@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
    return isWarming(input).orElseGet(() -> {
        LOG.info("Token request received");
        Optional<ErrorObject> invalidRequestParamError = tokenService.validateTokenRequestParams(input.getBody());
        if (invalidRequestParamError.isPresent()) {
            LOG.warn("Invalid Token Request. ErrorCode: {}. ErrorDescription: {}", invalidRequestParamError.get().getCode(), invalidRequestParamError.get().getDescription());
            return generateApiGatewayProxyResponse(400, invalidRequestParamError.get().toJSONObject().toJSONString());
        }
        Map<String, String> requestBody = parseRequestBody(input.getBody());
        String clientID = requestBody.get("client_id");
        ClientRegistry client;
        try {
            client = clientService.getClient(clientID).orElseThrow();
        } catch (NoSuchElementException e) {
            LOG.warn("Client not found in Client Registry with Client ID {}", clientID);
            return generateApiGatewayProxyResponse(400, OAuth2Error.INVALID_CLIENT.toJSONObject().toJSONString());
        }
        String baseUrl = configurationService.getBaseURL().orElseThrow(() -> {
            LOG.error("Application was not configured with baseURL");
            // exceptions
            return new RuntimeException("Application was not configured with baseURL");
        });
        String tokenUrl = buildURI(baseUrl, TOKEN_PATH).toString();
        Optional<ErrorObject> invalidPrivateKeyJwtError = tokenService.validatePrivateKeyJWT(input.getBody(), client.getPublicKey(), tokenUrl, clientID);
        if (invalidPrivateKeyJwtError.isPresent()) {
            LOG.warn("Private Key JWT is not valid for Client ID: {}", clientID);
            return generateApiGatewayProxyResponse(400, invalidPrivateKeyJwtError.get().toJSONObject().toJSONString());
        }
        if (requestBody.get("grant_type").equals(GrantType.REFRESH_TOKEN.getValue())) {
            LOG.info("Processing refresh token request");
            return processRefreshTokenRequest(requestBody, client.getScopes(), new RefreshToken(requestBody.get("refresh_token")));
        }
        AuthCodeExchangeData authCodeExchangeData;
        try {
            authCodeExchangeData = authorisationCodeService.getExchangeDataForCode(requestBody.get("code")).orElseThrow();
        } catch (NoSuchElementException e) {
            LOG.warn("Could not retrieve client session ID from code", e);
            return generateApiGatewayProxyResponse(400, OAuth2Error.INVALID_GRANT.toJSONObject().toJSONString());
        }
        ClientSession clientSession = clientSessionService.getClientSession(authCodeExchangeData.getClientSessionId());
        AuthenticationRequest authRequest;
        try {
            authRequest = AuthenticationRequest.parse(clientSession.getAuthRequestParams());
        } catch (ParseException e) {
            LOG.warn("Could not parse authentication request from client session", e);
            throw new RuntimeException(format("Unable to parse Auth Request\n Auth Request Params: %s \n Exception: %s", clientSession.getAuthRequestParams(), e));
        }
        if (!authRequest.getRedirectionURI().toString().equals(requestBody.get("redirect_uri"))) {
            LOG.warn("Redirect URI for auth request ({}) does not match redirect URI for request body ({})", authRequest.getRedirectionURI(), requestBody.get("redirect_uri"));
            return generateApiGatewayProxyResponse(400, OAuth2Error.INVALID_GRANT.toJSONObject().toJSONString());
        }
        UserProfile userProfile = dynamoService.getUserProfileByEmail(authCodeExchangeData.getEmail());
        Subject publicSubject = ClientSubjectHelper.getSubject(userProfile, client, dynamoService);
        Map<String, Object> additionalTokenClaims = new HashMap<>();
        if (authRequest.getNonce() != null) {
            additionalTokenClaims.put("nonce", authRequest.getNonce());
        }
        String vot = clientSession.getEffectiveVectorOfTrust().retrieveVectorOfTrustForToken();
        OIDCClaimsRequest claimsRequest = null;
        if (Objects.nonNull(clientSession.getEffectiveVectorOfTrust().getLevelOfConfidence()) && Objects.nonNull(authRequest.getOIDCClaims())) {
            claimsRequest = authRequest.getOIDCClaims();
        }
        var tokenResponse = tokenService.generateTokenResponse(clientID, new Subject(userProfile.getSubjectID()), authRequest.getScope(), additionalTokenClaims, publicSubject, vot, userProfile.getClientConsent(), client.isConsentRequired(), claimsRequest);
        clientSessionService.saveClientSession(authCodeExchangeData.getClientSessionId(), clientSession.setIdTokenHint(tokenResponse.getOIDCTokens().getIDToken().serialize()));
        LOG.info("Successfully generated tokens");
        return generateApiGatewayProxyResponse(200, tokenResponse.toJSONObject().toJSONString());
    });
}
Also used : UserProfile(uk.gov.di.authentication.shared.entity.UserProfile) HashMap(java.util.HashMap) ErrorObject(com.nimbusds.oauth2.sdk.ErrorObject) Subject(com.nimbusds.oauth2.sdk.id.Subject) AuthCodeExchangeData(uk.gov.di.authentication.shared.entity.AuthCodeExchangeData) OIDCClaimsRequest(com.nimbusds.openid.connect.sdk.OIDCClaimsRequest) RefreshToken(com.nimbusds.oauth2.sdk.token.RefreshToken) ClientSession(uk.gov.di.authentication.shared.entity.ClientSession) ClientRegistry(uk.gov.di.authentication.shared.entity.ClientRegistry) ErrorObject(com.nimbusds.oauth2.sdk.ErrorObject) ParseException(com.nimbusds.oauth2.sdk.ParseException) AuthenticationRequest(com.nimbusds.openid.connect.sdk.AuthenticationRequest) NoSuchElementException(java.util.NoSuchElementException)

Example 62 with Subject

use of com.nimbusds.oauth2.sdk.id.Subject in project di-authentication-api by alphagov.

the class UpdatePhoneNumberHandler method handleRequest.

@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
    return isWarming(input).orElseGet(() -> {
        String sessionId = RequestHeaderHelper.getHeaderValueOrElse(input.getHeaders(), SESSION_ID_HEADER, "");
        attachSessionIdToLogs(sessionId);
        LOG.info("UpdatePhoneNumberHandler received request");
        try {
            UpdatePhoneNumberRequest updatePhoneNumberRequest = objectMapper.readValue(input.getBody(), UpdatePhoneNumberRequest.class);
            boolean isValidOtpCode = codeStorageService.isValidOtpCode(updatePhoneNumberRequest.getEmail(), updatePhoneNumberRequest.getOtp(), NotificationType.VERIFY_PHONE_NUMBER);
            if (!isValidOtpCode) {
                return generateApiGatewayProxyErrorResponse(400, ErrorResponse.ERROR_1020);
            }
            Optional<ErrorResponse> phoneValidationErrors = validationService.validatePhoneNumber(updatePhoneNumberRequest.getPhoneNumber());
            if (phoneValidationErrors.isPresent()) {
                return generateApiGatewayProxyErrorResponse(400, phoneValidationErrors.get());
            }
            UserProfile userProfile = dynamoService.getUserProfileByEmail(updatePhoneNumberRequest.getEmail());
            Map<String, Object> authorizerParams = input.getRequestContext().getAuthorizer();
            RequestBodyHelper.validatePrincipal(new Subject(userProfile.getPublicSubjectID()), authorizerParams);
            dynamoService.updatePhoneNumber(updatePhoneNumberRequest.getEmail(), updatePhoneNumberRequest.getPhoneNumber());
            LOG.info("Phone Number has successfully been updated. Adding message to SQS queue");
            NotifyRequest notifyRequest = new NotifyRequest(updatePhoneNumberRequest.getEmail(), NotificationType.PHONE_NUMBER_UPDATED);
            sqsClient.send(objectMapper.writeValueAsString((notifyRequest)));
            auditService.submitAuditEvent(AccountManagementAuditableEvent.UPDATE_PHONE_NUMBER, context.getAwsRequestId(), sessionId, AuditService.UNKNOWN, userProfile.getSubjectID(), userProfile.getEmail(), IpAddressHelper.extractIpAddress(input), updatePhoneNumberRequest.getPhoneNumber(), PersistentIdHelper.extractPersistentIdFromHeaders(input.getHeaders()));
            LOG.info("Message successfully added to queue. Generating successful gateway response");
            return generateEmptySuccessApiGatewayResponse();
        } catch (JsonProcessingException | IllegalArgumentException e) {
            return generateApiGatewayProxyErrorResponse(400, ErrorResponse.ERROR_1001);
        }
    });
}
Also used : UserProfile(uk.gov.di.authentication.shared.entity.UserProfile) NotifyRequest(uk.gov.di.accountmanagement.entity.NotifyRequest) Subject(com.nimbusds.oauth2.sdk.id.Subject) ErrorResponse(uk.gov.di.authentication.shared.entity.ErrorResponse) ApiGatewayResponseHelper.generateApiGatewayProxyErrorResponse(uk.gov.di.authentication.shared.helpers.ApiGatewayResponseHelper.generateApiGatewayProxyErrorResponse) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) UpdatePhoneNumberRequest(uk.gov.di.accountmanagement.entity.UpdatePhoneNumberRequest)

Example 63 with Subject

use of com.nimbusds.oauth2.sdk.id.Subject in project di-authentication-api by alphagov.

the class UpdatePasswordHandler method handleRequest.

@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
    return isWarming(input).orElseGet(() -> {
        String sessionId = RequestHeaderHelper.getHeaderValueOrElse(input.getHeaders(), SESSION_ID_HEADER, "");
        attachSessionIdToLogs(sessionId);
        LOG.info("UpdatePasswordHandler received request");
        context.getClientContext();
        try {
            UpdatePasswordRequest updatePasswordRequest = objectMapper.readValue(input.getBody(), UpdatePasswordRequest.class);
            UserProfile userProfile = dynamoService.getUserProfileByEmail(updatePasswordRequest.getEmail());
            Map<String, Object> authorizerParams = input.getRequestContext().getAuthorizer();
            RequestBodyHelper.validatePrincipal(new Subject(userProfile.getPublicSubjectID()), authorizerParams);
            String currentPassword = dynamoService.getUserCredentialsFromEmail(updatePasswordRequest.getEmail()).getPassword();
            if (verifyPassword(currentPassword, updatePasswordRequest.getNewPassword())) {
                return generateApiGatewayProxyErrorResponse(400, ErrorResponse.ERROR_1024);
            }
            dynamoService.updatePassword(updatePasswordRequest.getEmail(), updatePasswordRequest.getNewPassword());
            LOG.info("User Password has successfully been updated.  Adding confirmation message to SQS queue");
            NotifyRequest notifyRequest = new NotifyRequest(updatePasswordRequest.getEmail(), NotificationType.PASSWORD_UPDATED);
            sqsClient.send(objectMapper.writeValueAsString((notifyRequest)));
            LOG.info("Message successfully added to queue. Generating successful gateway response");
            auditService.submitAuditEvent(AccountManagementAuditableEvent.UPDATE_PASSWORD, context.getAwsRequestId(), sessionId, AuditService.UNKNOWN, userProfile.getSubjectID(), userProfile.getEmail(), IpAddressHelper.extractIpAddress(input), userProfile.getPhoneNumber(), PersistentIdHelper.extractPersistentIdFromHeaders(input.getHeaders()));
            return generateEmptySuccessApiGatewayResponse();
        } catch (JsonProcessingException | IllegalArgumentException e) {
            return generateApiGatewayProxyErrorResponse(400, ErrorResponse.ERROR_1001);
        }
    });
}
Also used : UserProfile(uk.gov.di.authentication.shared.entity.UserProfile) UpdatePasswordRequest(uk.gov.di.accountmanagement.entity.UpdatePasswordRequest) NotifyRequest(uk.gov.di.accountmanagement.entity.NotifyRequest) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) Subject(com.nimbusds.oauth2.sdk.id.Subject)

Example 64 with Subject

use of com.nimbusds.oauth2.sdk.id.Subject in project di-authentication-api by alphagov.

the class RemoveAccountHandler method handleRequest.

@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
    return isWarming(input).orElseGet(() -> {
        try {
            String sessionId = RequestHeaderHelper.getHeaderValueOrElse(input.getHeaders(), SESSION_ID_HEADER, "");
            attachSessionIdToLogs(sessionId);
            LOG.info("RemoveAccountHandler received request");
            RemoveAccountRequest removeAccountRequest = objectMapper.readValue(input.getBody(), RemoveAccountRequest.class);
            String email = removeAccountRequest.getEmail();
            UserProfile userProfile = authenticationService.getUserProfileByEmailMaybe(email).orElseThrow(() -> new RuntimeException("User not found"));
            Map<String, Object> authorizerParams = input.getRequestContext().getAuthorizer();
            RequestBodyHelper.validatePrincipal(new Subject(userProfile.getPublicSubjectID()), authorizerParams);
            authenticationService.removeAccount(email);
            LOG.info("User account removed. Adding message to SQS queue");
            NotifyRequest notifyRequest = new NotifyRequest(email, NotificationType.DELETE_ACCOUNT);
            sqsClient.send(objectMapper.writeValueAsString((notifyRequest)));
            LOG.info("Remove account message successfully added to queue. Generating successful gateway response");
            auditService.submitAuditEvent(AccountManagementAuditableEvent.DELETE_ACCOUNT, context.getAwsRequestId(), sessionId, AuditService.UNKNOWN, userProfile.getSubjectID(), userProfile.getEmail(), IpAddressHelper.extractIpAddress(input), userProfile.getPhoneNumber(), PersistentIdHelper.extractPersistentIdFromHeaders(input.getHeaders()));
            return generateEmptySuccessApiGatewayResponse();
        } catch (JsonProcessingException e) {
            return generateApiGatewayProxyErrorResponse(400, ErrorResponse.ERROR_1001);
        }
    });
}
Also used : UserProfile(uk.gov.di.authentication.shared.entity.UserProfile) RemoveAccountRequest(uk.gov.di.accountmanagement.entity.RemoveAccountRequest) NotifyRequest(uk.gov.di.accountmanagement.entity.NotifyRequest) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) Subject(com.nimbusds.oauth2.sdk.id.Subject)

Example 65 with Subject

use of com.nimbusds.oauth2.sdk.id.Subject in project di-authentication-api by alphagov.

the class UserInfoServiceTest method createSignedAccessToken.

private AccessToken createSignedAccessToken(OIDCClaimsRequest identityClaims) throws JOSEException {
    var expiryDate = NowHelper.nowPlus(3, ChronoUnit.MINUTES);
    var ecSigningKey = new ECKeyGenerator(Curve.P_256).keyID(KEY_ID).algorithm(JWSAlgorithm.ES256).generate();
    var signer = new ECDSASigner(ecSigningKey);
    var signedJWT = TokenGeneratorHelper.generateSignedToken(CLIENT_ID, BASE_URL, SCOPES, signer, SUBJECT, ecSigningKey.getKeyID(), expiryDate, identityClaims);
    return new BearerAccessToken(signedJWT.serialize());
}
Also used : ECDSASigner(com.nimbusds.jose.crypto.ECDSASigner) ECKeyGenerator(com.nimbusds.jose.jwk.gen.ECKeyGenerator) BearerAccessToken(com.nimbusds.oauth2.sdk.token.BearerAccessToken)

Aggregations

Subject (com.nimbusds.oauth2.sdk.id.Subject)59 Test (org.junit.jupiter.api.Test)36 SignedJWT (com.nimbusds.jwt.SignedJWT)22 Date (java.util.Date)22 ApiGatewayHandlerIntegrationTest (uk.gov.di.authentication.sharedtest.basetest.ApiGatewayHandlerIntegrationTest)19 UserProfile (uk.gov.di.authentication.shared.entity.UserProfile)18 KeyPair (java.security.KeyPair)16 BearerAccessToken (com.nimbusds.oauth2.sdk.token.BearerAccessToken)15 JWTClaimsSet (com.nimbusds.jwt.JWTClaimsSet)13 ParseException (com.nimbusds.oauth2.sdk.ParseException)12 Scope (com.nimbusds.oauth2.sdk.Scope)12 APIGatewayProxyRequestEvent (com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent)11 APIGatewayProxyResponseEvent (com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent)11 AccessToken (com.nimbusds.oauth2.sdk.token.AccessToken)10 ECKeyGenerator (com.nimbusds.jose.jwk.gen.ECKeyGenerator)9 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)9 ECDSASigner (com.nimbusds.jose.crypto.ECDSASigner)8 Issuer (com.nimbusds.oauth2.sdk.id.Issuer)8 IDTokenClaimsSet (com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet)8 LocalDateTime (java.time.LocalDateTime)8