ef-keycloak-connect 1.9.2 → 1.9.3-RC2

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.
@@ -0,0 +1,2 @@
1
+ {
2
+ }
package/README.md CHANGED
@@ -40,8 +40,8 @@ This adapter is extended from keycloak-connect and have functionalities of both
40
40
  - getRealmRoles
41
41
  - assignRoleToUser
42
42
  - authenticateFinesse
43
- - createRealmAsTenant
44
43
  - externalServiceSso
44
+ - createRealmAsTenant
45
45
 
46
46
  ```
47
47
  ### Example
@@ -96,14 +96,14 @@ Sample `config` is given below:
96
96
  "bearer-only": true,
97
97
  "TWILIO_SID": "yourTwilioSID",
98
98
  "TWILIO_AUTH_TOKEN": "yourTwilioAuthToken",
99
+ "EXTERNAL_USER_PASSWORD": "external_service_user_password",
99
100
  "TWILIO_VERIFY_SID": "yourTwilioVerifySID",
100
101
  "ef-server-url": "https://<cx instance fqdn>/unified-admin/",
101
102
  "FINESSE_USERNAME_ADMIN": "<cisco admin username>",
102
103
  "FINESSE_PASSWORD_ADMIN": "<cisco admin username>",
103
104
  "SYNC_AGENT_PASSWORD": "<qm sync agent/supervisor password>",
104
105
  "MASTER_USERNAME": "master_admin_username",
105
- "MASTER_PASSWORD": "master_admin_password",
106
- "EXTERNAL_USER_PASSWORD": "external_service_user_password"
106
+ "MASTER_PASSWORD": "master_admin_password"
107
107
  }
108
108
  ```
109
109
  Here is the definition of each property defined in config file/object.
@@ -126,6 +126,7 @@ Here is the definition of each property defined in config file/object.
126
126
  - **SCOPE_NAME:** Keycloak Client App scope to use as default scope during Authorization.
127
127
  - **bearer-only:** Will keep its value as **true** (This should be set to true for services. If enabled the adapter will not attempt to authenticate users, but only verify bearer tokens. This is OPTIONAL. The default value is false.)
128
128
  - **TWILIO_SID:** Your Twilio Account SID.
129
+ - **EXTERNAL_USER_PASSWORD**: While syncing external service user to keycloak, this password value will be assigned as password to it.
129
130
  - **TWILIO_AUTH_TOKEN:** Your Twilio account's Auth Token.
130
131
  - **TWILIO_VERIFY_SID:** Your Twilio account's Verify Service's SID.
131
132
  - *(Each property having TWILIO in its name is optional and is required only in the case of 2FA via SMS.)*
@@ -136,7 +137,6 @@ Here is the definition of each property defined in config file/object.
136
137
  - **SYNC_AGENT_PASSWORD**: Password for Users being synced to Keycloak/CX.
137
138
  - **MASTER_USERNAME**: Keycloak master admin username.
138
139
  - **MASTER_PASSWORD**: Keycloak master password username.
139
- - **EXTERNAL_USER_PASSWORD**: While syncing external service user to keycloak, this password value will be assigned as password to it.
140
140
 
141
141
  For using keycloak-connect features:
142
142
  ```js
@@ -448,9 +448,6 @@ It takes 5 arguments:
448
448
  - finesse_server_url: The url of finesse server (In case of normal keycloak auth, send this parameter as **' '**)
449
449
  - user_roles: The array containing user_roles, it will be used to assign roles to finesse user while synching it with Keycloak (for normal auth send it as [ ]).
450
450
  - finesse_token: acess token for finesse SSO authentication (It will be passed if Finesse SSO instance is connected, in case of non SSO will pass empty string **' '** as argument)
451
-
452
-
453
-
454
451
 
455
452
  ##### Example of SSO Finesse Auth:
456
453
 
@@ -459,7 +456,6 @@ It takes 5 arguments:
459
456
 
460
457
  ##### Example of non SSO Finesse Auth:
461
458
 
462
- authenticateFinesse('johndoe', '12345', `https://${finesse_server_url}:${port}`, ['agent','supervisor'], '')
463
459
 
464
460
  ### externalServiceSso( userRolesArr, validationToken, externalServiceURL, type )
465
461
 
@@ -471,6 +467,30 @@ It takes 4 arguments:
471
467
  - externalServiceURL: The url of external service server e.g in case of dynamics365: **'https://{fqdn}/api/data/v9.0'** , in case of salesforce: **'https://{salesforce service fqdn}.com'**
472
468
  - type: Type of external service. In case of Dynamics365, the type is: **dynamics365**. In case of Salesforce, the type is: **salesforce**
473
469
 
