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 +1 -1
- package/services/keycloakService.js +85 -25
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( 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
|
-
//
|
|
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
764
|
config.data.grant_type = this.keycloakConfig.GRANT_TYPE;
|
|
708
|
-
config.data.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 =
|
|
773
|
+
intrsopectionResponse.data.access_token = rpt_token;
|
|
717
774
|
|
|
718
775
|
responseObject.permittedResources = {
|
|
719
|
-
Resources: ( intrsopectionResponse
|
|
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
|
-
|
|
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,
|