Skip to content

Commit

Permalink
Haar 2512 add service values (#123)
Browse files Browse the repository at this point in the history
* Parse the service api response

* display services in template

* fix up integration tests

* remove lines from husky pre-commit

* fix up baseClient types in factory
  • Loading branch information
thomasridd authored Aug 8, 2024
1 parent 90445c5 commit 98bea81
Show file tree
Hide file tree
Showing 16 changed files with 251 additions and 109 deletions.
3 changes: 0 additions & 3 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

NODE_ENV=dev && node_modules/.bin/lint-staged && npm run typecheck && npm test
4 changes: 2 additions & 2 deletions integration_tests/e2e/edit-base-client-deployment.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ context('Edit base client deployment: Auth', () => {
cy.task('stubSignIn')
cy.task('stubManageUser')
cy.task('stubListBaseClients')
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials })
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials, includeService: true })
cy.task('stubGetListClientInstancesList')
})

Expand All @@ -41,7 +41,7 @@ context('Edit base client deployment details page', () => {
cy.task('stubSignIn')
cy.task('stubManageUser')
cy.task('stubListBaseClients')
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials })
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials, includeService: true })
cy.task('stubGetListClientInstancesList')
editBaseClientDeploymentDetailsPage = visitEditBaseClientDeploymentDetailsPage()
})
Expand Down
61 changes: 48 additions & 13 deletions integration_tests/e2e/view-base-client.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ context('Base client page - Auth', () => {
beforeEach(() => {
cy.task('reset')
cy.task('stubSignIn')
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials })
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials, includeService: false })
cy.task('stubManageUser')
cy.task('stubGetListClientInstancesList')
cy.task('stubAddClientInstance')
Expand All @@ -42,7 +42,7 @@ context('Base client page - client credentials flow', () => {
beforeEach(() => {
cy.task('reset')
cy.task('stubSignIn')
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials })
cy.task('stubGetBaseClient', { grantType: GrantType.ClientCredentials, includeService: false })
cy.task('stubManageUser')
cy.task('stubGetListClientInstancesList')
cy.task('stubAddClientInstance')
Expand Down Expand Up @@ -112,18 +112,17 @@ context('Base client page - client credentials flow', () => {
context('Base client page - authorization-code flow', () => {
let baseClientsPage: ViewBaseClientPage

beforeEach(() => {
cy.task('reset')
cy.task('stubSignIn')
cy.task('stubGetBaseClient', { grantType: GrantType.AuthorizationCode })
cy.task('stubManageUser')
cy.task('stubGetListClientInstancesList')
cy.task('stubAddClientInstance')

baseClientsPage = visitBaseClientPage()
})
context('Base client details - response includes service details', () => {
beforeEach(() => {
cy.task('reset')
cy.task('stubSignIn')
cy.task('stubGetBaseClient', { grantType: GrantType.AuthorizationCode, includeService: true })
cy.task('stubManageUser')
cy.task('stubGetListClientInstancesList')
cy.task('stubAddClientInstance')
baseClientsPage = visitBaseClientPage()
})

context('Base client details', () => {
it('User can see base client details table', () => {
baseClientsPage.baseClientDetailsTable().should('be.visible')
})
Expand All @@ -148,4 +147,40 @@ context('Base client page - authorization-code flow', () => {
baseClientsPage.baseClientServiceDetailsTable().should('be.visible')
})
})

context('Base client details - response has null service details', () => {
beforeEach(() => {
cy.task('reset')
cy.task('stubSignIn')
cy.task('stubGetBaseClient', { grantType: GrantType.AuthorizationCode, includeService: false })
cy.task('stubManageUser')
cy.task('stubGetListClientInstancesList')
cy.task('stubAddClientInstance')
baseClientsPage = visitBaseClientPage()
})

it('User can see base client details table', () => {
baseClientsPage.baseClientDetailsTable().should('be.visible')
})

it('User can see audit trail table', () => {
baseClientsPage.baseClientAuditTable().should('be.visible')
})

it('User cannot see client credentials table', () => {
baseClientsPage.baseClientClientCredentialsTable().should('not.exist')
})

it('User can see authorization-code table', () => {
baseClientsPage.baseClientAuthorizationCodeTable().should('be.visible')
})

it('User can see config table', () => {
baseClientsPage.baseClientConfigTable().should('be.visible')
})

it('User cannot see service details panel', () => {
baseClientsPage.baseClientServiceDetailsTable().should('not.exist')
})
})
})
4 changes: 2 additions & 2 deletions integration_tests/mockApis/baseClientsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default {
})
},

stubGetBaseClient: (config: { grantType: GrantType }) => {
stubGetBaseClient: (config: { grantType: GrantType; includeService: boolean }) => {
return stubFor({
request: {
method: 'GET',
Expand All @@ -35,7 +35,7 @@ export default {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
jsonBody: getBaseClientResponseMock(config.grantType),
jsonBody: getBaseClientResponseMock(config.grantType, config.includeService),
},
})
},
Expand Down
6 changes: 4 additions & 2 deletions server/audit/baseClientAudit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ export const sendBaseClientEvent = async (
if (!config.apis.audit.enabled) {
logger.info(`${baseClientEvent} - ${baseClientId} - ${JSON.stringify(details)}`)
} else {
await auditService.sendAuditMessage({
const auditMessage = {
action: baseClientEvent,
who: username,
subjectId: baseClientId,
subjectType: BASE_CLIENT_SUBJECT_TYPE,
correlationId,
service: config.productId,
details: JSON.stringify(details),
})
}
await auditService.sendAuditMessage(auditMessage)
}
}

Expand Down
28 changes: 26 additions & 2 deletions server/controllers/baseClientController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,30 @@ describe('BaseClientController', () => {
expect(baseClientService.getBaseClient).toHaveBeenCalledWith(token, baseClient.baseClientId)
})

it('renders the main view of a base client with null service', async () => {
// GIVEN a base client with null service
const baseClient = baseClientFactory.build()
baseClient.service = null
const clients = clientFactory.buildList(3)
baseClientService.getBaseClient.mockResolvedValue(baseClient)
baseClientService.listClientInstances.mockResolvedValue(clients)

// WHEN the index page is requested
request = createMock<Request>({ params: { baseClientId: baseClient.baseClientId } })
await baseClientController.displayBaseClient()(request, response, next)

// THEN the view base client page is rendered
const presenter = viewBaseClientPresenter(baseClient, clients)
expect(response.render).toHaveBeenCalledWith('pages/base-client.njk', {
baseClient,
presenter,
...nunjucksUtils,
})

// AND the base client is retrieved from the base client service
expect(baseClientService.getBaseClient).toHaveBeenCalledWith(token, baseClient.baseClientId)
})

it('audits the view attempt', async () => {
// GIVEN a base client
const baseClient = baseClientFactory.build()
Expand Down Expand Up @@ -606,7 +630,7 @@ describe('BaseClientController', () => {
it.each([
['renders one client instance', 1, true],
['renders multiple client instances', 3, false],
])(`if %s renders the page with isLastClient %s`, async (_, clientCount, isLastClient) => {
])(`if %s renders the page with isLastClient %s`, async (_, clientCount: number, isLastClient: boolean) => {
// GIVEN a base client
const baseClient = baseClientFactory.build()
const clients = clientFactory.buildList(clientCount)
Expand Down Expand Up @@ -663,7 +687,7 @@ describe('BaseClientController', () => {
it.each([
['one client instance exists', '/', 1],
['multiple client instances', '/base-clients/abcd', 3],
])(`if delete successful and %s, redirects to %s`, async (_, redirectURL, clientCount) => {
])(`if delete successful and %s, redirects to %s`, async (_, redirectURL: string, clientCount: number) => {
// GIVEN a base client
const baseClient = baseClientFactory.build({ baseClientId: 'abcd' })
const clients = clientFactory.buildList(clientCount)
Expand Down
22 changes: 19 additions & 3 deletions server/data/localMockData/baseClientsResponseMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export const listBaseClientsResponseMock: ListBaseClientsResponse = {
],
}

export const getBaseClientResponseMock: (grantType: GrantType) => GetBaseClientResponse = (grantType: GrantType) => {
export const getBaseClientResponseMock: (grantType: GrantType, includeService: boolean) => GetBaseClientResponse = (
grantType: GrantType,
includeService: boolean = true,
) => {
const response: GetBaseClientResponse = {
grantType: 'CLIENT_CREDENTIALS',
clientId: 'base_client_id_1',
Expand All @@ -45,7 +48,6 @@ export const getBaseClientResponseMock: (grantType: GrantType) => GetBaseClientR
jiraNumber: 'jiraNumber',
validDays: 1,
accessTokenValiditySeconds: 3600,
serviceAuthorities: ['ROLE_ONE', 'ROLE_TWO'],
deployment: {
clientType: 'service',
team: 'deployment team',
Expand All @@ -69,14 +71,28 @@ export const getBaseClientResponseMock: (grantType: GrantType) => GetBaseClientR
}
}

return {
const baseClient = {
...response,
grantType: 'AUTHORIZATION_CODE',
redirectUris: ['redirectUri1', 'redirectUri2'],
jwtFields: '+alpha,-beta',
mfa: MfaType.None,
mfaRememberMe: false,
}

return includeService
? {
...baseClient,
service: {
name: 'service name',
description: 'service description',
authorisedRoles: ['ROLE_ONE', 'ROLE_TWO'],
url: 'https://localhost:3000',
enabled: true,
contact: 'service contact',
},
}
: baseClient
}

export const getListClientInstancesResponseMock: ListClientInstancesResponse = {
Expand Down
6 changes: 3 additions & 3 deletions server/interfaces/baseClientApi/baseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface BaseClient {
expired: boolean
clientCredentials: ClientCredentialsDetails
authorisationCode: AuthorisationCodeDetails
service: ServiceDetails
service?: ServiceDetails
deployment: DeploymentDetails
config: ClientConfig
}
Expand All @@ -31,13 +31,13 @@ interface AuthorisationCodeDetails {
mfa: MfaType
}

interface ServiceDetails {
export interface ServiceDetails {
serviceName: string
description: string
serviceRoles: string[]
url: string
contact: string
status: string
status: boolean
}

export interface DeploymentDetails {
Expand Down
9 changes: 8 additions & 1 deletion server/interfaces/baseClientApi/baseClientResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ export interface GetBaseClientResponse {
secretKey: string
deploymentInfo: string
}
serviceAuthorities?: string[]
service?: {
name: string
description: string
authorisedRoles: string[]
url: string
enabled: boolean
contact: string
}
}

export interface ClientSecretsResponse {
Expand Down
26 changes: 17 additions & 9 deletions server/mappers/baseClientApi/getBaseClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GetBaseClientResponse } from '../../interfaces/baseClientApi/baseClientResponse'
import { BaseClient, DeploymentDetails } from '../../interfaces/baseClientApi/baseClient'
import { BaseClient, DeploymentDetails, ServiceDetails } from '../../interfaces/baseClientApi/baseClient'
import { ClientType } from '../../data/enums/clientTypes'
import { HostingType } from '../../data/enums/hostingTypes'
import { snake, toBaseClientId } from '../../utils/utils'
Expand All @@ -23,14 +23,7 @@ export default (response: GetBaseClientResponse): BaseClient => {
mfaRememberMe: response.mfaRememberMe ? response.mfaRememberMe : false,
mfa: response.mfa ? response.mfa : '',
},
service: {
serviceName: '',
description: '',
serviceRoles: response.serviceAuthorities ? response.serviceAuthorities : [],
url: '',
contact: '',
status: '',
},
service: getService(response),
deployment: getDeployment(response),
config: {
allowedIPs: response.ips ? response.ips : [],
Expand Down Expand Up @@ -77,3 +70,18 @@ const getDeployment = (response: GetBaseClientResponse): DeploymentDetails => {

return deployment
}

const getService = (response: GetBaseClientResponse): ServiceDetails => {
if (!response.service) {
return null
}

return {
serviceName: response.service.name,
description: response.service.description,
serviceRoles: response.service.authorisedRoles ? response.service.authorisedRoles : [],
url: response.service.url,
contact: response.service.contact,
status: response.service.enabled,
}
}
7 changes: 6 additions & 1 deletion server/mappers/baseClientApi/listBaseClients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BaseClient, BaseClientListFilter } from '../../interfaces/baseClientApi
import { toClientType } from '../../data/enums/clientTypes'
import { toGrantType } from '../../data/enums/grantType'
import { kebab, multiSeparatorSplit, snake, toBaseClientId } from '../../utils/utils'
import { MfaType } from '../../data/enums/mfaTypes'

export const mapListBaseClientRequest = (request: Request): BaseClientListFilter => {
const asJson = JSON.stringify(request.query)
Expand Down Expand Up @@ -71,14 +72,16 @@ export default (response: ListBaseClientsResponse): BaseClient[] => {
registeredRedirectURIs: [],
jwtFields: '',
azureAdLoginFlow: false,
mfaRememberMe: false,
mfa: MfaType.None,
},
service: {
serviceName: client.teamName || '',
description: '',
serviceRoles: [],
url: '',
contact: '',
status: '',
status: false,
},
deployment: {
clientType: snake(client.clientType),
Expand All @@ -90,6 +93,8 @@ export default (response: ListBaseClientsResponse): BaseClient[] => {
deployment: '',
secretName: '',
clientIdKey: '',
secretKey: '',
deploymentInfo: '',
},
config: {
allowedIPs: [],
Expand Down
2 changes: 1 addition & 1 deletion server/mappers/forms/mapCreateBaseClientForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default (request: Request): BaseClient => {
serviceRoles: [],
url: '',
contact: '',
status: '',
status: false,
},
deployment: {
clientType: '',
Expand Down
Loading

0 comments on commit 98bea81

Please sign in to comment.