ef-keycloak-connect 1.8.4-patch-2.0 → 1.8.4-patch-4.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-2.0",
3
+ "version": "1.8.4-patch-4.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( this.keycloakConfig.USERNAME_ADMIN, this.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 ) {
@@ -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 = this.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
764
  config.data.grant_type = this.keycloakConfig.GRANT_TYPE;
708
- config.data.token = token;
765
+ config.data.token = rpt_token;
709
766
  URL = URL + "/introspect";
710
767
  config.url = URL;
711
768
 
@@ -713,10 +770,10 @@ 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
- Resources: ( intrsopectionResponse.data.authorization.permissions.length > 0 ) ? intrsopectionResponse.data.authorization.permissions : []
776
+ Resources: ( intrsopectionResponse?.data?.authorization?.permissions?.length > 0 ) ? intrsopectionResponse?.data?.authorization?.permissions : []
720
777
  }
721
778
 
722
779
  // T.O.K.E.N R.E.Q.U.E.S.T # 4 ( A.D.M.I.N. T.O.K.E.N)
@@ -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,