From 5c9a2abdcc37625b904d06de9a0cc334a345bb1e Mon Sep 17 00:00:00 2001 From: jimbali <40831617+jimbali@users.noreply.github.com> Date: Fri, 6 Oct 2023 09:29:23 +0100 Subject: [PATCH] MAP-305: Use HMPPS Manage Users API for user details (#650) This has been split out into a new API. It was once part of HMPPS Auth. --- feature.env | 1 + helm_deploy/use-of-force/templates/_envs.tpl | 3 ++ helm_deploy/values-dev.yaml | 1 + helm_deploy/values-preprod.yaml | 1 + helm_deploy/values-prod.yaml | 1 + integration-tests/mockApis/auth.js | 8 ++-- server/config.js | 7 +++ server/data/authClient.test.ts | 45 ++++++++++++-------- server/data/authClient.ts | 13 +++--- 9 files changed, 53 insertions(+), 27 deletions(-) diff --git a/feature.env b/feature.env index 5deeb834..7b96967e 100644 --- a/feature.env +++ b/feature.env @@ -5,6 +5,7 @@ PRISON_API_URL=http://localhost:9091 PRISONER_SEARCH_API_URL=http://localhost:9091/search TOKENVERIFICATION_API_URL=http://localhost:9091/token-verification-api TOKENVERIFICATION_API_ENABLED=true +HMPPS_MANAGE_USERS_API_URL=http://localhost:9091 DB_NAME=use-of-force-int DB_PORT=5432 diff --git a/helm_deploy/use-of-force/templates/_envs.tpl b/helm_deploy/use-of-force/templates/_envs.tpl index 81157666..3b8923c7 100644 --- a/helm_deploy/use-of-force/templates/_envs.tpl +++ b/helm_deploy/use-of-force/templates/_envs.tpl @@ -94,6 +94,9 @@ env: - name: NOMIS_AUTH_URL value: {{ .Values.env.NOMIS_AUTH_URL | quote }} + - name: HMPPS_MANAGE_USERS_API_URL + value: {{ .Values.env.HMPPS_MANAGE_USERS_API_URL | quote }} + - name: PRISON_API_URL value: {{ .Values.env.PRISON_API_URL | quote }} diff --git a/helm_deploy/values-dev.yaml b/helm_deploy/values-dev.yaml index ec04375d..198d5f99 100644 --- a/helm_deploy/values-dev.yaml +++ b/helm_deploy/values-dev.yaml @@ -27,3 +27,4 @@ env: DPS_URL: https://digital-dev.prison.service.justice.gov.uk/ COMPONENT_API_URL: "https://frontend-components-dev.hmpps.service.justice.gov.uk" ENVIRONMENT_NAME: 'DEV' + HMPPS_MANAGE_USERS_API_URL: https://manage-users-api-dev.hmpps.service.justice.gov.uk diff --git a/helm_deploy/values-preprod.yaml b/helm_deploy/values-preprod.yaml index 33c048d7..e8892a70 100644 --- a/helm_deploy/values-preprod.yaml +++ b/helm_deploy/values-preprod.yaml @@ -27,6 +27,7 @@ env: DPS_URL: https://digital-preprod.prison.service.justice.gov.uk/ COMPONENT_API_URL: "https://frontend-components-preprod.hmpps.service.justice.gov.uk" ENVIRONMENT_NAME: 'PRE-PRODUCTION' + HMPPS_MANAGE_USERS_API_URL: https://manage-users-api-preprod.hmpps.service.justice.gov.uk allow_list: office: "217.33.148.210/32" diff --git a/helm_deploy/values-prod.yaml b/helm_deploy/values-prod.yaml index 237835ac..68c90b93 100644 --- a/helm_deploy/values-prod.yaml +++ b/helm_deploy/values-prod.yaml @@ -27,6 +27,7 @@ env: DPS_URL: https://digital.prison.service.justice.gov.uk/ COMPONENT_API_URL: "https://frontend-components.hmpps.service.justice.gov.uk" ENVIRONMENT_NAME: '' + HMPPS_MANAGE_USERS_API_URL: https://manage-users-api.hmpps.service.justice.gov.uk allow_list: office: "217.33.148.210/32" diff --git a/integration-tests/mockApis/auth.js b/integration-tests/mockApis/auth.js index eb035117..b9b8ff60 100644 --- a/integration-tests/mockApis/auth.js +++ b/integration-tests/mockApis/auth.js @@ -152,7 +152,7 @@ const stubUser = username => stubFor({ request: { method: 'GET', - urlPattern: `/auth/api/user/${encodeURI(username)}`, + urlPattern: `/users/${encodeURI(username)}`, }, response: { status: 200, @@ -175,7 +175,7 @@ const stubFindUser = (firstName, lastName, results) => stubFor({ request: { method: 'GET', - urlPattern: `/auth/api/prisonuser\\?firstName=${encodeURI(firstName)}&lastName=${encodeURI(lastName)}`, + urlPattern: `/prisonusers\\?firstName=${encodeURI(firstName)}&lastName=${encodeURI(lastName)}`, }, response: { status: 200, @@ -198,7 +198,7 @@ const stubEmail = username => stubFor({ request: { method: 'GET', - urlPattern: `/auth/api/user/${encodeURI(username)}/email`, + urlPattern: `/users/${encodeURI(username)}/email`, }, response: { status: 200, @@ -216,7 +216,7 @@ const stubUnverifiedEmail = username => stubFor({ request: { method: 'GET', - urlPattern: `/auth/api/user/${encodeURI(username)}/email`, + urlPattern: `/users/${encodeURI(username)}/email`, }, response: { status: 204, diff --git a/server/config.js b/server/config.js index 17f06720..7997fec6 100755 --- a/server/config.js +++ b/server/config.js @@ -67,6 +67,13 @@ module.exports = { systemClientId: get('SYSTEM_CLIENT_ID', get('API_CLIENT_ID', 'use-of-force-system'), requiredInProduction), systemClientSecret: get('SYSTEM_CLIENT_SECRET', get('API_CLIENT_SECRET', 'clientsecret'), requiredInProduction), }, + hmppsManageUsersApi: { + url: get('HMPPS_MANAGE_USERS_API_URL', 'http://localhost:8081', requiredInProduction), + timeout: { + response: get('HMPPS_MANAGE_USERS_API_TIMEOUT_RESPONSE', 10000), + deadline: get('HMPPS_MANAGE_USERS_API_TIMEOUT_DEADLINE', 10000), + }, + }, prison: { url: get('PRISON_API_URL', 'http://localhost:8080', requiredInProduction), timeout: { diff --git a/server/data/authClient.test.ts b/server/data/authClient.test.ts index 2829b3a0..4e64bc79 100644 --- a/server/data/authClient.test.ts +++ b/server/data/authClient.test.ts @@ -14,14 +14,16 @@ const redisClient = { describe('authClient', () => { let systemToken - let fakeApi + let fakeHmppsAuthApi + let fakeHmppsManageUsersApi let client: AuthClient const token = 'token-1' beforeEach(() => { systemToken = systemTokenBuilder(new TokenStore(redisClient as RedisClient)) - fakeApi = nock(config.apis.oauth2.url) + fakeHmppsAuthApi = nock(config.apis.oauth2.url) + fakeHmppsManageUsersApi = nock(config.apis.hmppsManageUsersApi.url) client = new AuthClient(token) }) @@ -34,8 +36,8 @@ describe('authClient', () => { const userResponse = { username: 'BOB', email: 'an@email.com' } it('email exists', async () => { - fakeApi - .get(`/api/user/${userName}/email`) + fakeHmppsManageUsersApi + .get(`/users/${userName}/email`) .matchHeader('authorization', `Bearer ${token}`) .reply(200, userResponse) @@ -44,27 +46,27 @@ describe('authClient', () => { }) it('no verified email exists', async () => { - fakeApi.get(`/api/user/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(204) + fakeHmppsManageUsersApi.get(`/users/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(204) const output = await client.getEmail(userName) expect(output).toEqual({ username: 'Bob', exists: true, verified: false }) }) it('user doesnt exist', async () => { - fakeApi.get(`/api/user/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(404) + fakeHmppsManageUsersApi.get(`/users/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(404) const output = await client.getEmail(userName) expect(output).toEqual({ username: 'Bob', exists: false, verified: false }) }) it('username offends the auth service', async () => { - fakeApi.get(`/api/user/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(400) + fakeHmppsManageUsersApi.get(`/users/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(400) expect(client.getEmail(userName)).rejects.toThrow('Bad Request') }) it('not authorised error', async () => { - fakeApi.get(`/api/user/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(401) + fakeHmppsManageUsersApi.get(`/users/${userName}/email`).matchHeader('authorization', `Bearer ${token}`).reply(401) expect(client.getEmail(userName)).rejects.toThrow('Unauthorized') }) @@ -75,7 +77,10 @@ describe('authClient', () => { const userResponse = { username: 'Bob', email: 'an@email.com' } it('user exists', async () => { - fakeApi.get(`/api/user/${userName}`).matchHeader('authorization', `Bearer ${token}`).reply(200, userResponse) + fakeHmppsManageUsersApi + .get(`/users/${userName}`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, userResponse) const output = await client.getUser(userName) expect(output).toEqual(userResponse) @@ -87,8 +92,14 @@ describe('authClient', () => { const user2 = { username: 'Jo', email: 'bn@email.com' } it('getUsers', async () => { - fakeApi.get(`/api/user/${user1.username}`).matchHeader('authorization', `Bearer ${token}`).reply(200, user1) - fakeApi.get(`/api/user/${user2.username}`).matchHeader('authorization', `Bearer ${token}`).reply(200, user2) + fakeHmppsManageUsersApi + .get(`/users/${user1.username}`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, user1) + fakeHmppsManageUsersApi + .get(`/users/${user2.username}`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, user2) const output = await client.getUsers([user1.username, user2.username]) expect(output).toEqual(expect.arrayContaining([user1, user2])) @@ -99,8 +110,8 @@ describe('authClient', () => { const userResponse = { username: 'Bob', email: 'an@email.com' } it('user exists', async () => { - fakeApi - .get(`/api/prisonuser?firstName=bob&lastName=smith`) + fakeHmppsManageUsersApi + .get(`/prisonusers?firstName=bob&lastName=smith`) .matchHeader('authorization', `Bearer ${token}`) .reply(200, userResponse) @@ -109,8 +120,8 @@ describe('authClient', () => { }) it('it trims names', async () => { - fakeApi - .get(`/api/prisonuser?firstName=bob&lastName=smith`) + fakeHmppsManageUsersApi + .get(`/prisonusers?firstName=bob&lastName=smith`) .matchHeader('authorization', `Bearer ${token}`) .reply(200, userResponse) @@ -123,7 +134,7 @@ describe('authClient', () => { const tokenObject = { access_token: 'token-1' } it('with username', async () => { const userName = 'Bob' - fakeApi + fakeHmppsAuthApi .post(`/oauth/token`, 'grant_type=client_credentials&username=Bob') .basicAuth({ user: config.apis.oauth2.systemClientId, pass: config.apis.oauth2.systemClientSecret }) .matchHeader('Content-Type', 'application/x-www-form-urlencoded') @@ -134,7 +145,7 @@ describe('authClient', () => { }) it('without username', async () => { - fakeApi + fakeHmppsAuthApi .post(`/oauth/token`, 'grant_type=client_credentials') .basicAuth({ user: config.apis.oauth2.systemClientId, pass: config.apis.oauth2.systemClientSecret }) .matchHeader('Content-Type', 'application/x-www-form-urlencoded') diff --git a/server/data/authClient.ts b/server/data/authClient.ts index a00d66a8..1d6f9b62 100644 --- a/server/data/authClient.ts +++ b/server/data/authClient.ts @@ -13,7 +13,8 @@ const timeoutSpec = { response: config.apis.oauth2.timeout.response, deadline: config.apis.oauth2.timeout.deadline, } -const apiUrl = config.apis.oauth2.url +const hmppsAuthUrl = config.apis.oauth2.url +const hmppsManageUsersApiUrl = config.apis.hmppsManageUsersApi.url const agentOptions = { maxSockets: config.apis.oauth2.agent.maxSockets, @@ -21,7 +22,7 @@ const agentOptions = { freeSocketTimeout: config.apis.oauth2.agent.freeSocketTimeout, } -const keepaliveAgent = apiUrl.startsWith('https') ? new HttpsAgent(agentOptions) : new Agent(agentOptions) +const keepaliveAgent = hmppsAuthUrl.startsWith('https') ? new HttpsAgent(agentOptions) : new Agent(agentOptions) async function getSystemClientToken(tokenStore: TokenStore, username?: string) { const key = username || '%ANONYMOUS%' @@ -56,7 +57,7 @@ const getOauthToken = (oauthClientToken, requestSpec) => { const oauthRequest = querystring.stringify(requestSpec) return superagent - .post(`${apiUrl}/oauth/token`) + .post(`${hmppsAuthUrl}/oauth/token`) .set('Authorization', oauthClientToken) .set('content-type', 'application/x-www-form-urlencoded') .send(oauthRequest) @@ -126,7 +127,7 @@ export class AuthClient { } async getEmail(username: string): Promise { - const path = `${apiUrl}/api/user/${username}/email` + const path = `${hmppsManageUsersApiUrl}/users/${username}/email` const { status, body } = await this.get({ path, raw: true }) return { email: body.email, @@ -137,7 +138,7 @@ export class AuthClient { } async getUser(username: string): Promise { - const path = `${apiUrl}/api/user/${username}` + const path = `${hmppsManageUsersApiUrl}/users/${username}` const body = await this.get({ path }) return body } @@ -147,7 +148,7 @@ export class AuthClient { } async findUsers(firstName: string, lastName: string): Promise { - const path = `${apiUrl}/api/prisonuser` + const path = `${hmppsManageUsersApiUrl}/prisonusers` const body = await this.get({ path, query: querystring.stringify({ firstName: firstName?.trim(), lastName: lastName?.trim() }),