@opengovsg/mockpass 4.5.0 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +4 -2
- package/README.md +2 -2
- package/lib/assertions.js +1 -0
- package/lib/express/oidc/v2-ndi.js +38 -27
- package/package.json +1 -1
|
@@ -7,6 +7,8 @@ on:
|
|
|
7
7
|
jobs:
|
|
8
8
|
publish-npm:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
10
12
|
steps:
|
|
11
13
|
- uses: actions/checkout@v4
|
|
12
14
|
- uses: actions/setup-node@v3
|
|
@@ -15,10 +17,10 @@ jobs:
|
|
|
15
17
|
cache: 'npm'
|
|
16
18
|
cache-dependency-path: '**/package-lock.json'
|
|
17
19
|
registry-url: https://registry.npmjs.org/
|
|
20
|
+
- name: Update npm
|
|
21
|
+
run: npm install -g npm@latest # Get the latest npm for OIDC support
|
|
18
22
|
- run: npm ci
|
|
19
23
|
- run: npm publish --access public
|
|
20
|
-
env:
|
|
21
|
-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
|
22
24
|
publish-docker:
|
|
23
25
|
runs-on: ubuntu-latest
|
|
24
26
|
steps:
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Configure your application to point to the following endpoints:
|
|
|
21
21
|
|
|
22
22
|
- http://localhost:5156/singpass/v2/.well-known/openid-configuration
|
|
23
23
|
- http://localhost:5156/singpass/v2/.well-known/keys
|
|
24
|
-
- http://localhost:5156/singpass/v2/
|
|
24
|
+
- http://localhost:5156/singpass/v2/auth
|
|
25
25
|
- http://localhost:5156/singpass/v2/token
|
|
26
26
|
|
|
27
27
|
Configure your application (or MockPass) with keys:
|
|
@@ -45,7 +45,7 @@ Configure your application to point to the following endpoints:
|
|
|
45
45
|
|
|
46
46
|
- http://localhost:5156/corppass/v2/.well-known/openid-configuration
|
|
47
47
|
- http://localhost:5156/corppass/v2/.well-known/keys
|
|
48
|
-
- http://localhost:5156/corppass/v2/
|
|
48
|
+
- http://localhost:5156/corppass/v2/auth
|
|
49
49
|
- http://localhost:5156/corppass/v2/token
|
|
50
50
|
|
|
51
51
|
Configure your application (or MockPass) with keys:
|
package/lib/assertions.js
CHANGED
|
@@ -157,7 +157,7 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
157
157
|
const defaultProfile =
|
|
158
158
|
profiles.find((p) => p.nric === process.env.MOCKPASS_NRIC) || profiles[0]
|
|
159
159
|
|
|
160
|
-
app.get(`/${idp.toLowerCase()}/v2/
|
|
160
|
+
app.get(`/${idp.toLowerCase()}/v2/auth`, (req, res) => {
|
|
161
161
|
const {
|
|
162
162
|
scope: scopes,
|
|
163
163
|
response_type,
|
|
@@ -227,7 +227,7 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
227
227
|
const response = render(LOGIN_TEMPLATE, {
|
|
228
228
|
values,
|
|
229
229
|
customProfileConfig: {
|
|
230
|
-
endpoint: `/${idp.toLowerCase()}/v2/
|
|
230
|
+
endpoint: `/${idp.toLowerCase()}/v2/auth/custom-profile`,
|
|
231
231
|
showUuid: true,
|
|
232
232
|
showUen: idp === 'corpPass',
|
|
233
233
|
redirectURI,
|
|
@@ -250,7 +250,7 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
250
250
|
}
|
|
251
251
|
})
|
|
252
252
|
|
|
253
|
-
app.get(`/${idp.toLowerCase()}/v2/
|
|
253
|
+
app.get(`/${idp.toLowerCase()}/v2/auth/custom-profile`, (req, res) => {
|
|
254
254
|
const { nric, uuid, uen, redirectURI, state, nonce } = req.query
|
|
255
255
|
|
|
256
256
|
const profile = { nric, uuid }
|
|
@@ -423,14 +423,9 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
423
423
|
redirect_uri: redirectURI,
|
|
424
424
|
})
|
|
425
425
|
|
|
426
|
-
const { idTokenClaims } = await assertions.oidc.create[
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
aud,
|
|
430
|
-
nonce,
|
|
431
|
-
)
|
|
432
|
-
|
|
433
|
-
const accessToken = authCode
|
|
426
|
+
const { idTokenClaims, accessToken } = await assertions.oidc.create[
|
|
427
|
+
idp
|
|
428
|
+
](profile, iss, aud, nonce, authCode)
|
|
434
429
|
|
|
435
430
|
// Step 3: Sign ID token with ASP signing key
|
|
436
431
|
const aspKeyset = JSON.parse(aspSecret)
|
|
@@ -517,7 +512,7 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
517
512
|
// Note: does not support backchannel auth
|
|
518
513
|
const data = {
|
|
519
514
|
issuer: baseUrl,
|
|
520
|
-
authorization_endpoint: `${baseUrl}/
|
|
515
|
+
authorization_endpoint: `${baseUrl}/auth`,
|
|
521
516
|
jwks_uri: `${baseUrl}/.well-known/keys`,
|
|
522
517
|
response_types_supported: ['code'],
|
|
523
518
|
scopes_supported: ['openid'],
|
|
@@ -551,6 +546,9 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
551
546
|
...data['scopes_supported'],
|
|
552
547
|
'uinfin',
|
|
553
548
|
'name',
|
|
549
|
+
'email',
|
|
550
|
+
'mobileno',
|
|
551
|
+
'regadd',
|
|
554
552
|
]
|
|
555
553
|
data['userinfo_endpoint'] = `${baseUrl}/userinfo`
|
|
556
554
|
data['userinfo_signing_alg_values_supported'] = ['ES256']
|
|
@@ -573,16 +571,27 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
573
571
|
|
|
574
572
|
const authCode = extractBearerTokenFromHeader(headers, res)
|
|
575
573
|
|
|
576
|
-
const
|
|
574
|
+
const found = lookUpByAuthCode(authCode, {
|
|
577
575
|
isStateless,
|
|
578
576
|
})
|
|
579
577
|
|
|
578
|
+
if (!found || !found.scopes) {
|
|
579
|
+
return res.status(400).send({
|
|
580
|
+
error: 'invalid_request',
|
|
581
|
+
error_description:
|
|
582
|
+
'Myinfo profile has yet to be provisioned for the user',
|
|
583
|
+
})
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const {
|
|
587
|
+
profile: { uuid },
|
|
588
|
+
scopes,
|
|
589
|
+
clientId,
|
|
590
|
+
} = found
|
|
580
591
|
const scopesArr = scopes.split(' ')
|
|
581
592
|
console.log('userinfo scopes: ', scopesArr)
|
|
582
593
|
|
|
583
|
-
const
|
|
584
|
-
const { nric } = assertions.oidc.singPass.find((p) => p.uuid === uuid)
|
|
585
|
-
const name = `USER ${nric}`
|
|
594
|
+
const profile = assertions.oidc.singPass.find((p) => p.uuid === uuid)
|
|
586
595
|
|
|
587
596
|
const iss = `${protocol}://${host}/${idp.toLowerCase()}/v2`
|
|
588
597
|
const aud = clientId
|
|
@@ -599,10 +608,14 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
599
608
|
iat,
|
|
600
609
|
}
|
|
601
610
|
|
|
602
|
-
const claimMap =
|
|
611
|
+
const claimMap = profile.claims || {
|
|
612
|
+
uinfin: makeClaim(profile.nric),
|
|
613
|
+
name: makeClaim(`USER ${profile.nric}`),
|
|
614
|
+
}
|
|
615
|
+
|
|
603
616
|
for (const [claim, value] of Object.entries(claimMap)) {
|
|
604
617
|
if (scopesArr.includes(claim)) {
|
|
605
|
-
|
|
618
|
+
userinfoPayload[claim] = value
|
|
606
619
|
}
|
|
607
620
|
}
|
|
608
621
|
|
|
@@ -647,7 +660,7 @@ function config(app, { showLoginPage, isStateless }) {
|
|
|
647
660
|
alg: rpEncryptionKey.alg,
|
|
648
661
|
typ: 'JWT',
|
|
649
662
|
kid: rpEncryptionKey.kid,
|
|
650
|
-
enc: '
|
|
663
|
+
enc: 'A256GCM',
|
|
651
664
|
cty: 'JWT',
|
|
652
665
|
}
|
|
653
666
|
|
|
@@ -739,13 +752,11 @@ const extractBearerTokenFromHeader = (headers, res) => {
|
|
|
739
752
|
return tokenParts[1]
|
|
740
753
|
}
|
|
741
754
|
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
}
|
|
749
|
-
}
|
|
755
|
+
const makeClaim = (value) => ({
|
|
756
|
+
lastupdated: '2023-03-23',
|
|
757
|
+
source: '1',
|
|
758
|
+
classification: 'C',
|
|
759
|
+
value,
|
|
760
|
+
})
|
|
750
761
|
|
|
751
762
|
module.exports = config
|