scimgateway 5.5.0 → 5.5.1

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/README.md CHANGED
@@ -746,7 +746,7 @@ Example Entra ID (plugin-entra-id) using federated credentials:
746
746
  }
747
747
  }
748
748
  // Note: Federated credentials defined for the application in Entra ID must match the corresponding `issuer`, `subject`, and `name`
749
- // example issuer: "https://scimgateway.my-company.com/oauth" and must be reachable from the internet
749
+ // example issuer: "https://scimgateway.my-company.com/oauth" and base URL must be reachable from the internet
750
750
  // exampole name: "plugin-entra-id"
751
751
 
752
752
 
@@ -1491,6 +1491,12 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1491
1491
 
1492
1492
  ## Change log
1493
1493
 
1494
+ ### v5.5.1
1495
+
1496
+ [Fixed]
1497
+
1498
+ - 401 Unauthorized response did include scim-formatted error message when using `helper-rest` and authentication `PassThrough`. 401 should not include scim-formatted error message
1499
+
1494
1500
  ### v5.5.0
1495
1501
 
1496
1502
  [Improved]
@@ -1518,7 +1524,7 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1518
1524
  "options": {
1519
1525
  "tenantIdGUID": "11111111-2222-3333-4444-555555555555",
1520
1526
  "fedCred": {
1521
- "issuer": "https://scimgateway.my-company.com/oauth>",
1527
+ "issuer": "https://scimgateway.my-company.com/oauth",
1522
1528
  "subject": "99999999-8888-7777-6666-555555555555",
1523
1529
  "name": "plugin-entra-id"
1524
1530
  }
@@ -1529,7 +1535,6 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1529
1535
 
1530
1536
  Also note: SCIM Gateway must be reachable from the internet (as defined by the `issuer` URL). This requires allowing inbound internet communication — or alternatively, Azure Relay can be used for outbound-only communication.
1531
1537
 
1532
-
1533
1538
  ### v5.4.4
1534
1539
 
1535
1540
  [Improved]
@@ -586,7 +586,7 @@ export class ScimGateway {
586
586
  }
587
587
 
588
588
  if (ctx.response.status && (ctx.response.status < 200 || ctx.response.status > 299)) {
589
- if (ctx.response.status === 401 && !ctx.request.headers.get('authorization')) {
589
+ if (ctx.response.status === 401 && !ctx.request.headers.has('authorization')) {
590
590
  logger.warn(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}`, { baseEntity: ctx?.routeObj?.baseEntity })
591
591
  } else if (ctx.response.status === 404) {
592
592
  logger.warn(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}`, { baseEntity: ctx?.routeObj?.baseEntity })
@@ -597,11 +597,10 @@ export class ScimGateway {
597
597
  }
598
598
 
599
599
  // start auth methods - used by auth
600
- const basic = async (baseEntity: string, method: string, authType: string, authToken: string, path: string): Promise<boolean> => {
600
+ const basic = async (baseEntity: string, method: string, authType: string, authToken: string): Promise<boolean> => {
601
601
  return await new Promise((resolve, reject) => { // basic auth
602
602
  if (!found.Basic) return resolve(false)
603
603
  if (authType !== 'Basic' || !authToken) return resolve(false)
604
- if (found.PassThrough && this.authPassThroughAllowed && !path.endsWith('/logger')) return resolve(false) // Auth PassThrough browser logon dialog support
605
604
  const [userName, userPassword] = (Buffer.from(authToken, 'base64').toString() || '').split(':')
606
605
  if (!userName || !userPassword) return resolve(false)
607
606
  const arr = this.config.scimgateway.auth.basic
@@ -819,7 +818,7 @@ export class ScimGateway {
819
818
  const obj = this.config.scimgateway.auth.passThrough
820
819
  if (obj.baseEntities) {
821
820
  if (Array.isArray(obj.baseEntities) && obj.baseEntities.length > 0) {
822
- if (!baseEntity || !obj.baseEntities.includes(baseEntity)) throw new Error(`baseEntity=${baseEntity} not allowed for passThrough according to passThrough configuration baseEntitites=${obj.baseEntities}`)
821
+ if (!obj.baseEntities.includes(baseEntity)) throw new Error(`baseEntity=${baseEntity} not allowed for passThrough according to passThrough configuration baseEntitites=${obj.baseEntities}`)
823
822
  }
824
823
  }
825
824
  if (obj.readOnly === true && method !== 'GET') throw new Error('only allowing readOnly for passThrough according to passThrough configuration readOnly=true')
@@ -834,7 +833,7 @@ export class ScimGateway {
834
833
  try {
835
834
  // authenticate
836
835
  arrResolve = await Promise.all([
837
- basic(ctx.routeObj.baseEntity, ctx.request.method, authType, authToken, ctx.path),
836
+ basic(ctx.routeObj.baseEntity, ctx.request.method, authType, authToken),
838
837
  bearerToken(ctx.routeObj.baseEntity, ctx.request.method, authType, authToken),
839
838
  bearerJwtAzure(ctx.routeObj.baseEntity, ctx.request.method, authType, authToken),
840
839
  bearerJwt(ctx.routeObj.baseEntity, ctx.request.method, authType, authToken),
@@ -1100,11 +1099,12 @@ export class ScimGateway {
1100
1099
  if (pwErrCount < 3) {
1101
1100
  pwErrCount += 1
1102
1101
  } else { // delay brute force attempts
1103
- logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] ${ctx.origin + ctx.path} ${errDescr} => delaying response with 2 minutes to prevent brute force`)
1102
+ const delay = (this.config.scimgateway.idleTimeout || 120) - 5
1103
+ logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] ${ctx.origin + ctx.path} ${errDescr} => delaying response with ${delay} seconds to prevent brute force`)
1104
1104
  await new Promise((resolve) => {
1105
1105
  setTimeout(() => {
1106
1106
  resolve(ctx)
1107
- }, 1000 * 60 * 2)
1107
+ }, 1000 * delay)
1108
1108
  })
1109
1109
  ctx.response.status = 401
1110
1110
  return
@@ -2766,6 +2766,14 @@ export class ScimGateway {
2766
2766
  if (!ctx.response.body) {
2767
2767
  ctx.response.body = 'Unauthorized'
2768
2768
  ctx.response.headers.set('content-type', 'text/plain')
2769
+ } else {
2770
+ try {
2771
+ const b = JSON.parse(ctx.response.body)
2772
+ if (b.schemas) { // 401 - do not return scim formatted error message e.g., using PassThrough
2773
+ ctx.response.body = 'Unauthorized'
2774
+ ctx.response.headers.set('content-type', 'text/plain')
2775
+ }
2776
+ } catch (err) { void 0 }
2769
2777
  }
2770
2778
  break
2771
2779
  case 403:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scimgateway",
3
- "version": "5.5.0",
3
+ "version": "5.5.1",
4
4
  "type": "module",
5
5
  "description": "Using SCIM protocol as a gateway for user provisioning to other endpoints",
6
6
  "author": "Jarle Elshaug <jarle.elshaug@gmail.com> (https://elshaug.xyz)",