ef-keycloak-connect 1.8.4-patch → 1.8.4-patch-3.0
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/package.json +1 -1
- package/services/keycloakService.js +93 -35
package/package.json
CHANGED
|
@@ -49,7 +49,7 @@ class KeycloakService extends Keycloak {
|
|
|
49
49
|
let attributesFromToken = token.keycloak_User.attributes
|
|
50
50
|
|
|
51
51
|
if ( is2FAEnabled ) { // if 2FA is enabled then running the 2FA flow
|
|
52
|
-
if ( !twoFAChannel || twoFAChannel == '' || ( twoFAChannel !== 'app' && twoFAChannel !== 'sms' ) ) {
|
|
52
|
+
if ( !twoFAChannel || twoFAChannel == '' || ( twoFAChannel !== 'app' && twoFAChannel !== 'sms' && twoFAChannel !== 'rsa' ) ) {
|
|
53
53
|
return Promise.reject( { status: 400, error_message: 'twoFAChannel parameter is empty or invalid' } )
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -61,25 +61,42 @@ class KeycloakService extends Keycloak {
|
|
|
61
61
|
// checking if user attributes in keycloak exist or not to confirm 2FA registration
|
|
62
62
|
if ( !attributesFromToken || !attributesFromToken.is2FARegistered || attributesFromToken.is2FARegistered == 'false' ) {
|
|
63
63
|
|
|
64
|
+
// getting admin access token to update the user attributes for RSA & Auht Apps
|
|
65
|
+
const adminData = await this.getAccessToken( keycloakConfig.USERNAME_ADMIN, keycloakConfig.PASSWORD_ADMIN );
|
|
66
|
+
const adminToken = adminData.access_token;
|
|
67
|
+
|
|
64
68
|
// appending extra information regarding 2FA in response object
|
|
65
69
|
tempToken.is2FARegistered = false
|
|
66
70
|
tempToken.twoFAChannel = twoFAChannel
|
|
67
71
|
tempToken.message = "2FA registration required"
|
|
68
72
|
|
|
73
|
+
// handling RSA authenticator scenario exclusively
|
|
74
|
+
if ( twoFAChannel === 'rsa' ) {
|
|
75
|
+
|
|
76
|
+
tempToken.is2FARegistered = true;
|
|
77
|
+
tempToken.message = "OTP required.";
|
|
78
|
+
|
|
79
|
+
//updating user attributes for RSA MFA
|
|
80
|
+
let newAttributes = {};
|
|
81
|
+
if ( attributesFromToken ) newAttributes = attributesFromToken;
|
|
82
|
+
newAttributes.twoFAChannel = "rsa";
|
|
83
|
+
newAttributes.is2FARegistered = true;
|
|
84
|
+
|
|
85
|
+
await this.updateUserAttributes( adminToken, token.keycloak_User.id, newAttributes );
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
// if 2FA is required through authenticator app then performing necessary operation in keycloak user attributes
|
|
70
|
-
if ( twoFAChannel == 'app' ) {
|
|
89
|
+
else if ( twoFAChannel == 'app' ) {
|
|
90
|
+
|
|
71
91
|
// QR Code and Secret Code generation based on username
|
|
72
92
|
const qrSetup = await this.getQRCode( user_name )
|
|
73
93
|
if ( qrSetup ) {
|
|
94
|
+
|
|
74
95
|
tempToken.otpSecret = qrSetup.secret
|
|
75
96
|
tempToken.qrImage = qrSetup.image
|
|
76
97
|
}
|
|
77
98
|
else return Promise.reject( { error: 404, error_message: 'Error occurred while generating QR code.' } )
|
|
78
99
|
|
|
79
|
-
// getting admin access token to update the user attributes
|
|
80
|
-
const adminData = await this.getAccessToken( this.keycloakConfig.USERNAME_ADMIN, this.keycloakConfig.PASSWORD_ADMIN )
|
|
81
|
-
const adminToken = adminData.access_token
|
|
82
|
-
|
|
83
100
|
//updating user attributes for 2FA
|
|
84
101
|
let newAttributes = {}
|
|
85
102
|
if ( attributesFromToken ) newAttributes = attributesFromToken
|
|
@@ -90,11 +107,10 @@ class KeycloakService extends Keycloak {
|
|
|
90
107
|
// saving the Secret Code into KeyCloak as user attribute to validate the OTP on each login
|
|
91
108
|
await this.updateUserAttributes( adminToken, token.keycloak_User.id, newAttributes )
|
|
92
109
|
}
|
|
93
|
-
}
|
|
94
|
-
else if ( attributesFromToken.is2FARegistered[ 0 ] == 'true' ) { // if user has already registered for 2FA
|
|
110
|
+
} else if ( attributesFromToken.is2FARegistered[ 0 ] == 'true' ) { // if user has already registered for 2FA
|
|
95
111
|
tempToken.is2FARegistered = true
|
|
96
112
|
tempToken.twoFAChannel = attributesFromToken.twoFAChannel[ 0 ]
|
|
97
|
-
tempToken.message = "OTP required"
|
|
113
|
+
tempToken.message = "OTP required."
|
|
98
114
|
|
|
99
115
|
if ( attributesFromToken.twoFAChannel[ 0 ] == 'sms' ) {
|
|
100
116
|
if ( !attributesFromToken.phoneNumber ) {
|
|
@@ -223,7 +239,7 @@ class KeycloakService extends Keycloak {
|
|
|
223
239
|
|
|
224
240
|
return new Promise( async ( resolve, reject ) => {
|
|
225
241
|
|
|
226
|
-
let URL =
|
|
242
|
+
let URL = keycloakConfig[ "auth-server-url" ] + "realms/" + keycloakConfig[ "realm" ] + "/protocol/openid-connect/token/introspect";
|
|
227
243
|
|
|
228
244
|
let config = {
|
|
229
245
|
method: "post",
|
|
@@ -488,6 +504,47 @@ class KeycloakService extends Keycloak {
|
|
|
488
504
|
}
|
|
489
505
|
}
|
|
490
506
|
|
|
507
|
+
// running OTP validation flow for RSA Authenticator
|
|
508
|
+
else if ( userAttributes.twoFAChannel[ 0 ] === 'rsa' ) {
|
|
509
|
+
// setting up SecurID API for MFA
|
|
510
|
+
let URL = keycloakConfig.RSA_Server_URL + "mfa/v1_1/authn/initialize";
|
|
511
|
+
|
|
512
|
+
// configuring headers & payload
|
|
513
|
+
let config = {
|
|
514
|
+
method: "post",
|
|
515
|
+
url: URL,
|
|
516
|
+
headers: {
|
|
517
|
+
"Content-Type": "application/json",
|
|
518
|
+
"client-key": this.keycloakConfig.RSA_Client_Key,
|
|
519
|
+
},
|
|
520
|
+
data: {
|
|
521
|
+
clientId: this.keycloakConfig.RSA_Client_ID,
|
|
522
|
+
subjectName: username,
|
|
523
|
+
subjectCredentials: [
|
|
524
|
+
{
|
|
525
|
+
methodId: "SECURID",
|
|
526
|
+
collectedInputs: [ { name: "SECURID", value: otpToValidate } ],
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
context: {
|
|
530
|
+
authnAttemptId: "",
|
|
531
|
+
messageId: username + "2faAttempt",
|
|
532
|
+
inResponseTo: "",
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
try {
|
|
538
|
+
let verificationStatus = await requestController.httpRequest( config, false );
|
|
539
|
+
if ( verificationStatus.status !== 200 || !verificationStatus.data || ( verificationStatus.data.attemptResponseCode !== 'SUCCESS' && verificationStatus.data.attemptReasonCode !== 'CREDENTIAL_VERIFIED' ) ) {
|
|
540
|
+
throw false
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
catch ( err ) {
|
|
544
|
+
return Promise.reject( { error: 400, error_message: "Error occured while verifying token from RSA SecurID. This may be due to invalid token, invalid configurations or some issue with SecurID." } )
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
}
|
|
491
548
|
}
|
|
492
549
|
else return Promise.reject( { error: 400, error_message: 'Error occurred while fetching user attributes.' } )
|
|
493
550
|
|
|
@@ -514,7 +571,7 @@ class KeycloakService extends Keycloak {
|
|
|
514
571
|
|
|
515
572
|
let URL = this.keycloakConfig[ "auth-server-url" ] + "realms/" + realm_name + "/protocol/openid-connect/token";
|
|
516
573
|
|
|
517
|
-
//
|
|
574
|
+
//keycloakConfig["auth-server-url"] +'realms
|
|
518
575
|
let config = {
|
|
519
576
|
|
|
520
577
|
method: "post",
|
|
@@ -542,6 +599,7 @@ class KeycloakService extends Keycloak {
|
|
|
542
599
|
if ( tokenResponse.data.access_token ) {
|
|
543
600
|
|
|
544
601
|
token = tokenResponse.data.access_token;
|
|
602
|
+
refresh_token = tokenResponse.data.refresh_token;
|
|
545
603
|
|
|
546
604
|
//To fetch introspect token to handle errors.
|
|
547
605
|
let config_introspect = { ...config };
|
|
@@ -609,7 +667,7 @@ class KeycloakService extends Keycloak {
|
|
|
609
667
|
//Fetching Groups data for each user.
|
|
610
668
|
try {
|
|
611
669
|
|
|
612
|
-
let teamData = await this.getUserSupervisedGroups( responseObject.id, admin_token, type );
|
|
670
|
+
let teamData = await this.getUserSupervisedGroups( responseObject.id, admin_token, type, responseObject?.roles );
|
|
613
671
|
|
|
614
672
|
//Check for Permission Groups assignment and roles assignment against them
|
|
615
673
|
const checkUserRoleAndPermissions = this.checkUserRoleAndPermissions( teamData, responseObject );
|
|
@@ -700,12 +758,11 @@ class KeycloakService extends Keycloak {
|
|
|
700
758
|
let rptResponse = await requestController.httpRequest( config, true );
|
|
701
759
|
|
|
702
760
|
if ( rptResponse.data.access_token ) {
|
|
703
|
-
|
|
704
|
-
refresh_token = rptResponse.data.refresh_token;
|
|
761
|
+
let rpt_token = rptResponse.data.access_token;
|
|
705
762
|
|
|
706
763
|
let userToken = token;
|
|
707
|
-
config.data.grant_type =
|
|
708
|
-
config.data.token =
|
|
764
|
+
config.data.grant_type = keycloakConfig.GRANT_TYPE;
|
|
765
|
+
config.data.token = rpt_token;
|
|
709
766
|
URL = URL + "/introspect";
|
|
710
767
|
config.url = URL;
|
|
711
768
|
|
|
@@ -713,7 +770,7 @@ class KeycloakService extends Keycloak {
|
|
|
713
770
|
try {
|
|
714
771
|
|
|
715
772
|
let intrsopectionResponse = await requestController.httpRequest( config, true );
|
|
716
|
-
intrsopectionResponse.data.access_token =
|
|
773
|
+
intrsopectionResponse.data.access_token = rpt_token;
|
|
717
774
|
|
|
718
775
|
responseObject.permittedResources = {
|
|
719
776
|
Resources: ( intrsopectionResponse.data.authorization.permissions.length > 0 ) ? intrsopectionResponse.data.authorization.permissions : []
|
|
@@ -1640,7 +1697,7 @@ class KeycloakService extends Keycloak {
|
|
|
1640
1697
|
} );
|
|
1641
1698
|
}
|
|
1642
1699
|
|
|
1643
|
-
async getUserSupervisedGroups( userId, adminToken, type ) {
|
|
1700
|
+
async getUserSupervisedGroups( userId, adminToken, type, roles ) {
|
|
1644
1701
|
|
|
1645
1702
|
return new Promise( async ( resolve, reject ) => {
|
|
1646
1703
|
|
|
@@ -1682,10 +1739,13 @@ class KeycloakService extends Keycloak {
|
|
|
1682
1739
|
|
|
1683
1740
|
} catch ( er ) {
|
|
1684
1741
|
|
|
1685
|
-
|
|
1742
|
+
if ( !roles.includes( "admin" ) ) {
|
|
1686
1743
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1744
|
+
error = await errorService.handleError( er );
|
|
1745
|
+
|
|
1746
|
+
// Log the error and proceed with default values
|
|
1747
|
+
console.error( "User Team Fetch Error: An error occurred while fetching the user's team:", error );
|
|
1748
|
+
}
|
|
1689
1749
|
|
|
1690
1750
|
}
|
|
1691
1751
|
|
|
@@ -2151,10 +2211,11 @@ class KeycloakService extends Keycloak {
|
|
|
2151
2211
|
if ( flag == true ) {
|
|
2152
2212
|
|
|
2153
2213
|
obj.push( {
|
|
2154
|
-
id: user
|
|
2155
|
-
username: user
|
|
2156
|
-
firstName: user
|
|
2157
|
-
lastName: user
|
|
2214
|
+
id: user?.id,
|
|
2215
|
+
username: user?.username,
|
|
2216
|
+
firstName: user?.firstName == undefined ? "" : user?.firstName,
|
|
2217
|
+
lastName: user?.lastName == undefined ? "" : user?.lastName,
|
|
2218
|
+
attributes: ( user?.attributes ) ? user?.attributes : {},
|
|
2158
2219
|
roles: [ keycloak_roles[ i ] ],
|
|
2159
2220
|
} );
|
|
2160
2221
|
|
|
@@ -2466,7 +2527,6 @@ class KeycloakService extends Keycloak {
|
|
|
2466
2527
|
|
|
2467
2528
|
let URL = `${this.keycloakConfig[ "auth-server-url" ]}admin/realms/${this.keycloakConfig[ "realm" ]}/users/${userId}/role-mappings/realm`;
|
|
2468
2529
|
|
|
2469
|
-
|
|
2470
2530
|
let config = {
|
|
2471
2531
|
|
|
2472
2532
|
method: method,
|
|
@@ -4277,7 +4337,7 @@ class KeycloakService extends Keycloak {
|
|
|
4277
4337
|
|
|
4278
4338
|
// !-------------- Multitenancy -----------------!
|
|
4279
4339
|
|
|
4280
|
-
async createRealmAsTenant( tenantName, realmDataString, authzConfigDataString ) {
|
|
4340
|
+
async createRealmAsTenant( tenantName, realmDataString, authzConfigDataString, keycloakConfig ) {
|
|
4281
4341
|
|
|
4282
4342
|
return new Promise( async ( resolve, reject ) => {
|
|
4283
4343
|
|
|
@@ -4323,7 +4383,7 @@ class KeycloakService extends Keycloak {
|
|
|
4323
4383
|
let mainMessage = "";
|
|
4324
4384
|
|
|
4325
4385
|
let accessToken;
|
|
4326
|
-
let URL =
|
|
4386
|
+
let URL = keycloakConfig[ "auth-server-url" ] + "realms/master/protocol/openid-connect/token";
|
|
4327
4387
|
|
|
4328
4388
|
let config = {
|
|
4329
4389
|
method: "post",
|
|
@@ -4334,8 +4394,8 @@ class KeycloakService extends Keycloak {
|
|
|
4334
4394
|
data: {
|
|
4335
4395
|
client_id: "admin-cli",
|
|
4336
4396
|
grant_type: "password",
|
|
4337
|
-
username:
|
|
4338
|
-
password:
|
|
4397
|
+
username: keycloakConfig[ "MASTER_USERNAME" ],
|
|
4398
|
+
password: keycloakConfig[ "MASTER_PASSWORD" ]
|
|
4339
4399
|
},
|
|
4340
4400
|
};
|
|
4341
4401
|
|
|
@@ -4345,7 +4405,7 @@ class KeycloakService extends Keycloak {
|
|
|
4345
4405
|
|
|
4346
4406
|
accessToken = adminAccessToken.data.access_token;
|
|
4347
4407
|
|
|
4348
|
-
let createRealmUrl =
|
|
4408
|
+
let createRealmUrl = keycloakConfig[ "auth-server-url" ] + 'admin/realms';
|
|
4349
4409
|
|
|
4350
4410
|
// 1. Read the realm configuration JSON file
|
|
4351
4411
|
console.log( `Reading realm configuration from provided realm data.` );
|
|
@@ -4365,8 +4425,6 @@ class KeycloakService extends Keycloak {
|
|
|
4365
4425
|
data: realmData
|
|
4366
4426
|
};
|
|
4367
4427
|
|
|
4368
|
-
console.log( realmData );
|
|
4369
|
-
|
|
4370
4428
|
try {
|
|
4371
4429
|
|
|
4372
4430
|
let realmCreation = await requestController.httpRequest( config1, false );
|
|
@@ -4392,7 +4450,7 @@ class KeycloakService extends Keycloak {
|
|
|
4392
4450
|
|
|
4393
4451
|
// 4. Get the internal UUID of the target client
|
|
4394
4452
|
console.log( `Fetching UUID for client '${targetClientIdForAuthz}' in realm '${tenantName}'...` );
|
|
4395
|
-
const getClientUrl = `${
|
|
4453
|
+
const getClientUrl = `${keycloakConfig[ "auth-server-url" ]}admin/realms/${tenantName}/clients`;
|
|
4396
4454
|
|
|
4397
4455
|
let config2 = {
|
|
4398
4456
|
|
|
@@ -4465,7 +4523,7 @@ class KeycloakService extends Keycloak {
|
|
|
4465
4523
|
} );
|
|
4466
4524
|
}
|
|
4467
4525
|
|
|
4468
|
-
const importAuthzUrl = `${
|
|
4526
|
+
const importAuthzUrl = `${keycloakConfig[ "auth-server-url" ]}admin/realms/${tenantName}/clients/${clientUuid}/authz/resource-server/import`;
|
|
4469
4527
|
|
|
4470
4528
|
let config3 = {
|
|
4471
4529
|
|