All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.gov.di.ipv.cri.common.library.service.SessionService Maven / Gradle / Ivy

package uk.gov.di.ipv.cri.common.library.service;

import com.nimbusds.oauth2.sdk.token.AccessToken;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.lambda.powertools.logging.LoggingUtils;
import uk.gov.di.ipv.cri.common.library.annotations.ExcludeFromGeneratedCoverageReport;
import uk.gov.di.ipv.cri.common.library.domain.SessionRequest;
import uk.gov.di.ipv.cri.common.library.exception.AccessTokenExpiredException;
import uk.gov.di.ipv.cri.common.library.exception.AuthorizationCodeExpiredException;
import uk.gov.di.ipv.cri.common.library.exception.SessionExpiredException;
import uk.gov.di.ipv.cri.common.library.exception.SessionNotFoundException;
import uk.gov.di.ipv.cri.common.library.persistence.DataStore;
import uk.gov.di.ipv.cri.common.library.persistence.item.SessionItem;
import uk.gov.di.ipv.cri.common.library.util.ListUtil;

import java.time.Clock;
import java.util.Optional;
import java.util.UUID;

public class SessionService {
    private static final String SESSION_TABLE_PARAM_NAME = "SessionTableName";
    private static final String GOVUK_SIGNIN_JOURNEY_ID = "govuk_signin_journey_id";
    private static final String REQUESTED_VERIFICATION_SCORE = "requested_verification_score";
    private final ConfigurationService configurationService;
    private final DataStore dataStore;
    private final Clock clock;

    @ExcludeFromGeneratedCoverageReport
    public SessionService(
            ConfigurationService configurationService,
            DynamoDbEnhancedClient dynamoDbEnhancedClient) {
        this(
                new DataStore<>(
                        configurationService.getCommonParameterValue(SESSION_TABLE_PARAM_NAME),
                        SessionItem.class,
                        dynamoDbEnhancedClient),
                configurationService,
                Clock.systemUTC());
    }

    public SessionService(
            DataStore dataStore,
            ConfigurationService configurationService,
            Clock clock) {
        this.dataStore = dataStore;
        this.configurationService = configurationService;
        this.clock = clock;
    }

    public UUID saveSession(SessionRequest sessionRequest) {
        SessionItem sessionItem = new SessionItem();
        sessionItem.setCreatedDate(clock.instant().getEpochSecond());
        sessionItem.setExpiryDate(configurationService.getSessionExpirationEpoch());
        sessionItem.setState(sessionRequest.getState());
        sessionItem.setClientId(sessionRequest.getClientId());
        sessionItem.setEvidenceRequest(sessionRequest.getEvidenceRequest());
        sessionItem.setRedirectUri(sessionRequest.getRedirectUri());
        sessionItem.setSubject(sessionRequest.getSubject());
        sessionItem.setPersistentSessionId(sessionRequest.getPersistentSessionId());
        sessionItem.setClientSessionId(sessionRequest.getClientSessionId());
        sessionItem.setClientIpAddress(sessionRequest.getClientIpAddress());
        sessionItem.setAttemptCount(0);
        sessionItem.setContext(sessionRequest.getContext());
        setSessionItemsToLogging(sessionItem);

        dataStore.create(sessionItem);
        return sessionItem.getSessionId();
    }

    public void updateSession(SessionItem sessionItem) {
        setSessionItemsToLogging(sessionItem);
        dataStore.update(sessionItem);
    }

    public void createAuthorizationCode(SessionItem session) {
        session.setAuthorizationCode(UUID.randomUUID().toString());
        session.setAuthorizationCodeExpiryDate(
                configurationService.getAuthorizationCodeExpirationEpoch());
        updateSession(session);
    }

    public SessionItem validateSessionId(String sessionId)
            throws SessionNotFoundException, SessionExpiredException {

        SessionItem sessionItem = dataStore.getItem(sessionId);
        setSessionItemsToLogging(sessionItem);
        if (sessionItem == null) {
            throw new SessionNotFoundException("session not found");
        }

        if (sessionItem.getExpiryDate() < clock.instant().getEpochSecond()) {
            throw new SessionExpiredException("session expired");
        }

        return sessionItem;
    }

    private void setSessionItemsToLogging(SessionItem sessionItem) {
        Optional.ofNullable(sessionItem)
                .ifPresent(
                        s -> {
                            Optional.ofNullable(s.getClientSessionId())
                                    .ifPresent(
                                            id ->
                                                    LoggingUtils.appendKey(
                                                            GOVUK_SIGNIN_JOURNEY_ID, id));
                            Optional.ofNullable(s.getEvidenceRequest())
                                    .ifPresent(
                                            ev ->
                                                    LoggingUtils.appendKey(
                                                            REQUESTED_VERIFICATION_SCORE,
                                                            String.valueOf(
                                                                    ev.getVerificationScore())));
                        });
    }

    public SessionItem getSession(String sessionId) {
        SessionItem sessionItem = dataStore.getItem(sessionId);
        setSessionItemsToLogging(sessionItem);
        return sessionItem;
    }

    public SessionItem getSessionByAccessToken(AccessToken accessToken)
            throws SessionExpiredException, AccessTokenExpiredException, SessionNotFoundException {
        SessionItem sessionItem;

        try {
            sessionItem =
                    ListUtil.getOneItemOrThrowError(
                            dataStore.getItemByIndex(
                                    SessionItem.ACCESS_TOKEN_INDEX,
                                    accessToken.toAuthorizationHeader()));
        } catch (IllegalArgumentException e) {
            if (e.getMessage().contains("No items found")) {
                throw new SessionNotFoundException("no session found with that access token");
            } else {
                throw new SessionNotFoundException(
                        "more than one session found with that access token");
            }
        }

        // Re-fetch our session directly to avoid problems with projections
        sessionItem = validateSessionId(String.valueOf(sessionItem.getSessionId()));
        if (sessionItem.getAccessTokenExpiryDate() < clock.instant().getEpochSecond()) {
            throw new AccessTokenExpiredException("access code expired");
        }

        return sessionItem;
    }

    public SessionItem getSessionByAuthorisationCode(String authCode)
            throws SessionExpiredException, AuthorizationCodeExpiredException,
                    SessionNotFoundException {
        SessionItem sessionItem;

        try {
            sessionItem =
                    ListUtil.getOneItemOrThrowError(
                            dataStore.getItemByIndex(
                                    SessionItem.AUTHORIZATION_CODE_INDEX, authCode));
        } catch (IllegalArgumentException e) {
            if (e.getMessage().contains("No items found")) {
                throw new SessionNotFoundException("no session found with that authorization code");
            } else {
                throw new SessionNotFoundException(
                        "more than one session found with that authorization code");
            }
        }

        // Re-fetch our session directly to avoid problems with projections
        sessionItem = validateSessionId(String.valueOf(sessionItem.getSessionId()));

        if (sessionItem.getAuthorizationCodeExpiryDate() < clock.instant().getEpochSecond()) {
            throw new AuthorizationCodeExpiredException("authorization code expired");
        }

        return sessionItem;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy