Skip to content

Commit

Permalink
Remove getUserRoles as an api call and add as decoded from the token
Browse files Browse the repository at this point in the history
  • Loading branch information
tpmcgowan committed Dec 12, 2023
1 parent 59c68b2 commit ea6de48
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 21 deletions.
12 changes: 0 additions & 12 deletions server/data/manageUsersApiClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,4 @@ describe('manageUsersApiClient', () => {
expect(output).toEqual(response)
})
})

describe('getUserRoles', () => {
it('should return data from api', async () => {
fakeManageUsersApiClient
.get('/users/me/roles')
.matchHeader('authorization', `Bearer ${token.access_token}`)
.reply(200, [{ roleCode: 'role1' }, { roleCode: 'role2' }])

const output = await manageUsersApiClient.getUserRoles(token.access_token)
expect(output).toEqual(['role1', 'role2'])
})
})
})
6 changes: 0 additions & 6 deletions server/data/manageUsersApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,4 @@ export default class ManageUsersApiClient {
logger.info('Getting user details: calling HMPPS Manage Users Api')
return ManageUsersApiClient.restClient(token).get<User>({ path: '/users/me' })
}

getUserRoles(token: string): Promise<string[]> {
return ManageUsersApiClient.restClient(token)
.get<UserRole[]>({ path: '/users/me/roles' })
.then(roles => roles.map(role => role.roleCode))
}
}
14 changes: 12 additions & 2 deletions server/services/userService.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import UserService from './userService'
import ManageUsersApiClient, { type User } from '../data/manageUsersApiClient'
import createUserToken from '../testutils/createUserToken'

jest.mock('../data/manageUsersApiClient')

const token = 'some token'

describe('User service', () => {
let manageUsersApiClient: jest.Mocked<ManageUsersApiClient>
let userService: UserService
Expand All @@ -16,14 +15,25 @@ describe('User service', () => {
})

it('Retrieves and formats user name', async () => {
const token = createUserToken([])
manageUsersApiClient.getUser.mockResolvedValue({ name: 'john smith' } as User)

const result = await userService.getUser(token)

expect(result.displayName).toEqual('John Smith')
})

it('Retrieves and formats roles', async () => {
const token = createUserToken(['ROLE_ONE', 'ROLE_TWO'])
manageUsersApiClient.getUser.mockResolvedValue({ name: 'john smith' } as User)

const result = await userService.getUser(token)

expect(result.roles).toEqual(['ONE', 'TWO'])
})

it('Propagates error', async () => {
const token = createUserToken([])
manageUsersApiClient.getUser.mockRejectedValue(new Error('some error'))

await expect(userService.getUser(token)).rejects.toEqual(new Error('some error'))
Expand Down
9 changes: 8 additions & 1 deletion server/services/userService.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { jwtDecode } from 'jwt-decode'
import { convertToTitleCase } from '../utils/utils'
import type { User } from '../data/manageUsersApiClient'
import ManageUsersApiClient from '../data/manageUsersApiClient'

export interface UserDetails extends User {
displayName: string
roles: string[]
}

export default class UserService {
constructor(private readonly manageUsersApiClient: ManageUsersApiClient) {}

async getUser(token: string): Promise<UserDetails> {
const user = await this.manageUsersApiClient.getUser(token)
return { ...user, displayName: convertToTitleCase(user.name) }
return { ...user, roles: this.getUserRoles(token), displayName: convertToTitleCase(user.name) }
}

getUserRoles(token: string): string[] {
const { authorities: roles = [] } = jwtDecode(token) as { authorities?: string[] }
return roles.map(role => role.substring(role.indexOf('_') + 1))
}
}
14 changes: 14 additions & 0 deletions server/testutils/createUserToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import jwt from 'jsonwebtoken'

export default function createUserToken(authorities: string[]) {
const payload = {
user_name: 'user1',
scope: ['read', 'write'],
auth_source: 'nomis',
authorities,
jti: 'a610a10-cca6-41db-985f-e87efb303aaf',
client_id: 'clientid',
}

return jwt.sign(payload, 'secret', { expiresIn: '1h' })

Check failure

Code scanning / CodeQL

Hard-coded credentials Critical test

The hard-coded value "secret" is used as
jwt key
.
}

0 comments on commit ea6de48

Please sign in to comment.