Skip to content

Commit ea366dd

Browse files
Merge branch 'develop' into fix/link-button-url-resolution
2 parents 1515054 + 373ef68 commit ea366dd

File tree

403 files changed

+11747
-15185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

403 files changed

+11747
-15185
lines changed

.github/workflows/build-images-from-branch.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ jobs:
5656
# another workflow is calling this one
5757
5858
if [ "${{ github.event_name }}" == 'push' ]; then
59-
BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
59+
BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
6060
elif [ "${{ github.event_name }}" == 'pull_request' ]; then
61-
BRANCH=${{ github.event.pull_request.head.ref }}
61+
BRANCH=${{ github.event.pull_request.head.ref }}
6262
else
6363
BRANCH=${{ inputs.branch_name }}
6464
fi

.github/workflows/publish-toolkit-to-npm.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151

5252
- name: Build
5353
if: steps.check-version.outputs.version-exists == 'false'
54-
run: yarn build
54+
run: yarn build:all
5555
working-directory: packages/toolkit
5656

5757
- name: Authenticate to npm

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
### Breaking changes
66

77
- **Dashboard:** Changes made to the dashboard configuration will reset after upgrading OpenCRVS.
8+
- Removed unused searchBirthRegistrations and searchDeathRegistrations queries, as they are no longer used by the client.
9+
- **Retrieve action deprecated:** Field agents & registration agents used to be able to retrieve records to view the audit history & PII. We are removing this in favor of audit capabilities that is planned for in a future release.
810

911
### New features
1012

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ services:
186186
- CONFIG_SMS_CODE_EXPIRY_SECONDS=600
187187
- NOTIFICATION_SERVICE_URL=http://notification:2020/
188188
- METRICS_URL=http://metrics:1050
189+
- COUNTRY_CONFIG_URL_INTERNAL=http://countryconfig:3040
189190
user-mgnt:
190191
image: opencrvs/ocrvs-user-mgnt:${VERSION}
191192
#platform: linux/amd64