470
+ #### Example (Dynamics365)
471
+
472
+ ```js
473
+ await keycloak.externalServiceSso(
474
+ ['agent', 'supervisor'],
475
+ 'eyJ0eXAiOiJKV1QiLCJhbGci...',
476
+ 'https://yourcrm.dynamics.com/api/data/v9.0',
477
+ 'dynamics365'
478
+ );
479
+ ```
480
+
481
+ #### Example (Salesforce)
482
+
483
+ ```js
484
+ await keycloak.externalServiceSso(
485
+ ['agent'],
486
+ 'eyJ0eXAiOiJKV1QiLCJhbGci...',
487
+ 'https://yourorg.salesforce.com',
488
+ 'salesforce'
489
+ );
490
+ ```
491
+
492
+ authenticateFinesse('johndoe', '12345', `https://${finesse_server_url}:${port}`, ['agent','supervisor'], '')
493
+
474
494
  ### generateAccessTokenFromRefreshToken(refreshToken)
475
495
 
476
496
  This function generates a new access_token by using the refreshToken received in parameter.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ef-keycloak-connect",
3
- "version": "1.9.2",
3
+ "version": "1.9.3-RC2",
4
4
  "description": "Node JS keycloak adapter for authentication and authorization.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,7 +20,6 @@
20
20
  "keycloak-connect": "^26.0.7",
21
21
  "qrcode": "^1.5.4",
22
22
  "speakeasy": "^2.0.0",
23
- "twilio": "^5.2.2",
24
23
  "xml2js": "^0.6.2"
25
24
  }
26
25
  }
@@ -3,7 +3,7 @@ const https = require( 'https' );
3
3
 
4
4
  let requestController = require( "../controller/requestController.js" );
5
5
  const ErrorService = require( './errorService.js' );
6
- const { copyFileSync } = require( 'fs' );
6
+
7
7
 
8
8
  const errorService = new ErrorService();
9
9
  let realmRoles = [];
@@ -227,8 +227,8 @@ class CiscoSyncService {
227
227
  credentials: [
228
228
  {
229
229
  type: "password",
230
- value: "Expertflow464",
231
- temporary: false,
230
+ value: keycloakConfig[ "DEFAULT_USER_PASSWORD" ] || "Expertflow464",
231
+ temporary: true,
232
232
  },
233
233
  ],
234
234
  attributes: {
@@ -263,7 +263,7 @@ class CiscoSyncService {
263
263
  //Get list of all the roles in keycloak realm
264
264
  /* Storing all the realm roles in Global realmRoles list.If some role come from finesse which doesn't
265
265
  exist in realmRoles list then we call keycloak roles api again to update realmRoles list. */
266
- if ( ciscoUser.roles != [] ) {
266
+ if ( Array.isArray( ciscoUser.roles ) && ciscoUser.roles.length > 0 ) {
267
267
 
268
268
  if ( realmRoles.length > 0 ) {
269
269
 
@@ -572,8 +572,8 @@ class CiscoSyncService {
572
572
  let cxTeams = await this.fetchCXTeams( keycloakConfig[ "ef-server-url" ] );
573
573
 
574
574
  // Fetch Keycloak users
575
- let keycloakUsers = await this.fetchKeycloakUsers( keycloakConfig[ "auth-server-url" ], adminToken );
576
- const keycloakUsersByRole = await this.fetchKeycloakUsersByRole( keycloakConfig[ "auth-server-url" ], adminToken );
575
+ let keycloakUsers = await this.fetchKeycloakUsers( keycloakConfig, adminToken );
576
+ const keycloakUsersByRole = await this.fetchKeycloakUsersByRole( keycloakConfig, adminToken );
577
577
  const keycloakUsersByPermissionGroups = await this.fetchKeycloakUsersByPermissionGroups( keycloakConfig, adminToken );
578
578
 
579
579
  if ( ciscoUsers.length > 0 && ciscoTeams.length > 0 ) {
@@ -585,7 +585,7 @@ class CiscoSyncService {
585
585
  await this.syncUsersToCX( ciscoUsers, keycloakUsers, keycloakUsersByRole, keycloakUsersByPermissionGroups, keycloakConfig, adminToken );
586
586
 
587
587
  //Once users are synced, we fetch updated keycloak users list.
588
- keycloakUsers = await this.fetchKeycloakUsers( keycloakConfig[ "auth-server-url" ], adminToken );
588
+ keycloakUsers = await this.fetchKeycloakUsers( keycloakConfig, adminToken );
589
589
 
590
590
  let userSyncedToMongo = await this.syncKeycloakUsersToCXMongo( keycloakConfig[ "USERNAME_ADMIN" ], keycloakConfig[ "PASSWORD_ADMIN" ], keycloakConfig[ "ef-server-url" ] );
591
591
 
@@ -739,6 +739,9 @@ class CiscoSyncService {
739
739
  }
740
740
  } )
741
741
 
742
+ } else {
743
+
744
+ reject( er );
742
745
  }
743
746
 
744
747
  }
@@ -912,6 +915,9 @@ class CiscoSyncService {
912
915
  }
913
916
  } )
914
917
 
918
+ } else {
919
+
920
+ reject( er );
915
921
  }
916
922
 
917
923
  }
@@ -919,11 +925,11 @@ class CiscoSyncService {
919
925
  } );
920
926
  }
921
927
 
