Skip to content

Commit

Permalink
AUT-2760 adding functionality to skip "prove your identity welcome"
Browse files Browse the repository at this point in the history
  • Loading branch information
VladGavrilet authored and dbes-gds committed May 31, 2024
1 parent fdc4144 commit 03e9e4e
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 40 deletions.
4 changes: 4 additions & 0 deletions ci/terraform/ecs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ locals {
name = "LANGUAGE_TOGGLE_ENABLED"
value = var.language_toggle_enabled
},
{
name = "PROVE_IDENTITY_WELCOME_ENABLED"
value = var.prove_identity_welcome_enabled
},
{
name = "GA4_DISABLED"
value = var.ga4_disabled
Expand Down
12 changes: 9 additions & 3 deletions ci/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ variable "support_check_email_fraud" {
default = "0"
}

variable "prove_identity_welcome_enabled" {
description = "Do not show the prove identity welcome screen when disabled"
type = string
default = "1"
}

variable "email_entered_wrong_blocked_minutes" {
description = "The duration, in minutes, for which a user is blocked after entering the wrong email multiple times during reauthentication"
default = "15"
Expand Down Expand Up @@ -285,7 +291,7 @@ variable "rate_limited_endpoints_requests_per_period" {
default = 100000
}

#cloudfront variable
#cloudfront variable
variable "cloudfront_auth_frontend_enabled" {
type = bool
default = false
Expand Down Expand Up @@ -340,7 +346,7 @@ variable "cloudfront_WafAcl_Logdestination" {
default = "none"
description = "CSLS logging destinatiin for logging Cloufront CloakingOriginWebACL WAf logs "
}
#end of cloudfront variable
#end of cloudfront variable

variable "language_toggle_enabled" {
type = string
Expand Down Expand Up @@ -376,4 +382,4 @@ variable "analytics_cookie_domain" {
type = string
default = ""
description = "Analytics cookie domain where cookie is set"
}
}
2 changes: 2 additions & 0 deletions src/components/authorize/authorize-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { appendQueryParamIfHasValue } from "../../utils/url";
import {
getOrchToAuthExpectedClientId,
supportReauthentication,
proveIdentityWelcomeEnabled,
} from "../../config";
import { logger } from "../../utils/logger";
import { Claims } from "./claims-config";
Expand Down Expand Up @@ -137,6 +138,7 @@ export function authorizeGet(
skipAuthentication: req.session.user.docCheckingAppUser,
mfaMethodType: startAuthResponse.data.user.mfaMethodType,
isReauthenticationRequired: req.session.user.reauthenticate,
proveIdentityWelcomeEnabled: proveIdentityWelcomeEnabled(),
},
sessionId
);
Expand Down
53 changes: 37 additions & 16 deletions src/components/authorize/tests/authorize-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,25 +177,46 @@ describe("authorize controller", () => {

expect(res.redirect).to.have.calledWith(PATH_NAMES.AUTH_CODE);
});
it("should redirect to /identity page when identity check required and prove identity welcome is enabled", async () => {
process.env.PROVE_IDENTITY_WELCOME_ENABLED = "1";
it("should redirect to /identity page when identity check required", async () => {
authServiceResponseData.data.user = {
identityRequired: true,
upliftRequired: false,
authenticated: true,
};
fakeAuthorizeService = mockAuthService(authServiceResponseData);

it("should redirect to /identity page when identity check required", async () => {
authServiceResponseData.data.user = {
identityRequired: true,
upliftRequired: false,
authenticated: true,
};
fakeAuthorizeService = mockAuthService(authServiceResponseData);
await authorizeGet(
fakeAuthorizeService,
fakeCookieConsentService,
fakeKmsDecryptionService,
fakeJwtService
)(req as Request, res as Response);

await authorizeGet(
fakeAuthorizeService,
fakeCookieConsentService,
fakeKmsDecryptionService,
fakeJwtService
)(req as Request, res as Response);
expect(res.redirect).to.have.calledWith(
PATH_NAMES.PROVE_IDENTITY_WELCOME
);
});

expect(res.redirect).to.have.calledWith(
PATH_NAMES.PROVE_IDENTITY_WELCOME
);
it("should redirect to /sign-in-or-create page when identity check required and prove identity welcome is not enabled", async () => {
process.env.PROVE_IDENTITY_WELCOME_ENABLED = "0";
authServiceResponseData.data.user = {
identityRequired: true,
upliftRequired: false,
authenticated: false,
};
fakeAuthorizeService = mockAuthService(authServiceResponseData);

await authorizeGet(
fakeAuthorizeService,
fakeCookieConsentService,
fakeKmsDecryptionService,
fakeJwtService
)(req as Request, res as Response);

expect(res.redirect).to.have.calledWith(PATH_NAMES.SIGN_IN_OR_CREATE);
});
});

it("should redirect to sign in when reauthentication is requested and user is not authenticated and support reauthenticate feature flag is on", async () => {
Expand Down
13 changes: 11 additions & 2 deletions src/components/common/state-machine/state-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
OIDC_PROMPT,
PATH_NAMES,
} from "../../../app.constants";
import { proveIdentityWelcomeEnabled } from "../../../config";

const USER_JOURNEY_EVENTS = {
AUTHENTICATED: "AUTHENTICATED",
Expand Down Expand Up @@ -78,6 +79,7 @@ const authStateMachine = createMachine(
requiresResetPasswordMFASmsCode: false,
requiresResetPasswordMFAAuthAppCode: false,
isOnForcedPasswordResetJourney: false,
proveIdentityWelcomeEnabled: proveIdentityWelcomeEnabled(),
},
states: {
[PATH_NAMES.ROOT]: {
Expand All @@ -92,7 +94,7 @@ const authStateMachine = createMachine(
[USER_JOURNEY_EVENTS.EXISTING_SESSION]: [
{
target: [PATH_NAMES.PROVE_IDENTITY_WELCOME],
cond: "isIdentityRequired",
cond: "isIdentityRequiredAndProveIdentityWelcomeEnabled",
},
{ target: [PATH_NAMES.ENTER_PASSWORD], cond: "requiresLogin" },
{
Expand All @@ -104,6 +106,10 @@ const authStateMachine = createMachine(
target: [PATH_NAMES.ENTER_EMAIL_SIGN_IN],
cond: "isReauthenticationRequired",
},
{
target: [PATH_NAMES.PROVE_IDENTITY],
cond: "isIdentityRequired",
},
{ target: [PATH_NAMES.AUTH_CODE], cond: "isAuthenticated" },
],
[USER_JOURNEY_EVENTS.NO_EXISTING_SESSION]: [
Expand All @@ -117,7 +123,7 @@ const authStateMachine = createMachine(
},
{
target: [PATH_NAMES.PROVE_IDENTITY_WELCOME],
cond: "isIdentityRequired",
cond: "isIdentityRequiredAndProveIdentityWelcomeEnabled",
},
{ target: [PATH_NAMES.SIGN_IN_OR_CREATE] },
],
Expand Down Expand Up @@ -742,6 +748,9 @@ const authStateMachine = createMachine(
skipAuthentication: (context) =>
context.skipAuthentication === true &&
context.isAuthenticated === false,
isIdentityRequiredAndProveIdentityWelcomeEnabled: (context) =>
context.isIdentityRequired === true &&
context.proveIdentityWelcomeEnabled === true,
requiresMFAAuthAppCode: (context) =>
context.mfaMethodType === MFA_METHOD_TYPE.AUTH_APP &&
context.requiresTwoFactorAuth === true,
Expand Down
94 changes: 94 additions & 0 deletions src/components/common/state-machine/tests/state-machine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,99 @@ import { getNextState, USER_JOURNEY_EVENTS } from "../state-machine";
import { MFA_METHOD_TYPE, PATH_NAMES } from "../../../../app.constants";

describe("state-machine", () => {
describe(`getNextState - ${PATH_NAMES.AUTHORIZE} on ${USER_JOURNEY_EVENTS.EXISTING_SESSION}`, () => {
describe("where isIdentityRequired", () => {
it(`should move from ${PATH_NAMES.AUTHORIZE} to ${PATH_NAMES.PROVE_IDENTITY_WELCOME}`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.EXISTING_SESSION,
{
isIdentityRequired: true,
proveIdentityWelcomeEnabled: true,
}
);

expect(nextState.value).to.equal(PATH_NAMES.PROVE_IDENTITY_WELCOME);
});

it(`should move from ${PATH_NAMES.AUTHORIZE} to ${PATH_NAMES.PROVE_IDENTITY}`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.EXISTING_SESSION,
{
isIdentityRequired: true,
proveIdentityWelcomeEnabled: false,
}
);

expect(nextState.value).to.equal(PATH_NAMES.PROVE_IDENTITY);
});
it(`should stay on ${PATH_NAMES.AUTHORIZE}`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.EXISTING_SESSION,
{ isIdentityRequired: false, proveIdentityWelcomeEnabled: false }
);
expect(nextState.value).to.equal(PATH_NAMES.AUTHORIZE);
});
it(`should move from ${PATH_NAMES.AUTHORIZE} to ${PATH_NAMES.ENTER_EMAIL_SIGN_IN}`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.EXISTING_SESSION,
{
isIdentityRequired: true,
proveIdentityWelcomeEnabled: false,
isAuthenticated: true,
isReauthenticationRequired: true,
}
);
expect(nextState.value).to.equal(PATH_NAMES.ENTER_EMAIL_SIGN_IN);
});
it(`should move from ${PATH_NAMES.AUTHORIZE} to ${PATH_NAMES.PROVE_IDENTITY}`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.EXISTING_SESSION,
{
isIdentityRequired: true,
isAuthenticated: true,
isReauthenticationRequired: false,
proveIdentityWelcomeEnabled: false,
}
);
expect(nextState.value).to.equal(PATH_NAMES.PROVE_IDENTITY);
});
});
});

describe(`getNextState - ${PATH_NAMES.AUTHORIZE} on ${USER_JOURNEY_EVENTS.NO_EXISTING_SESSION}`, () => {
describe("where isIdentityRequired", () => {
it(`should move from ${PATH_NAMES.AUTHORIZE} to ${PATH_NAMES.PROVE_IDENTITY_WELCOME} proveIdentityWelcomeEnabled is true`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.NO_EXISTING_SESSION,
{
isIdentityRequired: true,
proveIdentityWelcomeEnabled: true,
}
);

expect(nextState.value).to.equal(PATH_NAMES.PROVE_IDENTITY_WELCOME);
});

it(`should move from ${PATH_NAMES.AUTHORIZE} to ${PATH_NAMES.SIGN_IN_OR_CREATE} proveIdentityWelcomeEnabled is false`, () => {
const nextState = getNextState(
PATH_NAMES.AUTHORIZE,
USER_JOURNEY_EVENTS.NO_EXISTING_SESSION,
{
isIdentityRequired: true,
proveIdentityWelcomeEnabled: false,
}
);

expect(nextState.value).to.equal(PATH_NAMES.SIGN_IN_OR_CREATE);
});
});
});
describe("getNextState - login journey (2fa)", () => {
it("should move from initial state to sign or create when user event is landing", () => {
const nextState = getNextState(PATH_NAMES.ROOT, USER_JOURNEY_EVENTS.ROOT);
Expand Down Expand Up @@ -43,6 +136,7 @@ describe("state-machine", () => {
expect(nextState.value).to.equal(PATH_NAMES.AUTH_CODE);
});
});

describe("getNextState - login journey (non 2fa)", () => {
it("should move from initial state to sign or create when user event is landing", () => {
const nextState = getNextState(PATH_NAMES.ROOT, USER_JOURNEY_EVENTS.ROOT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { Request, Response } from "express";
import { getNextPathAndUpdateJourney } from "../common/constants";
import { USER_JOURNEY_EVENTS } from "../common/state-machine/state-machine";
import { PATH_NAMES } from "../../app.constants";

import { proveIdentityWelcomeEnabled } from "../../config";
export function proveIdentityWelcomeGet(req: Request, res: Response): void {
res.render(
req.session.user.isAuthenticated
? "prove-identity-welcome/index-existing-session.njk"
: "prove-identity-welcome/index.njk"
);
if (!proveIdentityWelcomeEnabled()) {
res.redirect("/sign-in-or-create");
} else {
res.render(
req.session.user.isAuthenticated
? "prove-identity-welcome/index-existing-session.njk"
: "prove-identity-welcome/index.njk"
);
}
}

export async function proveIdentityWelcomePost(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,31 @@ describe("prove your identity welcome controller", () => {
});

describe("proveIdentityWelcomeGet", () => {
it("should render prove your identity welcome page", async () => {
it("should render prove your identity welcome page when page enabled", async () => {
process.env.PROVE_IDENTITY_WELCOME_ENABLED = "1";
proveIdentityWelcomeGet(req as Request, res as Response);

expect(res.render).to.have.been.calledWith(
"prove-identity-welcome/index.njk"
);
});

it("should render prove identity welcome page for user that already has an active session", async () => {
req.session.user.isAuthenticated = true;
it("should redirect to sign-in-or-create from prove your identity welcome page when not enabled", async () => {
process.env.PROVE_IDENTITY_WELCOME_ENABLED = "0";
proveIdentityWelcomeGet(req as Request, res as Response);
expect(res.redirect).to.have.been.calledWith(
PATH_NAMES.SIGN_IN_OR_CREATE
);
});

it("should render prove identity welcome page for user that already has an active session if page enabled", async () => {
req.session.user.isAuthenticated = true;
process.env.PROVE_IDENTITY_WELCOME_ENABLED = "1";
proveIdentityWelcomeGet(req as Request, res as Response);
expect(res.render).to.have.been.calledWith(
"prove-identity-welcome/index-existing-session.njk"
);
});
});

describe("proveIdentityWelcomePost", () => {
it("should redirect to sign in or create when user not authenticated", async () => {
await proveIdentityWelcomePost(req as Request, res as Response);
Expand Down
3 changes: 3 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,6 @@ export function googleAnalytics4Disabled(): string {
export function universalAnalyticsDisabled(): string {
return process.env.UA_DISABLED || "false";
}
export function proveIdentityWelcomeEnabled(): boolean {
return process.env.PROVE_IDENTITY_WELCOME_ENABLED === "1";
}
9 changes: 1 addition & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2626,20 +2626,13 @@ [email protected]:
dependencies:
ms "2.0.0"

debug@4, [email protected], debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
debug@4, [email protected], debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

decache@^4.6.1:
version "4.6.1"
resolved "https://registry.npmjs.org/decache/-/decache-4.6.1.tgz"
Expand Down

0 comments on commit 03e9e4e

Please sign in to comment.