packages/auth/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"scripts": {
88
"start": "cross-env NODE_ENV=development NODE_OPTIONS=--dns-result-order=ipv4first nodemon --exec ts-node -r tsconfig-paths/register src/index.ts",
99
"start:prod": "TS_NODE_BASEURL=./build/dist/src node -r tsconfig-paths/register build/dist/src/index.js",
10-
"test": "jest --coverage --silent --noStackTrace && yarn test:compilation",
10+
"test": "yarn test:compilation && jest --coverage --silent --noStackTrace",
1111
"test:watch": "jest --watch",
1212
"open:cov": "yarn test && opener coverage/index.html",
1313
"lint": "eslint -c .eslintrc.js --fix ./src --max-warnings=0",
@@ -83,7 +83,8 @@
8383
"<rootDir>"
8484
],
8585
"moduleNameMapper": {
86-
"@auth/(.*)": "<rootDir>/src/$1"
86+
"@auth/(.*)": "<rootDir>/src/$1",
87+
"@opencrvs/commons/(.*)": "<rootDir>/../commons/src/$1"
8788
},
8889
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
8990
"setupFiles": [

packages/auth/resources/generate-test-token.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
*
99
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
1010
*/
11-
import * as commandLineArgs from 'command-line-args'
12-
import * as commandLineUsage from 'command-line-usage'
11+
import commandLineArgs from 'command-line-args'
12+
import commandLineUsage from 'command-line-usage'
1313
import { join } from 'path'
1414

1515
const optionList = [

packages/auth/resources/request-token.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
*
99
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
1010
*/
11-
import * as commandLineArgs from 'command-line-args'
12-
import * as commandLineUsage from 'command-line-usage'
11+
import commandLineArgs from 'command-line-args'
12+
import commandLineUsage from 'command-line-usage'
1313
import fetch from 'node-fetch'
1414
import * as readline from 'readline'
1515

packages/auth/src/environment.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export const env = cleanEnv(process.env, {
1919
METRICS_URL: url({ devDefault: 'http://localhost:1050' }),
2020
NOTIFICATION_SERVICE_URL: url({ devDefault: 'http://localhost:2020/' }),
2121
DOMAIN: str({ devDefault: '*' }),
22-
COUNTRY_CONFIG_URL: url({ devDefault: 'http://localhost:3040/' }),
22+
COUNTRY_CONFIG_URL: url({ devDefault: 'http://localhost:3040/' }), // used for external requests (CORS whitelist)
23+
COUNTRY_CONFIG_URL_INTERNAL: url({ devDefault: 'http://localhost:3040/' }), // used for internal service-to-service communication
2324
LOGIN_URL: url({ devDefault: 'http://localhost:3020/' }),
2425
CLIENT_APP_URL: url({ devDefault: 'http://localhost:3000/' }),
2526
CERT_PRIVATE_KEY_PATH: str({ devDefault: '../../.secrets/private-key.pem' }),

packages/auth/src/features/authenticate/handler.test.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
*/
1111
import * as fetchAny from 'jest-fetch-mock'
1212
import { createProductionEnvironmentServer } from '@auth/tests/util'
13-
import { AuthServer, createServer } from '@auth/server'
13+
import { createServer, AuthServer } from '@auth/server'
14+
import { DEFAULT_ROLES_DEFINITION } from '@opencrvs/commons/authentication'
1415

1516
const fetch = fetchAny as fetchAny.FetchMock
1617
describe('authenticate handler receives a request', () => {
@@ -54,7 +55,7 @@ describe('authenticate handler receives a request', () => {
5455
it('returns 403', async () => {
5556
fetch.mockResponse(
5657
JSON.stringify({
57-
userId: '1',
58+
id: '1',
5859
status: 'deactivated',
5960
scope: ['admin']
6061
})
@@ -78,14 +79,18 @@ describe('authenticate handler receives a request', () => {
7879

7980
jest.spyOn(reloadedCodeService, 'generateNonce').mockReturnValue('12345')
8081

81-
fetch.mockResponse(
82+
fetch.mockResponseOnce(
8283
JSON.stringify({
83-
userId: '1',
84+
id: '1',
8485
status: 'active',
85-
scope: ['admin'],
86+
role: 'NATIONAL_SYSTEM_ADMIN',
8687
mobile: `+345345343`
8788
})
8889
)
90+
91+
fetch.mockResponse(JSON.stringify(DEFAULT_ROLES_DEFINITION), {
92+
status: 200
93+
})
8994
const spy = jest.spyOn(reloadedCodeService, 'sendVerificationCode')
9095

9196
await server.server.inject({
@@ -109,14 +114,19 @@ describe('authenticate handler receives a request', () => {
109114

110115
jest.spyOn(reloadedCodeService, 'generateNonce').mockReturnValue('12345')
111116

112-
fetch.mockResponse(
117+
fetch.mockResponseOnce(
113118
JSON.stringify({
114-
userId: '1',
119+
id: '1',
115120
status: 'pending',
116-
scope: ['admin'],
121+
role: 'NATIONAL_SYSTEM_ADMIN',
117122
mobile: `+345345343`
118123
})
119124
)
125+
126+
fetch.mockResponse(JSON.stringify(DEFAULT_ROLES_DEFINITION), {
127+
status: 200
128+
})
129+
120130
const spy = jest.spyOn(reloadedCodeService, 'sendVerificationCode')
121131

122132
await server.server.inject({

packages/auth/src/features/authenticate/handler.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@
88
*
99
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
1010
*/
11-
import * as Hapi from '@hapi/hapi'
12-
import * as Joi from 'joi'
11+
import { JWT_ISSUER, WEB_USER_JWT_AUDIENCES } from '@auth/constants'
1312
import {
13+
IAuthentication,
1414
authenticate,
15-
storeUserInformation,
1615
createToken,
1716
generateAndSendVerificationCode,
18-
IAuthentication
17+
storeUserInformation
1918
} from '@auth/features/authenticate/service'
2019
import {
2120
NotificationEvent,
2221
generateNonce
2322
} from '@auth/features/verifyCode/service'
24-
import { unauthorized, forbidden } from '@hapi/boom'
25-
import { WEB_USER_JWT_AUDIENCES, JWT_ISSUER } from '@auth/constants'
23+
import { forbidden, unauthorized } from '@hapi/boom'
24+
import * as Hapi from '@hapi/hapi'
25+
import * as Joi from 'joi'
26+
import { getUserRoleScopeMapping } from '@auth/features/scopes/service'
2627

2728
interface IAuthPayload {
2829
username: string
@@ -43,6 +44,7 @@ export default async function authenticateHandler(
4344
): Promise<IAuthResponse> {
4445
const payload = request.payload as IAuthPayload
4546
let result: IAuthentication
47+
4648
const { username, password } = payload
4749
try {
4850
result = await authenticate(username.trim(), password)
@@ -63,10 +65,15 @@ export default async function authenticateHandler(
6365

6466
const isPendingUser = response.status && response.status === 'pending'
6567

68+
const roleScopeMappings = await getUserRoleScopeMapping()
69+
70+
const role = result.role as keyof typeof roleScopeMappings
71+
const scopes = roleScopeMappings[role]
72+
6673
if (isPendingUser) {
6774
response.token = await createToken(
6875
result.userId,
69-
result.scope,
76+
scopes,
7077
WEB_USER_JWT_AUDIENCES,
7178
JWT_ISSUER
7279
)
@@ -75,7 +82,7 @@ export default async function authenticateHandler(
7582
nonce,
7683
result.name,
7784
result.userId,
78-
result.scope,
85+
scopes,
7986
result.mobile,
8087
result.email
8188
)
@@ -84,13 +91,14 @@ export default async function authenticateHandler(
8491

8592
await generateAndSendVerificationCode(
8693
nonce,
87-
result.scope,
94+
scopes,
8895
notificationEvent,
8996
result.name,
9097
result.mobile,
9198
result.email
9299
)
93100
}
101+
94102
return response
95103
}
96104

@@ -104,6 +112,7 @@ export const responseSchema = Joi.object({
104112
mobile: Joi.string().optional(),
105113
email: Joi.string().optional(),
106114
status: Joi.string(),
115+
role: Joi.string(),
107116
token: Joi.string().optional()
108117
})
109118

packages/auth/src/features/authenticate/service.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ import {
2424
} from '@auth/features/verifyCode/service'
2525
import { logger, UUID } from '@opencrvs/commons'
2626
import { unauthorized } from '@hapi/boom'
27-
import { chainW, tryCatch } from 'fp-ts/Either'
28-
import { pipe } from 'fp-ts/function'
27+
import * as F from 'fp-ts'
28+
import { Scope } from '@opencrvs/commons/authentication'
29+
const { chainW, tryCatch } = F.either
30+
const { pipe } = F.function
2931
import { env } from '@auth/environment'
3032

3133
const cert = readFileSync(env.CERT_PRIVATE_KEY_PATH)
@@ -48,14 +50,14 @@ export interface IAuthentication {
4850
mobile?: string
4951
userId: string
5052
status: string
51-
scope: string[]
5253
email?: string
54+
role: string
5355
}
5456

5557
export interface ISystemAuthentication {
5658
systemId: string
5759
status: string
58-
scope: string[]
60+
scope: Scope[]
5961
}
6062

6163
export class UserInfoNotFoundError extends Error {}
@@ -79,11 +81,13 @@ export async function authenticate(
7981
if (res.status !== 200) {
8082
throw Error(res.statusText)
8183
}
84+
8285
const body = await res.json()
86+
8387
return {
8488
name: body.name,
8589
userId: body.id,
86-
scope: body.scope,
90+
role: body.role,
8791
status: body.status,
8892
mobile: body.mobile,
8993
email: body.email
@@ -121,9 +125,6 @@ export async function createToken(
121125
issuer: string,
122126
temporary?: boolean
123127
): Promise<string> {
124-
if (typeof userId === undefined) {
125-
throw new Error('Invalid userId found for token creation')
126-
}
127128
return sign({ scope }, cert, {
128129
subject: userId,
129130
algorithm: 'RS256',
@@ -201,12 +202,7 @@ export async function generateAndSendVerificationCode(
201202
email?: string
202203
) {
203204
const isDemoUser = scope.indexOf('demo') > -1 || env.QA_ENV
204-
logger.info(
205-
`isDemoUser,
206-
${JSON.stringify({
207-
isDemoUser: isDemoUser
208-
})}`
209-
)
205+
logger.info(`Is demo user: ${isDemoUser}. Scopes: ${scope.join(', ')}`)
210206
let verificationCode
211207
if (isDemoUser) {
212208
verificationCode = '000000'

packages/auth/src/features/authenticateSuperUser/handler.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
} from '@auth/features/authenticate/service'
1818
import { unauthorized } from '@hapi/boom'
1919
import { WEB_USER_JWT_AUDIENCES, JWT_ISSUER } from '@auth/constants'
20+
import { Scope, SCOPES } from '@opencrvs/commons/authentication'
21+
import { logger } from '@opencrvs/commons'
2022

2123
interface IAuthPayload {
2224
username: string
@@ -36,9 +38,19 @@ export default async function authenticateSuperUserHandler(
3638
throw unauthorized()
3739
}
3840

41+
if (result.status === 'deactivated') {
42+
logger.info('Login attempt with a deactivated super user account detected')
43+
throw unauthorized()
44+
}
45+
46+
const SUPER_ADMIN_SCOPES = [
47+
SCOPES.BYPASSRATELIMIT,
48+
SCOPES.USER_DATA_SEEDING
49+
] satisfies Scope[]
50+
3951
const token = await createToken(
4052
result.userId,
41-
result.scope,
53+
SUPER_ADMIN_SCOPES,
4254
WEB_USER_JWT_AUDIENCES,
4355
JWT_ISSUER
4456
)

packages/auth/src/features/oauthToken/client-credentials.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
NOTIFICATION_API_USER_AUDIENCE
2121
} from '@auth/constants'
2222
import * as oauthResponse from './responses'
23+
import { SCOPES } from '@opencrvs/commons/authentication'
2324

2425
export async function clientCredentialsHandler(
2526
request: Hapi.Request,
@@ -43,7 +44,7 @@ export async function clientCredentialsHandler(
4344
return oauthResponse.invalidClient(h)
4445
}
4546

46-
const isNotificationAPIUser = result.scope.includes('notification-api')
47+
const isNotificationAPIUser = result.scope.includes(SCOPES.NOTIFICATION_API)
4748

4849
const token = await createToken(
4950
result.systemId,

packages/auth/src/features/oauthToken/token-exchange.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import {
1717
import { pipe } from 'fp-ts/lib/function'
1818
import { UUID } from '@opencrvs/commons'
1919

20-
const SUBJECT_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token'
21-
const RECORD_TOKEN_TYPE = 'urn:opencrvs:oauth:token-type:single_record_token'
20+
export const SUBJECT_TOKEN_TYPE =
21+
'urn:ietf:params:oauth:token-type:access_token'
22+
export const RECORD_TOKEN_TYPE =
23+
'urn:opencrvs:oauth:token-type:single_record_token'
2224

2325
/**
2426
* Allows creating record-specific tokens for when a 3rd party system needs to confirm a registration

0 commit comments

Comments
 (0)