Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DTFS2-6892): move entra id to tfm api #3960

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6f01382
feat(dtfs2-6892): add api to upsert user
AlexBramhill Nov 25, 2024
70c1db3
feat(dtfs2-6892): add handle redirect to entra id service
AlexBramhill Nov 25, 2024
4dfd7dd
feat(dtfs2-6892): add user parital login data error
AlexBramhill Nov 27, 2024
51e6a20
Revert "feat(dtfs2-6892): add api to upsert user"
AlexBramhill Nov 27, 2024
eae68f8
Revert "feat(dtfs2-6892): add handle redirect to entra id service"
AlexBramhill Nov 27, 2024
9300c66
feat(dtfs2-6892): add login service
AlexBramhill Nov 27, 2024
d954593
feat(dtfs2-6892): add login service
AlexBramhill Nov 27, 2024
35fc108
feat(dtfs2-6892): add login service
AlexBramhill Nov 27, 2024
f973209
feat(dtfs2-6892): move entra to tfm api
AlexBramhill Nov 27, 2024
019ef20
feat(dtfs2-6892): move entra to tfm api
AlexBramhill Nov 27, 2024
9df20ed
feat(dtfs2-6892): move entra to tfm api
AlexBramhill Nov 27, 2024
6aa48cc
feat(dtfs2-6892): move entra to tfm api
AlexBramhill Nov 29, 2024
c036ea2
feat(dtfs2-6892): move entra to tfm api
AlexBramhill Nov 29, 2024
05ff7e4
Merge branch 'main' into feat/DTFS2-6892/add-frontend-upsert-user-fun…
AlexBramhill Nov 29, 2024
fda5a2d
Merge branch 'main' into feat/DTFS2-6892/add-frontend-upsert-user-fun…
AlexBramhill Dec 9, 2024
15ecd10
feat(DTFS2-6892): add object id schema for tfm sso (#4027)
AlexBramhill Jan 2, 2025
1bd2233
Merge branch 'main' into feat/DTFS2-6892/add-frontend-upsert-user-fun…
AlexBramhill Jan 3, 2025
4fe1900
Merge branch 'main' into feat/DTFS2-6892/add-frontend-upsert-user-fun…
AlexBramhill Jan 6, 2025
cd59c23
feat(dtfs2-6892): review comments
AlexBramhill Jan 7, 2025
9ebfdac
feat(dtfs2-6892): update to review comments
AlexBramhill Jan 14, 2025
3e80688
feat(dtfs2-6892): clarify how zod union works
AlexBramhill Jan 22, 2025
6c08a10
feat(dtfs2-6892): update to review comments
AlexBramhill Jan 22, 2025
4829ecc
feat(dtfs2-6892): add sso controller test
AlexBramhill Jan 23, 2025
3f94a37
feat(dtfs2-6892): update controller reroute, add tests
AlexBramhill Jan 23, 2025
f2e2f5e
feat(dtfs2-6892): uninstall msal node from tfm ui
AlexBramhill Jan 23, 2025
bbc537f
Merge branch 'main' into feat/DTFS2-6892/add-frontend-upsert-user-fun…
AlexBramhill Jan 23, 2025
ef3d702
Merge branch 'main' into feat/DTFS2-6892/add-frontend-upsert-user-fun…
AlexBramhill Jan 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion azure-functions/acbs-function/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ const baseRules = {
'no-underscore-dangle': [
'error',
{
allow: ['_id', '_csrf', '_getBuffer', '_getData', '_getHeaders', '_getStatusCode', '_getRedirectUrl', '_getRenderData', '_getRenderView', '_isEndCalled'],
allow: [
'_id',
'_csrf',
'_getBuffer',
'_getData',
'_getJSONData',
'_getHeaders',
'_getStatusCode',
'_getRedirectUrl',
'_getRenderData',
'_getRenderView',
'_isEndCalled',
],
},
],
'import/extensions': 'off',
Expand Down
14 changes: 13 additions & 1 deletion dtfs-central-api/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ const baseRules = {
'no-underscore-dangle': [
'error',
{
allow: ['_id', '_csrf', '_getBuffer', '_getData', '_getHeaders', '_getStatusCode', '_getRedirectUrl', '_getRenderData', '_getRenderView', '_isEndCalled'],
allow: [
'_id',
'_csrf',
'_getBuffer',
'_getData',
'_getJSONData',
'_getHeaders',
'_getStatusCode',
'_getRedirectUrl',
'_getRenderData',
'_getRenderView',
'_isEndCalled',
],
},
],
'import/extensions': 'off',
Expand Down
14 changes: 13 additions & 1 deletion e2e-tests/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ const baseRules = {
'no-underscore-dangle': [
'error',
{
allow: ['_id', '_csrf', '_getBuffer', '_getData', '_getHeaders', '_getStatusCode', '_getRedirectUrl', '_getRenderData', '_getRenderView', '_isEndCalled'],
allow: [
'_id',
'_csrf',
'_getBuffer',
'_getData',
'_getJSONData',
'_getHeaders',
'_getStatusCode',
'_getRedirectUrl',
'_getRenderData',
'_getRenderView',
'_isEndCalled',
],
},
],
'import/extensions': 'off',
Expand Down
14 changes: 13 additions & 1 deletion external-api/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ const baseRules = {
'no-underscore-dangle': [
'error',
{
allow: ['_id', '_csrf', '_getBuffer', '_getData', '_getHeaders', '_getStatusCode', '_getRedirectUrl', '_getRenderData', '_getRenderView', '_isEndCalled'],
allow: [
'_id',
'_csrf',
'_getBuffer',
'_getData',
'_getJSONData',
'_getHeaders',
'_getStatusCode',
'_getRedirectUrl',
'_getRenderData',
'_getRenderView',
'_isEndCalled',
],
},
],
'import/extensions': 'off',
Expand Down
14 changes: 13 additions & 1 deletion gef-ui/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ const baseRules = {
'no-underscore-dangle': [
'error',
{
allow: ['_id', '_csrf', '_getBuffer', '_getData', '_getHeaders', '_getStatusCode', '_getRedirectUrl', '_getRenderData', '_getRenderView', '_isEndCalled'],
allow: [
'_id',
'_csrf',
'_getBuffer',
'_getData',
'_getJSONData',
'_getHeaders',
'_getStatusCode',
'_getRedirectUrl',
'_getRenderData',
'_getRenderView',
'_isEndCalled',
],
},
],
'import/extensions': 'off',
Expand Down
14 changes: 13 additions & 1 deletion libs/common/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ const baseRules = {
'no-underscore-dangle': [
'error',
{
allow: ['_id', '_csrf', '_getBuffer', '_getData', '_getHeaders', '_getStatusCode', '_getRedirectUrl', '_getRenderData', '_getRenderView', '_isEndCalled'],
allow: [
'_id',
'_csrf',
'_getBuffer',
'_getData',
'_getJSONData',
'_getHeaders',
'_getStatusCode',
'_getRedirectUrl',
'_getRenderData',
'_getRenderView',
'_isEndCalled',
],
},
],
'import/extensions': 'off',
Expand Down
1 change: 1 addition & 0 deletions libs/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"unit-test-ff": "jest --coverage --verbose --config=unit.ff.jest.config.js --passWithNoTests"
},
"dependencies": {
"@azure/msal-node": "^2.16.2",
"axios": "1.7.8",
"big.js": "^6.2.2",
"date-fns": "^3.3.1",
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export * from './user-session.error';
export * from './user-session-not-defined.error';
export * from './user-token-not-defined.error';
export * from './multiple-users-found.error';
export * from './user-partial-login-data-not-defined.error';
export * from './amendment-not-found.error';
export * from './eligibility-criteria-not-found.error';
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { HttpStatusCode } from 'axios';
import { ApiError } from './api.error';
import { UserSessionError } from './user-session.error';
import { UserPartialLoginDataNotDefinedError } from './user-partial-login-data-not-defined.error';

describe('UserPartialLoginDataNotDefinedError', () => {
it('should expose the message the error was created with', () => {
// Act
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception.message).toEqual('Expected session.loginData to be defined');
});

it('should expose the 401 (Unauthorised) status code', () => {
// Act
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception.status).toEqual(HttpStatusCode.Unauthorized);
});

it('should expose the INVALID_USER_SESSION code', () => {
// Act
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception.code).toEqual('INVALID_USER_SESSION');
});

it('should be an instance of UserPartialLoginDataNotDefinedError', () => {
// Act
rkontogianni marked this conversation as resolved.
Show resolved Hide resolved
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception).toBeInstanceOf(UserPartialLoginDataNotDefinedError);
});

it('should be an instance of UserSessionError', () => {
// Act
rkontogianni marked this conversation as resolved.
Show resolved Hide resolved
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception).toBeInstanceOf(UserSessionError);
});

it('should be an instance of ApiError', () => {
// Act
rkontogianni marked this conversation as resolved.
Show resolved Hide resolved
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception).toBeInstanceOf(ApiError);
});

it('should expose the name of the exception', () => {
// Act
const exception = new UserPartialLoginDataNotDefinedError();

// Assert
expect(exception.name).toEqual('UserPartialLoginDataNotDefinedError');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { HttpStatusCode } from 'axios';
import { UserSessionError } from './user-session.error';

/**
* Error to use when a partially logged in user's session does not contain the expected data
*/
export class UserPartialLoginDataNotDefinedError extends UserSessionError {
constructor() {
super({
status: HttpStatusCode.Unauthorized,
message: 'Expected session.loginData to be defined',
});

this.name = this.constructor.name;
}
}
6 changes: 3 additions & 3 deletions libs/common/src/schemas/audit-database-record.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import z from 'zod';
import { ISO_DATE_TIME_STAMP } from './iso-date-time-stamp';
import { OBJECT_ID } from './object-id';
import { OBJECT_ID_OR_OBJECT_ID_STRING } from './object-id';

export const AUDIT_DATABASE_RECORD = z
.object({
lastUpdatedAt: ISO_DATE_TIME_STAMP,
lastUpdatedByPortalUserId: OBJECT_ID.nullable(),
lastUpdatedByTfmUserId: OBJECT_ID.nullable(),
lastUpdatedByPortalUserId: OBJECT_ID_OR_OBJECT_ID_STRING.nullable(),
lastUpdatedByTfmUserId: OBJECT_ID_OR_OBJECT_ID_STRING.nullable(),
lastUpdatedByIsSystem: z.boolean().nullable(),
noUserLoggedIn: z.boolean().nullable(),
})
Expand Down
2 changes: 1 addition & 1 deletion libs/common/src/schemas/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * as PORTAL_USER from './portal-user';
export * as ISO_DATE_TIME_STAMP from './iso-date-time-stamp';
export { OBJECT_ID } from './object-id';
export * from './object-id';
export * from './deal-cancellation';
export * from './tfm';
export * from './unix-timestamp.schema';
Expand Down
67 changes: 58 additions & 9 deletions libs/common/src/schemas/object-id.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,72 @@
import { ObjectId } from 'mongodb';
import { OBJECT_ID } from './object-id';
import { OBJECT_ID, OBJECT_ID_OR_OBJECT_ID_STRING, OBJECT_ID_STRING } from './object-id';
import { withSchemaTests } from '../test-helpers';

describe('OBJECT_ID', () => {
withSchemaTests({
successTestCases: getSuccessTestCases(),
failureTestCases: getFailureTestCases(),
successTestCases: getObjectIdSuccessTestCases(),
failureTestCases: getObjectIdSharedFailureTestCases(),
schema: OBJECT_ID,
});

it('should transform a valid string ObjectId to an ObjectId', () => {
const stringObjectId = new ObjectId().toString();

const result = OBJECT_ID.parse(stringObjectId);

expect(result).toEqual(new ObjectId(stringObjectId));
});
});

function getSuccessTestCases() {
return [
{ description: 'a valid ObjectId', aTestCase: () => new ObjectId() },
{ description: 'a valid string ObjectId', aTestCase: () => '075bcd157dcb851180e02a7c' },
];
describe('OBJECT_ID_STRING', () => {
withSchemaTests({
MarRobSoftwire marked this conversation as resolved.
Show resolved Hide resolved
successTestCases: getObjectIdStringSuccessTestCases(),
failureTestCases: getObjectIdSharedFailureTestCases(),
schema: OBJECT_ID_STRING,
});

it('should transform a valid ObjectId to a string', () => {
const objectId = new ObjectId();

const result = OBJECT_ID_STRING.parse(objectId);

expect(result).toEqual(objectId.toString());
});
});

describe('OBJECT_ID_OR_OBJECT_ID_STRING', () => {
withSchemaTests({
successTestCases: [...getObjectIdSuccessTestCases(), ...getObjectIdStringSuccessTestCases()],
failureTestCases: getObjectIdSharedFailureTestCases(),
schema: OBJECT_ID_OR_OBJECT_ID_STRING,
});

it('should not transform a valid ObjectId to a string', () => {
const objectId = new ObjectId();

const result = OBJECT_ID_OR_OBJECT_ID_STRING.parse(objectId);

expect(result).toEqual(objectId);
});

it('should not transform a valid string ObjectId to an ObjectId', () => {
const stringObjectId = new ObjectId().toString();

const result = OBJECT_ID_OR_OBJECT_ID_STRING.parse(stringObjectId);

expect(result).toEqual(stringObjectId);
});
});

function getObjectIdSuccessTestCases() {
return [{ description: 'a valid ObjectId', aTestCase: () => new ObjectId() }];
}

function getObjectIdStringSuccessTestCases() {
return [{ description: 'a valid string ObjectId', aTestCase: () => '075bcd157dcb851180e02a7c' }];
}

function getFailureTestCases() {
function getObjectIdSharedFailureTestCases() {
return [
{ description: 'a string', aTestCase: () => 'string' },
{ description: 'an object', aTestCase: () => ({ An: 'object' }) },
Expand Down
26 changes: 25 additions & 1 deletion libs/common/src/schemas/object-id.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
import { ObjectId } from 'mongodb';
import z from 'zod';

export const OBJECT_ID = z.union([z.instanceof(ObjectId), z.string().refine((id) => ObjectId.isValid(id))]);
/**
* A zod schema that represents a valid ObjectId as an ObjectId object
* This schema also transforms any valid string into an ObjectId object
*/
export const OBJECT_ID = z.union([
z.instanceof(ObjectId),
z
.string()
.refine((id) => ObjectId.isValid(id))
.transform((id) => new ObjectId(id)),
]);

/**
* A zod schema that represents a valid ObjectId as a string
* This schema also transforms any valid ObjectId object into a string
*/
export const OBJECT_ID_STRING = z.union([z.string().refine((id) => ObjectId.isValid(id)), z.instanceof(ObjectId).transform((id) => id.toString())]);

/**
* A zod schema that represents a valid ObjectId as an ObjectId object or a string
* This schema does not do any transformation, only validates.
* This is because we check to see if the value is an ObjectId prior to applying the OBJECT_ID_STRING
* schema, and zod union returns the first valid schema
*/
export const OBJECT_ID_OR_OBJECT_ID_STRING = z.union([z.instanceof(ObjectId), OBJECT_ID_STRING]);
ttbarnes marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { withSchemaTests } from '@ukef/dtfs2-common';
import { DecodedAuthCodeRequestState } from '../types/entra-id';
import { withSchemaTests } from '../../test-helpers';
import { DecodedAuthCodeRequestState } from '../../types/tfm/entra-id';
import { DECODED_AUTH_CODE_REQUEST_STATE_SCHEMA } from './entra-id.schema';

describe('DECODED_AUTH_CODE_REQUEST_STATE_SCHEMA', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { withSchemaTests } from '@ukef/dtfs2-common';
import { EntraIdAuthCodeRedirectResponseBody } from '../types/entra-id';
import { withSchemaTests } from '../../test-helpers';
import { EntraIdAuthCodeRedirectResponseBody } from '../../types/tfm/entra-id';
import { ENTRA_ID_AUTH_CODE_REDIRECT_RESPONSE_BODY_SCHEMA } from './entra-id.schema';

describe('ENTRA_ID_AUTH_CODE_REDIRECT_RESPONSE_BODY_SCHEMA', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { anEntraIdUser, withEntraIdUserSchemaTests, withSchemaTests } from '@ukef/dtfs2-common';
import { EntraIdAuthenticationResult } from '../types/entra-id';
import { anEntraIdUser, withEntraIdUserSchemaTests, withSchemaTests } from '../../test-helpers';
import { EntraIdAuthenticationResult } from '../../types/tfm/entra-id';
import { ENTRA_ID_AUTHENTICATION_RESULT_SCHEMA } from './entra-id.schema';

describe('ENTRA_ID_AUTHENTICATION_RESULT_SCHEMA', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ENTRA_ID_USER_SCHEMA } from '@ukef/dtfs2-common/schemas';
import { z } from 'zod';
import { ENTRA_ID_USER_SCHEMA } from './entra-id-user.schema';

export const DECODED_AUTH_CODE_REQUEST_STATE_SCHEMA = z.object({
csrfToken: z.string(),
Expand Down
3 changes: 2 additions & 1 deletion libs/common/src/schemas/tfm/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './entra-id-user.schema';
export * from './entra-id-user-to-upsert-tfm-user-request.schema';
export * from './entra-id.schema';
export * from './create-tfm-user-request.schema';
export * from './update-tfm-user-request.schema';
export * from './upsert-tfm-user-request.schema';
export * from './entra-id-user-to-upsert-tfm-user-request.schema';
export * from './tfm-team.schema';
Loading
Loading