@defra-fish/gafl-webapp-service
Version:
The websales frontend for the GAFL service
187 lines (169 loc) • 7.67 kB
JavaScript
import { initialise, signIn } from '../oidc-handler.js'
import OpenIdClient from 'openid-client'
import { salesApi } from '@defra-fish/connectors-lib'
import {
setupEnvironment,
mockSettings,
mockOidcClient,
mockCache,
mockServer,
mockOidcClientConstructor
} from '../../__mocks__/openid-client.js'
jest.mock('@defra-fish/connectors-lib')
describe('oidc handler', () => {
beforeAll(setupEnvironment)
describe('initialise', () => {
it('initialises authentication on the hapi server', async () => {
await expect(initialise(mockServer)).resolves.toBeUndefined()
expect(OpenIdClient.Issuer.discover).toHaveBeenCalledWith(mockSettings.ENV.OIDC_ENDPOINT)
expect(mockOidcClientConstructor).toHaveBeenCalledWith({
client_id: mockSettings.ENV.OIDC_CLIENT_ID,
client_secret: mockSettings.ENV.OIDC_CLIENT_SECRET,
redirect_uris: [`${mockSettings.ENV.OIDC_REDIRECT_HOST}/oidc/signin`],
response_types: ['code', 'id_token']
})
expect(mockServer.cache).toHaveBeenCalledWith({ expiresIn: 43200000, segment: 'oidc' })
expect(mockServer.auth.default).toHaveBeenCalledWith('oidc')
expect(mockServer.auth.strategy).toHaveBeenCalledWith('oidc', 'cookie', {
cookie: {
name: mockSettings.ENV.OIDC_SESSION_COOKIE_NAME,
password: mockSettings.ENV.OIDC_SESSION_COOKIE_PASSWORD,
ttl: null,
isSecure: process.env.NODE_ENV !== 'development',
isHttpOnly: process.env.NODE_ENV !== 'development',
isSameSite: 'Lax',
path: '/'
},
redirectTo: expect.any(Function),
validateFunc: expect.any(Function)
})
const redirectHandler = mockServer.auth.strategy.mock.calls[0][2].redirectTo
const validationHandler = mockServer.auth.strategy.mock.calls[0][2].validateFunc
expect(redirectHandler({ path: '/original/path', cookieAuth: { clear: jest.fn() } })).toEqual(mockSettings.TEST_AUTH_ENDPOINT)
expect(mockOidcClient.authorizationUrl).toHaveBeenCalledWith({
response_mode: 'form_post',
response_type: 'code id_token',
scope: 'openid profile email',
state: mockSettings.TEST_STATE,
nonce: mockSettings.TEST_NONCE,
domain_hint: 'defra.gov.uk'
})
await expect(validationHandler({}, {})).resolves.toEqual({ valid: false })
await expect(validationHandler({}, { oid: mockSettings.TEST_OID })).resolves.toEqual({
valid: true,
credentials: { oid: mockSettings.TEST_OID }
})
})
})
describe('signIn', () => {
beforeEach(async () => {
await expect(initialise(mockServer)).resolves.toBeUndefined()
})
it('redirects to the page requested prior to authentication on success', async () => {
const fakeRequest = {
payload: {
id_token: 'sample_token',
state: mockSettings.TEST_STATE
},
cookieAuth: {
set: jest.fn(),
ttl: jest.fn()
}
}
const fakeHandler = { redirectWithLanguageCode: jest.fn() }
salesApi.getSystemUser.mockResolvedValue({
id: '26449770-5e67-e911-a988-000d3ab9df39',
oid: 'e4661642-0a25-4d49-b7bd-8178699e0161',
firstName: 'Sam',
lastName: 'Gardner-Dell',
isDisabled: false,
roles: [
{
id: 'cf333fee-79b8-e611-80e7-c4346bac7e3c',
name: mockSettings.ENV.OIDC_REQUIRE_DYNAMICS_ROLE
}
]
})
await expect(signIn(fakeRequest, fakeHandler)).resolves.toBeUndefined()
expect(fakeRequest.cookieAuth.set).toHaveBeenCalledWith({
oid: mockSettings.TEST_OID,
name: mockSettings.TEST_NAME,
email: mockSettings.TEST_EMAIL
})
expect(fakeRequest.cookieAuth.ttl).toHaveBeenCalledWith(expect.any(Number))
expect(fakeHandler.redirectWithLanguageCode).toHaveBeenCalledWith(mockSettings.TEST_POST_AUTH_REDIRECT)
})
it('redirects to /oidc/role-required if the user does not have the required role set in Dynamics', async () => {
const fakeRequest = {
payload: { id_token: 'sample_token', state: mockSettings.TEST_STATE },
cookieAuth: { set: jest.fn(), ttl: jest.fn() }
}
const fakeHandler = { redirectWithLanguageCode: jest.fn() }
salesApi.getSystemUser.mockResolvedValue({
id: '26449770-5e67-e911-a988-000d3ab9df39',
oid: 'e4661642-0a25-4d49-b7bd-8178699e0161',
firstName: 'Sam',
lastName: 'Gardner-Dell',
isDisabled: false,
roles: [
{
id: 'cf333fee-79b8-e611-80e7-c4346bac7e3c',
name: 'Not the correct role'
}
]
})
await expect(signIn(fakeRequest, fakeHandler)).resolves.toBeUndefined()
expect(fakeRequest.cookieAuth.set).not.toHaveBeenCalled()
expect(fakeRequest.cookieAuth.ttl).not.toHaveBeenCalled()
expect(fakeHandler.redirectWithLanguageCode).toHaveBeenCalledWith('/oidc/role-required')
})
it('redirects to /oidc/account-disabled if the user account is not recognised in Dynamics', async () => {
const fakeRequest = {
payload: { id_token: 'sample_token', state: 'test_stored_state' },
cookieAuth: { set: jest.fn(), ttl: jest.fn() }
}
const fakeHandler = { redirectWithLanguageCode: jest.fn() }
salesApi.getSystemUser.mockResolvedValue(null)
await expect(signIn(fakeRequest, fakeHandler)).resolves.toBeUndefined()
expect(fakeRequest.cookieAuth.set).not.toHaveBeenCalled()
expect(fakeRequest.cookieAuth.ttl).not.toHaveBeenCalled()
expect(fakeHandler.redirectWithLanguageCode).toHaveBeenCalledWith('/oidc/account-disabled')
})
it('redirects to /oidc/account-disabled if the user account has been set to disabled in Dynamics', async () => {
const fakeRequest = {
payload: { id_token: 'sample_token', state: 'test_stored_state' },
cookieAuth: { set: jest.fn(), ttl: jest.fn() }
}
const fakeHandler = { redirectWithLanguageCode: jest.fn() }
salesApi.getSystemUser.mockResolvedValue({
id: '26449770-5e67-e911-a988-000d3ab9df39',
oid: 'e4661642-0a25-4d49-b7bd-8178699e0161',
firstName: 'Sam',
lastName: 'Gardner-Dell',
isDisabled: true,
roles: [
{
id: 'cf333fee-79b8-e611-80e7-c4346bac7e3c',
name: 'Fish CRM - Telesales'
}
]
})
await expect(signIn(fakeRequest, fakeHandler)).resolves.toBeUndefined()
expect(fakeRequest.cookieAuth.set).not.toHaveBeenCalled()
expect(fakeRequest.cookieAuth.ttl).not.toHaveBeenCalled()
expect(fakeHandler.redirectWithLanguageCode).toHaveBeenCalledWith('/oidc/account-disabled')
})
it('throws errors authenticating the token back up the stack', async () => {
mockOidcClient.callback.mockRejectedValue(new Error('error validating jwt token'))
mockCache.get.mockResolvedValue(null)
const fakeRequest = { payload: { id_token: 'sample_token', state: mockSettings.TEST_STATE } }
const fakeHandler = { redirectWithLanguageCode: jest.fn() }
await expect(signIn(fakeRequest, fakeHandler)).rejects.toThrow('error validating jwt token')
})
it('throws a 500 error if the payload does not contain an id_token', async () => {
const fakeRequest = { payload: { error: 'ERROR_CODE', error_description: 'Something went wrong' } }
const fakeHandler = { redirectWithLanguageCode: jest.fn() }
await expect(signIn(fakeRequest, fakeHandler)).rejects.toThrow('Authentication error: ERROR_CODE: Something went wrong')
})
})
})