922
- async fetchKeycloakUsers( keycloakURL, adminToken ) {
928
+ async fetchKeycloakUsers( keycloakConfig, adminToken ) {
923
929
 
924
930
  return new Promise( async ( resolve, reject ) => {
925
931
 
926
- let URL = keycloakURL + 'admin/realms/expertflow/users?max=100000';
932
+ let URL = keycloakConfig[ "auth-server-url" ] + `admin/realms/${keycloakConfig[ "realm" ]}/users?max=100000`;
927
933
 
928
934
  let config = {
929
935
 
@@ -933,8 +939,6 @@ class CiscoSyncService {
933
939
  Accept: "application/json",
934
940
  "cache-control": "no-cache",
935
941
  "Content-Type": "application/x-www-form-urlencoded",
936
- },
937
- headers: {
938
942
  Authorization: "Bearer " + adminToken,
939
943
  },
940
944
 
@@ -952,7 +956,7 @@ class CiscoSyncService {
952
956
  } )
953
957
  }
954
958
 
955
- async fetchKeycloakUsersByRole( keycloakURL, adminToken ) {
959
+ async fetchKeycloakUsersByRole( keycloakConfig, adminToken ) {
956
960
 
957
961
  return new Promise( async ( resolve, reject ) => {
958
962
 
@@ -963,7 +967,7 @@ class CiscoSyncService {
963
967
  // Use Promise.all to handle multiple role requests concurrently
964
968
  for ( let role of roles ) {
965
969
 
966
- const URL = `${keycloakURL}admin/realms/expertflow/roles/${role}/users?max=1000000`;
970
+ const URL = `${keycloakConfig[ "auth-server-url" ]}admin/realms/${keycloakConfig[ "realm" ]}/roles/${role}/users?max=1000000`;
967
971
 
968
972
  const config = {
969
973
  method: "get",
@@ -1023,7 +1027,7 @@ class CiscoSyncService {
1023
1027
  // Use Promise.all to handle multiple role requests concurrently
1024
1028
  for ( let group of permissionGroupsObj ) {
1025
1029
 
1026
- const URL = `${keycloakConfig[ "auth-server-url" ]}admin/realms/expertflow/groups/${group.id}/members?max=1000000`;
1030
+ const URL = `${keycloakConfig[ "auth-server-url" ]}admin/realms/${keycloakConfig[ "realm" ]}/groups/${group.id}/members?max=1000000`;
1027
1031
 
1028
1032
  const config = {
1029
1033
 
@@ -15,12 +15,12 @@ class Dynamics365Service {
15
15
 
16
16
  let config = {
17
17
  method: 'get',
18
- 'Content-Type': 'application/json',
19
- 'Accept': 'application/json',
20
- 'OData-MaxVersion': '4.0',
21
- 'OData-Version': '4.0',
22
18
  url: URL,
23
19
  headers: {
20
+ 'Content-Type': 'application/json',
21
+ 'Accept': 'application/json',
22
+ 'OData-MaxVersion': '4.0',
23
+ 'OData-Version': '4.0',
24
24
  'Authorization': `Bearer ${validationToken}`
25
25
  },
26
26
  //disable ssl
@@ -106,4 +106,4 @@ class Dynamics365Service {
106
106
  }
107
107
  }
108
108
 
109
- module.exports = Dynamics365Service;
109
+ module.exports = Dynamics365Service;
@@ -82,10 +82,20 @@ class ErrorService {
82
82
  };
83
83
  case 'invalid_grant':
84
84
 
85
+ let reasonToReturn
86
+ if ( err.response.status === 400 ) {
87
+ if(errorData.error_description.includes('Account disabled')){
88
+ reasonToReturn = "Account Disabled: User account has been disabled in Keycloak."
89
+ }
90
+ else
91
+ reasonToReturn = 'Password Update Required: Please update your password, as it was set temporarily by the admin or has expired.'
92
+ }
93
+ else reasonToReturn = 'Invalid User Credentials: The provided credentials are not valid. Please enter valid user credentials.'
85
94
  return {
86
95
  status: err.response.status,
87
- reason: 'Invalid User Credentials: The provided credentials are not valid. Please enter valid user credentials.',
96
+ reason: reasonToReturn,
88
97
  };
98
+
89
99
  default:
90
100
 
91
101
  if ( typeof ( err.response.data ) === "object" ) {
@@ -115,7 +125,7 @@ class ErrorService {
115
125
  } else {
116
126
 
117
127
  if ( typeof ( err.response.data ) === "object" ) {
118
-
128
+
119
129
  return {
120
130
  status: err.response.status,
121
131
  reason: err.response.data.error
@@ -97,6 +97,9 @@ class FinesseService {
97
97
  }
98
98
  } )
99
99
 
100
+ } else {
101
+
102
+ reject( er );
100
103
  }
101
104
 
102
105
  }
@@ -189,6 +192,9 @@ class FinesseService {
189
192
  }
190
193
  } )
191
194
 
195
+ } else {
196
+
197
+ reject( er );
192
198
  }
193
199
  }
194
200