diff --git a/backend/functions/azure/application-context-creator.test.ts b/backend/functions/azure/application-context-creator.test.ts index 40b073e0b..15e76a094 100644 --- a/backend/functions/azure/application-context-creator.test.ts +++ b/backend/functions/azure/application-context-creator.test.ts @@ -2,7 +2,7 @@ import MockData from '../../../common/src/cams/test-utilities/mock-data'; import { ApplicationContext } from '../lib/adapters/types/basic'; import * as FeatureFlags from '../lib/adapters/utils/feature-flag'; import { ApplicationConfiguration } from '../lib/configs/application-configuration'; -import { MockUserSessionGateway } from '../lib/testing/mock-gateways/mock-user-session-gateway'; +import { MockUserSessionUseCase } from '../lib/testing/mock-gateways/mock-user-session-use-case'; import { createMockApplicationContext } from '../lib/testing/testing-utilities'; import ContextCreator from './application-context-creator'; import { createMockAzureFunctionContext, createMockAzureFunctionRequest } from './testing-helpers'; @@ -78,7 +78,7 @@ describe('Application Context Creator', () => { const mockContext = await createMockApplicationContext(); mockContext.request = request; const lookupSpy = jest - .spyOn(MockUserSessionGateway.prototype, 'lookup') + .spyOn(MockUserSessionUseCase.prototype, 'lookup') .mockResolvedValue(MockData.getCamsSession()); await ContextCreator.getApplicationContextSession(mockContext); expect(lookupSpy).toHaveBeenCalled(); diff --git a/backend/functions/azure/application-context-creator.ts b/backend/functions/azure/application-context-creator.ts index adedcfbf5..abe589cee 100644 --- a/backend/functions/azure/application-context-creator.ts +++ b/backend/functions/azure/application-context-creator.ts @@ -6,8 +6,7 @@ import { getFeatureFlags } from '../lib/adapters/utils/feature-flag'; import { LoggerImpl } from '../lib/adapters/services/logger.service'; import { azureToCamsHttpRequest } from './functions'; import { UnauthorizedError } from '../lib/common-errors/unauthorized-error'; -import { getUserSessionGateway } from '../lib/factory'; -import { SessionGateway } from '../lib/adapters/utils/session-gateway'; +import { getUserSessionUseCase } from '../lib/factory'; const MODULE_NAME = 'APPLICATION-CONTEXT-CREATOR'; @@ -77,8 +76,8 @@ async function getApplicationContextSession(context: ApplicationContext) { }); } - const sessionGateway: SessionGateway = getUserSessionGateway(context); - const session = await sessionGateway.lookup( + const sessionUseCase = getUserSessionUseCase(context); + const session = await sessionUseCase.lookup( context, accessToken, context.config.authConfig.provider, diff --git a/backend/functions/lib/adapters/gateways/okta/okta-gateway.test.ts b/backend/functions/lib/adapters/gateways/okta/okta-gateway.test.ts index c667b0efc..722027348 100644 --- a/backend/functions/lib/adapters/gateways/okta/okta-gateway.test.ts +++ b/backend/functions/lib/adapters/gateways/okta/okta-gateway.test.ts @@ -31,7 +31,7 @@ describe('Okta gateway tests', () => { userInfoUri: 'something', }; jest.spyOn(AuthorizationConfiguration, 'getAuthorizationConfig').mockReturnValue(authConfig); - await expect(gateway.verifyToken('test')).rejects.toThrow('Invalid provider.'); + await expect(gateway.getUser('test')).rejects.toThrow('Invalid provider.'); }); test('Should receive invalid issuer error', async () => { @@ -42,7 +42,7 @@ describe('Okta gateway tests', () => { userInfoUri: 'something', }; jest.spyOn(AuthorizationConfiguration, 'getAuthorizationConfig').mockReturnValue(authConfig); - await expect(gateway.verifyToken('test')).rejects.toThrow('Issuer not provided.'); + await expect(gateway.getUser('test')).rejects.toThrow('Issuer not provided.'); }); test('Should receive invalid audience error', async () => { @@ -53,10 +53,10 @@ describe('Okta gateway tests', () => { userInfoUri: 'something', }; jest.spyOn(AuthorizationConfiguration, 'getAuthorizationConfig').mockReturnValue(authConfig); - await expect(gateway.verifyToken('test')).rejects.toThrow('Audience not provided.'); + await expect(gateway.getUser('test')).rejects.toThrow('Audience not provided.'); }); - test('Should return valid Jwt when given valid token and audience', async () => { + test('Should return valid user with Jwt when given valid token and audience', async () => { const token = 'testToken'; const jwtClaims = { iss: 'https://fake.okta.com/oauth2/default', @@ -64,7 +64,8 @@ describe('Okta gateway tests', () => { aud: 'api://default', iat: 0, exp: Math.floor(Date.now() / 1000) + 600, - groups: [], + ad_groups: ['groupA', 'groupB'], + groups: ['groupB', 'groupC'], }; const jwtHeader = { alg: 'RS256', @@ -79,27 +80,24 @@ describe('Okta gateway tests', () => { isNotBefore: jest.fn(), }; jest.spyOn(Verifier, 'verifyAccessToken').mockResolvedValue(jwt); - const actual = await gateway.verifyToken(token); - expect(actual).toEqual(jwt); - }); - - test('Should throw UnauthorizedError if not given valid input ', async () => { - const token = 'testToken'; - jest.spyOn(Verifier, 'verifyAccessToken').mockRejectedValue(new Error('Test error')); - await expect(gateway.verifyToken(token)).rejects.toThrow('Unauthorized'); - }); - - test('getUser should return a valid response with user.name', async () => { const userInfo = { name: 'Test Name', testAttribute: '', }; const mockFetchResponse = MockFetch.ok(userInfo); jest.spyOn(global, 'fetch').mockImplementation(mockFetchResponse); - const actualResponse = await gateway.getUser('testAccessToken'); + const actual = await gateway.getUser(token); + expect(actual).toEqual({ + user: { id: undefined, name: userInfo.name }, + groups: ['groupA', 'groupB', 'groupC'], + jwt, + }); + }); - expect(actualResponse).not.toEqual(expect.objectContaining({ testAttribute: '' })); - expect(actualResponse).toEqual(expect.objectContaining({ name: 'Test Name' })); + test('Should throw UnauthorizedError if not given valid input ', async () => { + const token = 'testToken'; + jest.spyOn(Verifier, 'verifyAccessToken').mockRejectedValue(new Error('Test error')); + await expect(gateway.getUser(token)).rejects.toThrow('Unauthorized'); }); test('getUser should throw Error if call failed', async () => { diff --git a/backend/functions/lib/adapters/gateways/okta/okta-gateway.ts b/backend/functions/lib/adapters/gateways/okta/okta-gateway.ts index 9abf8ff56..43214d2e9 100644 --- a/backend/functions/lib/adapters/gateways/okta/okta-gateway.ts +++ b/backend/functions/lib/adapters/gateways/okta/okta-gateway.ts @@ -5,6 +5,7 @@ import { UnauthorizedError } from '../../../common-errors/unauthorized-error'; import { verifyAccessToken } from './HumbleVerifier'; import { CamsUser } from '../../../../../../common/src/cams/users'; import { CamsJwt } from '../../../../../../common/src/cams/jwt'; +import { isCamsError } from '../../../common-errors/cams-error'; const MODULE_NAME = 'OKTA-GATEWAY'; @@ -43,10 +44,19 @@ async function verifyToken(token: string): Promise { } } -async function getUser(accessToken: string): Promise { +async function getUser( + accessToken: string, +): Promise<{ user: CamsUser; groups: string[]; jwt: CamsJwt }> { const { userInfoUri } = getAuthorizationConfig(); try { + const jwt = await verifyToken(accessToken); + if (!jwt) { + throw new UnauthorizedError(MODULE_NAME, { + message: 'Unable to verify token.', + }); + } + const response = await fetch(userInfoUri, { method: 'GET', headers: { authorization: 'Bearer ' + accessToken }, @@ -54,23 +64,31 @@ async function getUser(accessToken: string): Promise { if (response.ok) { const oktaUser = (await response.json()) as OktaUserInfo; - // TODO: We need to decide on the claim we will map to CamsUser.id - const camsUser: CamsUser = { + const user: CamsUser = { id: oktaUser.sub, name: oktaUser.name, }; - return camsUser; + type DojLoginUnifiedGroupClaims = { + ad_groups?: string[]; + groups?: string[]; + }; + + const claims = jwt.claims as unknown as DojLoginUnifiedGroupClaims; + const groups = Array.from(new Set([].concat(claims.ad_groups, claims.groups))); + + return { user, groups, jwt }; } else { throw new Error('Failed to retrieve user info from Okta.'); } } catch (originalError) { - throw new UnauthorizedError(MODULE_NAME, { originalError }); + throw isCamsError(originalError) + ? originalError + : new UnauthorizedError(MODULE_NAME, { originalError }); } } const OktaGateway: OpenIdConnectGateway = { - verifyToken, getUser, }; diff --git a/backend/functions/lib/adapters/types/authorization.ts b/backend/functions/lib/adapters/types/authorization.ts index 263e8c3b7..644558961 100644 --- a/backend/functions/lib/adapters/types/authorization.ts +++ b/backend/functions/lib/adapters/types/authorization.ts @@ -9,8 +9,7 @@ export type AuthorizationConfig = { }; export interface OpenIdConnectGateway { - verifyToken: (accessToken: string) => Promise; - getUser: (accessToken: string) => Promise; + getUser: (accessToken: string) => Promise<{ user: CamsUser; groups: string[]; jwt: CamsJwt }>; } export interface UserGroupGateway { diff --git a/backend/functions/lib/adapters/utils/session-gateway.ts b/backend/functions/lib/adapters/utils/session-gateway.ts deleted file mode 100644 index 84d6a7365..000000000 --- a/backend/functions/lib/adapters/utils/session-gateway.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CamsSession } from '../../../../../common/src/cams/session'; -import { ApplicationContext } from '../types/basic'; - -export interface SessionGateway { - lookup: (context: ApplicationContext, token: string, provider: string) => Promise; -} diff --git a/backend/functions/lib/factory.ts b/backend/functions/lib/factory.ts index db147da6a..1d0594c5d 100644 --- a/backend/functions/lib/factory.ts +++ b/backend/functions/lib/factory.ts @@ -32,9 +32,7 @@ import { OpenIdConnectGateway, UserGroupGateway } from './adapters/types/authori import OktaGateway from './adapters/gateways/okta/okta-gateway'; import { UserSessionCacheRepository } from './adapters/gateways/user-session-cache.repository'; import { UserSessionCacheCosmosDbRepository } from './adapters/gateways/user-session-cache.cosmosdb.repository'; -import { SessionGateway } from './adapters/utils/session-gateway'; -import { UserSessionGateway } from './adapters/gateways/user-session-gateway'; -import { MockUserSessionGateway } from './testing/mock-gateways/mock-user-session-gateway'; +import { MockUserSessionUseCase } from './testing/mock-gateways/mock-user-session-use-case'; import MockOpenIdConnectGateway from './testing/mock-gateways/mock-oauth2-gateway'; import { StorageGateway } from './adapters/types/storage'; import LocalStorageGateway from './adapters/gateways/storage/local-storage-gateway'; @@ -43,6 +41,7 @@ import { MockOrdersGateway } from './testing/mock-gateways/mock.orders.gateway'; import { MockOfficesGateway } from './testing/mock-gateways/mock.offices.gateway'; import { OfficesCosmosDbRepository } from './adapters/gateways/offices.cosmosdb.repository'; import OktaUserGroupGateway from './adapters/gateways/okta/okta-user-group-gateway'; +import { UserSessionUseCase } from './use-cases/user-session/user-session'; export const getAttorneyGateway = (): AttorneyGatewayInterface => { return MockAttorneysGateway; @@ -147,11 +146,11 @@ export const getAuthorizationGateway = (context: ApplicationContext): OpenIdConn return null; }; -export const getUserSessionGateway = (context: ApplicationContext): SessionGateway => { +export const getUserSessionUseCase = (context: ApplicationContext) => { if (context.config.authConfig.provider === 'mock') { - return new MockUserSessionGateway(); + return new MockUserSessionUseCase(); } - return new UserSessionGateway(); + return new UserSessionUseCase(); }; export const getUserSessionCacheRepository = ( diff --git a/backend/functions/lib/testing/mock-gateways/mock-oauth2-gateway.ts b/backend/functions/lib/testing/mock-gateways/mock-oauth2-gateway.ts index 7b35c1e33..bfce19cb8 100644 --- a/backend/functions/lib/testing/mock-gateways/mock-oauth2-gateway.ts +++ b/backend/functions/lib/testing/mock-gateways/mock-oauth2-gateway.ts @@ -65,11 +65,10 @@ export async function getUser(accessToken: string) { const decodedToken = jwt.decode(accessToken); const mockUser = mockUsers.find((role) => role.sub === decodedToken.sub); addSuperUserOffices(mockUser.user); - return mockUser.user; + return { user: mockUser.user, groups: [], jwt: {} as CamsJwt }; } const MockOpenIdConnectGateway: OpenIdConnectGateway = { - verifyToken, getUser, }; diff --git a/backend/functions/lib/testing/mock-gateways/mock-user-session-gateway.ts b/backend/functions/lib/testing/mock-gateways/mock-user-session-use-case.ts similarity index 88% rename from backend/functions/lib/testing/mock-gateways/mock-user-session-gateway.ts rename to backend/functions/lib/testing/mock-gateways/mock-user-session-use-case.ts index d9f0fea91..36ac8212f 100644 --- a/backend/functions/lib/testing/mock-gateways/mock-user-session-gateway.ts +++ b/backend/functions/lib/testing/mock-gateways/mock-user-session-use-case.ts @@ -1,6 +1,5 @@ import * as jwt from 'jsonwebtoken'; import { ApplicationContext } from '../../adapters/types/basic'; -import { SessionGateway } from '../../adapters/utils/session-gateway'; import { getUser } from './mock-oauth2-gateway'; import { OFFICES } from '../../../../../common/src/cams/test-utilities/offices.mock'; import { CamsSession } from '../../../../../common/src/cams/session'; @@ -9,13 +8,13 @@ import { CamsJwtClaims } from '../../../../../common/src/cams/jwt'; const cache = new Map(); -export class MockUserSessionGateway implements SessionGateway { +export class MockUserSessionUseCase { async lookup( context: ApplicationContext, accessToken: string, provider: string, ): Promise { - const user = await getUser(accessToken); + const { user } = await getUser(accessToken); const parts = accessToken.split('.'); const key = parts[2]; diff --git a/backend/functions/lib/adapters/gateways/user-session-gateway.test.ts b/backend/functions/lib/use-cases/user-session/user-session.test.ts similarity index 75% rename from backend/functions/lib/adapters/gateways/user-session-gateway.test.ts rename to backend/functions/lib/use-cases/user-session/user-session.test.ts index b3cbd7baa..b3f6b60e6 100644 --- a/backend/functions/lib/adapters/gateways/user-session-gateway.test.ts +++ b/backend/functions/lib/use-cases/user-session/user-session.test.ts @@ -1,5 +1,5 @@ -import { ConflictError, isConflictError, UserSessionGateway } from './user-session-gateway'; -import { ApplicationContext } from '../types/basic'; +import { ConflictError, isConflictError, UserSessionUseCase } from './user-session'; +import { ApplicationContext } from '../../adapters/types/basic'; import { createMockApplicationContext } from '../../testing/testing-utilities'; import { MockHumbleItems, MockHumbleQuery } from '../../testing/mock.cosmos-client-humble'; import { MockData } from '../../../../../common/src/cams/test-utilities/mock-data'; @@ -11,11 +11,12 @@ import { CamsRole } from '../../../../../common/src/cams/roles'; import { urlRegex } from '../../../../../common/src/cams/test-utilities/regex'; import { OFFICES } from '../../../../../common/src/cams/test-utilities/offices.mock'; import { CamsJwtHeader } from '../../../../../common/src/cams/jwt'; -import { UserSessionCacheCosmosDbRepository } from './user-session-cache.cosmosdb.repository'; +import { UserSessionCacheCosmosDbRepository } from '../../adapters/gateways/user-session-cache.cosmosdb.repository'; import MockOpenIdConnectGateway from '../../testing/mock-gateways/mock-oauth2-gateway'; +import * as Verifier from '../../adapters/gateways/okta/HumbleVerifier'; describe('user-session.gateway test', () => { - const jwt = MockData.getJwt(); + const jwtString = MockData.getJwt(); const claims = { iss: 'https://nonsense-3wjj23473kdwh2.okta.com/oauth2/default', sub: 'user@fake.com', @@ -28,23 +29,23 @@ describe('user-session.gateway test', () => { const mockUser = MockData.getCamsUser(); const expectedSession = MockData.getCamsSession({ user: mockUser, - accessToken: jwt, + accessToken: jwtString, provider, }); const mockCamsSession: CamsSession = { user: { id: 'userId-Wrong Name', name: 'Wrong Name' }, - accessToken: jwt, + accessToken: jwtString, provider, issuer: 'http://issuer/', expires: Number.MAX_SAFE_INTEGER, }; let context: ApplicationContext; - let gateway: UserSessionGateway; + let gateway: UserSessionUseCase; beforeEach(async () => { - gateway = new UserSessionGateway(); + gateway = new UserSessionUseCase(); context = await createMockApplicationContext({ - env: { CAMS_LOGIN_PROVIDER: 'mock', CAMS_LOGIN_PROVIDER_CONFIG: 'something' }, + env: { CAMS_LOGIN_PROVIDER: 'okta', CAMS_LOGIN_PROVIDER_CONFIG: 'something' }, }); const jwtHeader = { @@ -52,11 +53,14 @@ describe('user-session.gateway test', () => { typ: undefined, kid: '', }; - jest.spyOn(MockOpenIdConnectGateway, 'verifyToken').mockResolvedValue({ + const camsJwt = { claims, header: jwtHeader as CamsJwtHeader, - }); - jest.spyOn(MockOpenIdConnectGateway, 'getUser').mockResolvedValue(mockUser); + }; + jest.spyOn(Verifier, 'verifyAccessToken').mockResolvedValue(camsJwt); + jest + .spyOn(MockOpenIdConnectGateway, 'getUser') + .mockResolvedValue({ user: mockUser, groups: [], jwt: camsJwt }); }); afterEach(() => { @@ -68,7 +72,7 @@ describe('user-session.gateway test', () => { const createSpy = jest .spyOn(UserSessionCacheCosmosDbRepository.prototype, 'put') .mockResolvedValue(mockCamsSession); - const session = await gateway.lookup(context, jwt, provider); + const session = await gateway.lookup(context, jwtString, provider); expect(session).toEqual({ ...expectedSession, expires: expect.any(Number), @@ -84,7 +88,7 @@ describe('user-session.gateway test', () => { const createSpy = jest .spyOn(UserSessionCacheCosmosDbRepository.prototype, 'put') .mockRejectedValue('We should not call this function.'); - const session = await gateway.lookup(context, jwt, provider); + const session = await gateway.lookup(context, jwtString, provider); expect(session).toEqual({ ...expectedSession, expires: expect.any(Number), @@ -98,10 +102,10 @@ describe('user-session.gateway test', () => { resources: [], }); jest - .spyOn(MockOpenIdConnectGateway, 'verifyToken') - .mockRejectedValue(new UnauthorizedError('TEST_USER_SESSION_GATEWAY')); + .spyOn(MockOpenIdConnectGateway, 'getUser') + .mockRejectedValue(new UnauthorizedError('test-module')); const createSpy = jest.spyOn(MockHumbleItems.prototype, 'create'); - await expect(gateway.lookup(context, jwt, provider)).rejects.toThrow(); + await expect(gateway.lookup(context, jwtString, provider)).rejects.toThrow(); expect(createSpy).not.toHaveBeenCalled(); }); @@ -109,16 +113,24 @@ describe('user-session.gateway test', () => { jest.spyOn(MockHumbleQuery.prototype, 'fetchAll').mockResolvedValue({ resources: [], }); - jest.spyOn(MockOpenIdConnectGateway, 'verifyToken').mockResolvedValue(null); - await expect(gateway.lookup(context, jwt, provider)).rejects.toThrow(UnauthorizedError); + jest.spyOn(MockOpenIdConnectGateway, 'getUser').mockResolvedValue({ + user: mockUser, + groups: [], + jwt: null, + }); + await expect(gateway.lookup(context, jwtString, provider)).rejects.toThrow(UnauthorizedError); }); test('should handle undefined jwt from authGateway', async () => { jest.spyOn(MockHumbleQuery.prototype, 'fetchAll').mockResolvedValue({ resources: [], }); - jest.spyOn(MockOpenIdConnectGateway, 'verifyToken').mockResolvedValue(undefined); - await expect(gateway.lookup(context, jwt, provider)).rejects.toThrow(UnauthorizedError); + jest.spyOn(MockOpenIdConnectGateway, 'getUser').mockResolvedValue({ + user: mockUser, + groups: [], + jwt: undefined, + }); + await expect(gateway.lookup(context, jwtString, provider)).rejects.toThrow(UnauthorizedError); }); test('should return valid session and NOT add to cache when Conflict error is received', async () => { @@ -139,9 +151,9 @@ describe('user-session.gateway test', () => { .spyOn(UserSessionCacheCosmosDbRepository.prototype, 'get') .mockResolvedValueOnce(null) .mockResolvedValue(mockCamsSession); - jest.spyOn(MockOpenIdConnectGateway, 'verifyToken').mockRejectedValue(conflictError); + jest.spyOn(MockOpenIdConnectGateway, 'getUser').mockRejectedValue(conflictError); const createSpy = jest.spyOn(MockHumbleItems.prototype, 'create'); - const session = await gateway.lookup(context, jwt, provider); + const session = await gateway.lookup(context, jwtString, provider); expect(session).toEqual({ ...mockCamsSession, expires: expect.any(Number), @@ -171,9 +183,9 @@ describe('user-session.gateway test', () => { jest.spyOn(MockHumbleQuery.prototype, 'fetchAll').mockResolvedValue({ resources: [], }); - jest.spyOn(MockOpenIdConnectGateway, 'verifyToken').mockRejectedValue(new Error('Test error')); + jest.spyOn(MockOpenIdConnectGateway, 'getUser').mockRejectedValue(new Error('Test error')); const createSpy = jest.spyOn(MockHumbleItems.prototype, 'create'); - await expect(gateway.lookup(context, jwt, provider)).rejects.toThrow(UnauthorizedError); + await expect(gateway.lookup(context, jwtString, provider)).rejects.toThrow(UnauthorizedError); expect(createSpy).not.toHaveBeenCalled(); }); @@ -182,7 +194,7 @@ describe('user-session.gateway test', () => { resources: [], }); jest.spyOn(factoryModule, 'getAuthorizationGateway').mockReturnValue(null); - await expect(gateway.lookup(context, jwt, provider)).rejects.toThrow(ServerConfigError); + await expect(gateway.lookup(context, jwtString, provider)).rejects.toThrow(ServerConfigError); }); test('should use legacy behavior if restrict-case-assignment feature flag is not set', async () => { @@ -196,7 +208,7 @@ describe('user-session.gateway test', () => { const localContext = { ...context, featureFlags: { ...context.featureFlags } }; localContext.featureFlags['restrict-case-assignment'] = false; - const session = await gateway.lookup(localContext, jwt, provider); + const session = await gateway.lookup(localContext, jwtString, provider); expect(session.user.offices).toEqual([ OFFICES.find((office) => office.courtDivisionCode === '081'), ]); diff --git a/backend/functions/lib/adapters/gateways/user-session-gateway.ts b/backend/functions/lib/use-cases/user-session/user-session.ts similarity index 80% rename from backend/functions/lib/adapters/gateways/user-session-gateway.ts rename to backend/functions/lib/use-cases/user-session/user-session.ts index db01a293d..1cb08085d 100644 --- a/backend/functions/lib/adapters/gateways/user-session-gateway.ts +++ b/backend/functions/lib/use-cases/user-session/user-session.ts @@ -1,15 +1,14 @@ -import { SessionGateway } from '../utils/session-gateway'; import { getAuthorizationGateway, getOfficesGateway, getUserSessionCacheRepository, } from '../../factory'; -import { ApplicationContext } from '../types/basic'; +import { ApplicationContext } from '../../adapters/types/basic'; import { UnauthorizedError } from '../../common-errors/unauthorized-error'; import { isCamsError } from '../../common-errors/cams-error'; import { ServerConfigError } from '../../common-errors/server-config-error'; import { OfficeDetails } from '../../../../../common/src/cams/courts'; -import LocalStorageGateway from './storage/local-storage-gateway'; +import LocalStorageGateway from '../../adapters/gateways/storage/local-storage-gateway'; import { OFFICES } from '../../../../../common/src/cams/test-utilities/offices.mock'; import { CamsRole } from '../../../../../common/src/cams/roles'; import { CamsSession } from '../../../../../common/src/cams/session'; @@ -73,7 +72,7 @@ async function getOffices( return offices; } -export class UserSessionGateway implements SessionGateway { +export class UserSessionUseCase { async lookup(context: ApplicationContext, token: string, provider: string): Promise { const sessionCacheRepository = getUserSessionCacheRepository(context); const cached = await sessionCacheRepository.get(context, token); @@ -89,20 +88,14 @@ export class UserSessionGateway implements SessionGateway { message: 'Unsupported authentication provider.', }); } - const jwt = await authGateway.verifyToken(token); - if (!jwt) { - throw new UnauthorizedError(MODULE_NAME, { - message: 'Unable to verify token.', - }); - } - const user = await authGateway.getUser(token); + + const { user, groups, jwt } = await authGateway.getUser(token); + user.roles = getRoles(groups); + user.offices = await getOffices(context, groups); // Simulate the legacy behavior by appending roles and Manhattan office to the user // if the 'restrict-case-assignment' feature flag is not set. - if (context.featureFlags['restrict-case-assignment']) { - user.roles = getRoles(jwt.claims.groups); - user.offices = await getOffices(context, jwt.claims.groups); - } else { + if (!context.featureFlags['restrict-case-assignment']) { user.offices = [OFFICES.find((office) => office.courtDivisionCode === '081')]; user.roles = [CamsRole.CaseAssignmentManager]; } @@ -123,14 +116,12 @@ export class UserSessionGateway implements SessionGateway { return await sessionCacheRepository.get(context, token); } - if (isCamsError(originalError)) { - throw originalError; - } - - throw new UnauthorizedError(MODULE_NAME, { - message: originalError.message, - originalError, - }); + throw isCamsError(originalError) + ? originalError + : new UnauthorizedError(MODULE_NAME, { + message: originalError.message, + originalError, + }); } } }