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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ef-keycloak-connect",
3
- "version": "1.8.4-patch",
3
+ "version": "1.8.4-patch-3.0",
4
4
  "description": "Node JS keycloak adapter for authentication and authorization.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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 = this.keycloakConfig[ "auth-server-url" ] + "realms/" + this.keycloakConfig[ "realm" ] + "/protocol/openid-connect/token/introspect";
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
- //this.keycloakConfig["auth-server-url"] +'realms
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
- token = rptResponse.data.access_token;
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 = this.keycloakConfig.GRANT_TYPE;
708
- config.data.token = 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 = 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
- error = await errorService.handleError( er );
1742
+ if ( !roles.includes( "admin" ) ) {
1686
1743
 
1687
- // Log the error and proceed with default values
1688
- console.error( "User Team Fetch Error: An error occurred while fetching the user's team:", error );
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.id,
2155
- username: user.username,
2156
- firstName: user.firstName == undefined ? "" : user.firstName,
2157
- lastName: user.lastName == undefined ? "" : user.lastName,
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 = this.keycloakConfig[ "auth-server-url" ] + "realms/master/protocol/openid-connect/token";
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: this.keycloakConfig[ "MASTER_USERNAME" ],
4338
- password: this.keycloakConfig[ "MASTER_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 = this.keycloakConfig[ "auth-server-url" ] + 'admin/realms';
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 = `${this.keycloakConfig[ "auth-server-url" ]}admin/realms/${tenantName}/clients`;
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 = `${this.keycloakConfig[ "auth-server-url" ]}admin/realms/${tenantName}/clients/${clientUuid}/authz/resource-server/import`;
4526
+ const importAuthzUrl = `${keycloakConfig[ "auth-server-url" ]}admin/realms/${tenantName}/clients/${clientUuid}/authz/resource-server/import`;
4469
4527
 
4470
4528
  let config3 = {
4471
4529