@frontmcp/auth 1.12.0-rc.1 → 1.12.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.
Files changed (73) hide show
  1. package/authorities/authorities.context.d.ts +7 -0
  2. package/authorities/authorities.context.d.ts.map +1 -1
  3. package/authorities/authorities.engine.d.ts +10 -4
  4. package/authorities/authorities.engine.d.ts.map +1 -1
  5. package/authorities/authorities.evaluator.d.ts +2 -0
  6. package/authorities/authorities.evaluator.d.ts.map +1 -1
  7. package/authorities/authorities.validation.d.ts.map +1 -1
  8. package/authorization/dcr-client.registry.d.ts.map +1 -1
  9. package/authorization/public.authorization.d.ts +3 -2
  10. package/authorization/public.authorization.d.ts.map +1 -1
  11. package/browser/authorities/authorities.context.mjs +5 -0
  12. package/browser/authorities/authorities.engine.mjs +45 -9
  13. package/browser/authorities/authorities.evaluator.mjs +36 -10
  14. package/browser/authorities/authorities.validation.mjs +3 -1
  15. package/browser/authorization/authorization.class.mjs +3 -3
  16. package/browser/authorization/dcr-client.registry.mjs +8 -0
  17. package/browser/authorization/public.authorization.mjs +10 -4
  18. package/browser/cimd/cimd-redis.cache.mjs +2 -0
  19. package/browser/cimd/cimd.service.mjs +16 -7
  20. package/browser/cimd/cimd.validator.mjs +6 -2
  21. package/browser/detection/auth-provider-detection.mjs +15 -0
  22. package/browser/jwks/jwks.service.mjs +9 -9
  23. package/browser/people/loopback-token.auth.mjs +10 -3
  24. package/browser/session/authorization.store.mjs +56 -2
  25. package/browser/session/consent.store.mjs +2 -1
  26. package/browser/session/credentials-accessor.impl.mjs +4 -1
  27. package/browser/session/incremental-auth-ticket.mjs +2 -0
  28. package/browser/session/redis-session.store.mjs +6 -4
  29. package/browser/session/secure-store-backends.mjs +2 -1
  30. package/browser/session/secure-store.factory.mjs +7 -1
  31. package/browser/session/storage/storage-authorization-vault.mjs +8 -2
  32. package/browser/session/storage-authorization.store.mjs +49 -3
  33. package/browser/session/storage-consent.store.mjs +3 -1
  34. package/browser/session/token-storage.factory.mjs +5 -2
  35. package/browser/session/transport-session.types.mjs +6 -0
  36. package/browser/session/utils/session-crypto.utils.mjs +14 -1
  37. package/browser/session/vercel-kv-session.store.mjs +6 -4
  38. package/cimd/cimd-redis.cache.d.ts.map +1 -1
  39. package/cimd/cimd.service.d.ts +1 -0
  40. package/cimd/cimd.service.d.ts.map +1 -1
  41. package/cimd/cimd.validator.d.ts +2 -0
  42. package/cimd/cimd.validator.d.ts.map +1 -1
  43. package/detection/auth-provider-detection.d.ts.map +1 -1
  44. package/esm/index.mjs +5 -5
  45. package/esm/package.json +5 -5
  46. package/index.js +5 -5
  47. package/jwks/jwks.service.d.ts.map +1 -1
  48. package/package.json +5 -5
  49. package/people/loopback-token.auth.d.ts +5 -1
  50. package/people/loopback-token.auth.d.ts.map +1 -1
  51. package/session/authorization.store.d.ts +23 -0
  52. package/session/authorization.store.d.ts.map +1 -1
  53. package/session/consent.store.d.ts +3 -1
  54. package/session/consent.store.d.ts.map +1 -1
  55. package/session/credentials-accessor.impl.d.ts.map +1 -1
  56. package/session/incremental-auth-ticket.d.ts +4 -0
  57. package/session/incremental-auth-ticket.d.ts.map +1 -1
  58. package/session/redis-session.store.d.ts.map +1 -1
  59. package/session/secure-store-backends.d.ts +3 -4
  60. package/session/secure-store-backends.d.ts.map +1 -1
  61. package/session/secure-store.factory.d.ts +2 -1
  62. package/session/secure-store.factory.d.ts.map +1 -1
  63. package/session/storage/storage-authorization-vault.d.ts.map +1 -1
  64. package/session/storage-authorization.store.d.ts +8 -0
  65. package/session/storage-authorization.store.d.ts.map +1 -1
  66. package/session/storage-consent.store.d.ts.map +1 -1
  67. package/session/token-storage.factory.d.ts +2 -1
  68. package/session/token-storage.factory.d.ts.map +1 -1
  69. package/session/transport-session.types.d.ts +5 -0
  70. package/session/transport-session.types.d.ts.map +1 -1
  71. package/session/utils/session-crypto.utils.d.ts +2 -1
  72. package/session/utils/session-crypto.utils.d.ts.map +1 -1
  73. package/session/vercel-kv-session.store.d.ts.map +1 -1
@@ -17,6 +17,11 @@ import type { AuthoritiesEvaluationContext, RelationshipResolver } from './autho
17
17
  * resolveDotPath({ a: 1 }, 'a.b') // undefined
18
18
  */
19
19
  export declare function resolveDotPath(obj: Record<string, unknown>, path: string): unknown;
20
+ /**
21
+ * The resolver of a context built without `relationshipResolver`. Its `check` answers false, and the
22
+ * engine reports a relationship rule checked against it as unresolved, so a `not` around it never grants.
23
+ */
24
+ export declare const noopRelationshipResolver: RelationshipResolver;
20
25
  /**
21
26
  * Function signature for custom claims resolution.
22
27
  */
@@ -70,6 +75,8 @@ export declare class AuthoritiesContextBuilder {
70
75
  private readonly claimsResolver;
71
76
  private readonly relationshipResolver;
72
77
  constructor(options?: AuthoritiesContextBuilderOptions);
78
+ /** Whether a relationship resolver was configured; without one every relationship check denies as unresolved. */
79
+ get hasRelationshipResolver(): boolean;
73
80
  /**
74
81
  * Build an evaluation context from AuthInfo and tool input.
75
82
  */
@@ -1 +1 @@
1
- {"version":3,"file":"authorities.context.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE9F;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAelF;AA0BD;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK;IAClE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAI9G;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGxF;AAQD;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED;;GAEG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAuB;gBAEhD,OAAO,GAAE,gCAAqC;IAM1D;;OAEG;IACH,KAAK,CACH,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,EAC/B,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAc,GACxC,4BAA4B;CAwEhC"}
1
+ {"version":3,"file":"authorities.context.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE9F;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAelF;AAgBD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,oBAItC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK;IAClE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAI9G;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGxF;AAQD;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,aAAa,CAAC,EAAE,wBAAwB,CAAC;IACzC,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED;;GAEG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAuB;gBAEhD,OAAO,GAAE,gCAAqC;IAM1D,iHAAiH;IACjH,IAAI,uBAAuB,IAAI,OAAO,CAErC;IAED;;OAEG;IACH,KAAK,CACH,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,EAC/B,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAc,GACxC,4BAA4B;CAwEhC"}
@@ -24,15 +24,21 @@ export declare class AuthoritiesEngine {
24
24
  constructor(profiles: AuthoritiesProfileRegistry, evaluators: AuthoritiesEvaluatorRegistry);
25
25
  /**
26
26
  * Problems with an `authorities` value declared on an entry (see {@link findAuthoritiesRuleProblems}),
27
- * and each profile name it uses that no registered profile has. The server reports them when it
28
- * starts; {@link evaluate} denies such a value (an unknown profile as `profile '…' is not registered`).
27
+ * each profile name it uses that no registered profile has, and each custom evaluator it names that
28
+ * is not registered. The server reports them when it starts; {@link evaluate} denies such a value.
29
29
  */
30
30
  findRuleProblems(authorities: unknown): string[];
31
31
  /**
32
- * Problems with every registered profile's rule (see {@link findAuthoritiesRuleProblems}).
33
- * The server reports them when it starts.
32
+ * Problems with every registered profile's rule (see {@link findAuthoritiesRuleProblems}), and each
33
+ * custom evaluator a profile names that is not registered. The server reports them when it starts.
34
34
  */
35
35
  findProfileProblems(): string[];
36
+ /** The registered profiles whose rule checks relationships, at any depth. */
37
+ profilesCheckingRelationships(): string[];
38
+ /** Whether an entry's rule object checks relationships, at any depth (a profile it names is not looked into). */
39
+ ruleChecksRelationships(authorities: unknown): boolean;
40
+ /** A problem for each custom evaluator a rule names, at any depth, that is not registered. */
41
+ private unknownEvaluatorProblems;
36
42
  /**
37
43
  * Evaluate an AuthoritiesMetadata value (string, string[], or policy object).
38
44
  *
@@ -1 +1 @@
1
- {"version":3,"file":"authorities.engine.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACvG,OAAO,KAAK,EACV,4BAA4B,EAC5B,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EAElB,MAAM,qBAAqB,CAAC;AA2C7B;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAL7B,iGAAiG;IACjG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;gBAG7C,QAAQ,EAAE,0BAA0B,EACpC,UAAU,EAAE,4BAA4B;IAG3D;;;;OAIG;IACH,gBAAgB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE;IAShD;;;OAGG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAM/B;;;;OAIG;IACG,QAAQ,CAAC,WAAW,EAAE,mBAAmB,EAAE,GAAG,EAAE,4BAA4B,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkB/G;;OAEG;YACW,eAAe;IAyB7B,yEAAyE;IACzE,OAAO,CAAC,UAAU;IAUlB;;OAEG;YACW,oBAAoB;IAIlC;;OAEG;YACW,cAAc;IA+C5B;;OAEG;IACH,OAAO,CAAC,cAAc;IA4BtB;;OAEG;YACW,cAAc;IAkB5B;;;;OAIG;YACW,cAAc;IAyB5B;;OAEG;YACW,aAAa;IAO3B;;OAEG;YACW,aAAa;IA4B3B;;OAEG;YACW,WAAW;IAiBzB;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS;CAGpE"}
1
+ {"version":3,"file":"authorities.engine.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACvG,OAAO,KAAK,EACV,4BAA4B,EAC5B,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EAElB,MAAM,qBAAqB,CAAC;AAiE7B;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAL7B,iGAAiG;IACjG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;gBAG7C,QAAQ,EAAE,0BAA0B,EACpC,UAAU,EAAE,4BAA4B;IAG3D;;;;OAIG;IACH,gBAAgB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE;IAYhD;;;OAGG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAQ/B,6EAA6E;IAC7E,6BAA6B,IAAI,MAAM,EAAE;IAMzC,iHAAiH;IACjH,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO;IAItD,8FAA8F;IAC9F,OAAO,CAAC,wBAAwB;IAMhC;;;;OAIG;IACG,QAAQ,CAAC,WAAW,EAAE,mBAAmB,EAAE,GAAG,EAAE,4BAA4B,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkB/G;;OAEG;YACW,eAAe;IAyB7B,yEAAyE;IACzE,OAAO,CAAC,UAAU;IAUlB;;OAEG;YACW,oBAAoB;IAIlC;;OAEG;YACW,cAAc;IA+C5B;;OAEG;IACH,OAAO,CAAC,cAAc;IA4BtB;;OAEG;YACW,cAAc;IAmB5B;;;;OAIG;YACW,cAAc;IAyB5B;;OAEG;YACW,aAAa;IAO3B;;OAEG;YACW,aAAa;IA4B3B;;OAEG;YACW,WAAW;IAiBzB;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS;CAGpE"}
@@ -12,6 +12,8 @@ export declare function evaluateRbacRoles(policy: RbacRolesPolicy, ctx: Authorit
12
12
  * Evaluate RBAC permissions policy against user permissions.
13
13
  */
14
14
  export declare function evaluateRbacPermissions(policy: RbacPermissionsPolicy, ctx: AuthoritiesEvaluationContext): AuthoritiesResult;
15
+ /** Why a `matches` check cannot run on these values in bounded time, or undefined when it can. */
16
+ export declare function unmatchableReason(actual: unknown, pattern: unknown): string | undefined;
15
17
  /**
16
18
  * Evaluate ABAC policy.
17
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"authorities.evaluator.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.evaluator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC5B,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,aAAa,EACd,MAAM,qBAAqB,CAAC;AAM7B;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,4BAA4B,GAAG,iBAAiB,CA4B/G;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,EAAE,4BAA4B,GAChC,iBAAiB,CA4BnB;AAgHD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,4BAA4B,GAAG,iBAAiB,CAmDrG;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,4BAA4B,GAAG,MAAM,GAAG,SAAS,CAc3G;AAiDD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,GAAG,WAAW,EAAE,EACnC,GAAG,EAAE,4BAA4B,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAY5B"}
1
+ {"version":3,"file":"authorities.evaluator.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.evaluator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACV,UAAU,EACV,4BAA4B,EAC5B,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,aAAa,EACd,MAAM,qBAAqB,CAAC;AAM7B;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,4BAA4B,GAAG,iBAAiB,CA4B/G;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,EAAE,4BAA4B,GAChC,iBAAiB,CA4BnB;AA8DD,kGAAkG;AAClG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAUvF;AA+CD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,4BAA4B,GAAG,iBAAiB,CA4DrG;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,4BAA4B,GAAG,MAAM,GAAG,SAAS,CAc3G;AA4DD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,GAAG,WAAW,EAAE,EACnC,GAAG,EAAE,4BAA4B,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAY5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"authorities.validation.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.validation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgPH;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,CAY1E;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,CAEtF"}
1
+ {"version":3,"file":"authorities.validation.d.ts","sourceRoot":"","sources":["../../src/authorities/authorities.validation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkPH;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,CAY1E;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,CAEtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"dcr-client.registry.d.ts","sourceRoot":"","sources":["../../src/authorization/dcr-client.registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dcr-client.registry.d.ts","sourceRoot":"","sources":["../../src/authorization/dcr-client.registry.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,7 @@ export interface PublicAuthorizationCreateCtx {
44
44
  * - Ideal for development, docs, public wikis, and read-only resources
45
45
  */
46
46
  export declare class PublicAuthorization extends AuthorizationBase {
47
+ #private;
47
48
  readonly mode: AuthMode;
48
49
  /**
49
50
  * Issuer identifier for the anonymous authorization
@@ -73,11 +74,11 @@ export declare class PublicAuthorization extends AuthorizationBase {
73
74
  */
74
75
  getToken(_providerId?: string): Promise<string>;
75
76
  /**
76
- * Check if all tools are allowed (public access)
77
+ * Check if all tools are allowed (`allowedTools: 'all'`); an empty list allows none
77
78
  */
78
79
  get allowsAllTools(): boolean;
79
80
  /**
80
- * Check if all prompts are allowed (public access)
81
+ * Check if all prompts are allowed (`allowedPrompts: 'all'`); an empty list allows none
81
82
  */
82
83
  get allowsAllPrompts(): boolean;
83
84
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"public.authorization.d.ts","sourceRoot":"","sources":["../../src/authorization/public.authorization.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAoC,MAAM,uBAAuB,CAAC;AAExF;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAY;IAEnC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB,OAAO;IAKP;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,MAAM,CAAC,GAAG,GAAE,4BAAiC,GAAG,mBAAmB;IA6D1E;;;;OAIG;IACG,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOrD;;OAEG;IACH,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED;;OAEG;IACM,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAQ/C;;OAEG;IACM,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAOpD"}
1
+ {"version":3,"file":"public.authorization.d.ts","sourceRoot":"","sources":["../../src/authorization/public.authorization.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAoC,MAAM,uBAAuB,CAAC;AAExF;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,iBAAiB;;IACxD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAY;IAEnC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAKzB,OAAO;IAOP;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,MAAM,CAAC,GAAG,GAAE,4BAAiC,GAAG,mBAAmB;IA+D1E;;;;OAIG;IACG,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOrD;;OAEG;IACH,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED;;OAEG;IACM,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAO/C;;OAEG;IACM,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAMpD"}
@@ -53,6 +53,10 @@ var AuthoritiesContextBuilder = class {
53
53
  this.claimsResolver = options.claimsResolver;
54
54
  this.relationshipResolver = options.relationshipResolver ?? noopRelationshipResolver;
55
55
  }
56
+ /** Whether a relationship resolver was configured; without one every relationship check denies as unresolved. */
57
+ get hasRelationshipResolver() {
58
+ return this.relationshipResolver !== noopRelationshipResolver;
59
+ }
56
60
  /**
57
61
  * Build an evaluation context from AuthInfo and tool input.
58
62
  */
@@ -111,6 +115,7 @@ var AuthoritiesContextBuilder = class {
111
115
  export {
112
116
  AuthoritiesContextBuilder,
113
117
  isAnonymousSubject,
118
+ noopRelationshipResolver,
114
119
  resolveAuthUser,
115
120
  resolveDotPath,
116
121
  signedInSubject
@@ -15,6 +15,24 @@ function invalidRule(problems, policies = []) {
15
15
  evaluatedPolicies: policies
16
16
  };
17
17
  }
18
+ function customEvaluatorNames(rule, seen = /* @__PURE__ */ new Set()) {
19
+ if (typeof rule !== "object" || rule === null || Array.isArray(rule) || seen.has(rule)) return [];
20
+ seen.add(rule);
21
+ const { custom, allOf, anyOf, not } = rule;
22
+ const nested = [...Array.isArray(allOf) ? allOf : [], ...Array.isArray(anyOf) ? anyOf : [], not];
23
+ return [
24
+ ...typeof custom === "object" && custom !== null ? Object.keys(custom) : [],
25
+ ...nested.flatMap((inner) => customEvaluatorNames(inner, seen))
26
+ ];
27
+ }
28
+ function checksRelationships(rule, seen = /* @__PURE__ */ new Set()) {
29
+ if (typeof rule !== "object" || rule === null || Array.isArray(rule) || seen.has(rule)) return false;
30
+ seen.add(rule);
31
+ const { relationships, allOf, anyOf, not } = rule;
32
+ if (relationships !== void 0) return true;
33
+ const nested = [...Array.isArray(allOf) ? allOf : [], ...Array.isArray(anyOf) ? anyOf : [], not];
34
+ return nested.some((inner) => checksRelationships(inner, seen));
35
+ }
18
36
  async function evaluateEvery(items, evaluateItem, evaluatedPolicies = []) {
19
37
  let unresolved;
20
38
  for (const item of items) {
@@ -37,23 +55,40 @@ var AuthoritiesEngine = class {
37
55
  ruleProblems = /* @__PURE__ */ new WeakMap();
38
56
  /**
39
57
  * Problems with an `authorities` value declared on an entry (see {@link findAuthoritiesRuleProblems}),
40
- * and each profile name it uses that no registered profile has. The server reports them when it
41
- * starts; {@link evaluate} denies such a value (an unknown profile as `profile '\u2026' is not registered`).
58
+ * each profile name it uses that no registered profile has, and each custom evaluator it names that
59
+ * is not registered. The server reports them when it starts; {@link evaluate} denies such a value.
42
60
  */
43
61
  findRuleProblems(authorities) {
44
62
  const problems = findAuthoritiesRuleProblems(authorities);
45
63
  if (problems.length > 0) return problems;
46
64
  const names = typeof authorities === "string" ? [authorities] : Array.isArray(authorities) ? authorities : [];
47
- return names.filter((name) => typeof name === "string" && !this.profiles.has(name)).map((name) => `names an unknown profile "${name}"`);
65
+ return [
66
+ ...names.filter((name) => typeof name === "string" && !this.profiles.has(name)).map((name) => `names an unknown profile "${name}"`),
67
+ ...this.unknownEvaluatorProblems(authorities)
68
+ ];
48
69
  }
49
70
  /**
50
- * Problems with every registered profile's rule (see {@link findAuthoritiesRuleProblems}).
51
- * The server reports them when it starts.
71
+ * Problems with every registered profile's rule (see {@link findAuthoritiesRuleProblems}), and each
72
+ * custom evaluator a profile names that is not registered. The server reports them when it starts.
52
73
  */
53
74
  findProfileProblems() {
54
- return Object.entries(this.profiles.getAll()).flatMap(
55
- ([name, policy]) => findAuthoritiesProfileProblems(name, policy)
56
- );
75
+ return Object.entries(this.profiles.getAll()).flatMap(([name, policy]) => {
76
+ const problems = findAuthoritiesProfileProblems(name, policy);
77
+ if (problems.length > 0) return problems;
78
+ return this.unknownEvaluatorProblems(policy).map((problem) => `profile "${name}": ${problem}`);
79
+ });
80
+ }
81
+ /** The registered profiles whose rule checks relationships, at any depth. */
82
+ profilesCheckingRelationships() {
83
+ return Object.entries(this.profiles.getAll()).filter(([, policy]) => checksRelationships(policy)).map(([name]) => name);
84
+ }
85
+ /** Whether an entry's rule object checks relationships, at any depth (a profile it names is not looked into). */
86
+ ruleChecksRelationships(authorities) {
87
+ return checksRelationships(authorities);
88
+ }
89
+ /** A problem for each custom evaluator a rule names, at any depth, that is not registered. */
90
+ unknownEvaluatorProblems(rule) {
91
+ return [...new Set(customEvaluatorNames(rule))].filter((name) => !this.evaluators.has(name)).map((name) => `names an unknown custom evaluator "${name}" (register it in authorities.evaluators)`);
57
92
  }
58
93
  /**
59
94
  * Evaluate an AuthoritiesMetadata value (string, string[], or policy object).
@@ -183,7 +218,8 @@ var AuthoritiesEngine = class {
183
218
  if (!evaluator) {
184
219
  return {
185
220
  granted: false,
186
- deniedBy: `custom evaluator '${name}' is not registered`,
221
+ unresolved: true,
222
+ deniedBy: `custom evaluator '${name}' is not registered (add it to authorities.evaluators)`,
187
223
  evaluatedPolicies: [`custom.${name}`]
188
224
  };
189
225
  }
@@ -1,5 +1,6 @@
1
1
  // libs/auth/src/authorities/authorities.evaluator.ts
2
- import { isAnonymousSubject, resolveDotPath } from "./authorities.context.mjs";
2
+ import { isPatternSafe } from "@frontmcp/utils";
3
+ import { isAnonymousSubject, noopRelationshipResolver, resolveDotPath } from "./authorities.context.mjs";
3
4
  function evaluateRbacRoles(policy, ctx) {
4
5
  const userRoles = ctx.user.roles;
5
6
  if (policy.all) {
@@ -87,6 +88,19 @@ function unresolvedAttribute(policyPath, denialPath, path, value, actual) {
87
88
  evaluatedPolicies: [policyPath]
88
89
  };
89
90
  }
91
+ var MAX_PATTERN_LENGTH = 256;
92
+ var MAX_MATCHED_LENGTH = 1e4;
93
+ function unmatchableReason(actual, pattern) {
94
+ if (typeof pattern !== "string") return void 0;
95
+ if (pattern.length > MAX_PATTERN_LENGTH) return `the pattern is longer than ${MAX_PATTERN_LENGTH} characters`;
96
+ if (!isPatternSafe(pattern)) {
97
+ return "the pattern is not a valid regular expression, or its matching time can grow very fast with the value";
98
+ }
99
+ if (typeof actual === "string" && actual.length > MAX_MATCHED_LENGTH) {
100
+ return `the value is longer than ${MAX_MATCHED_LENGTH} characters`;
101
+ }
102
+ return void 0;
103
+ }
90
104
  function applyOperator(actual, op, expected) {
91
105
  switch (op) {
92
106
  case "eq":
@@ -116,14 +130,7 @@ function applyOperator(actual, op, expected) {
116
130
  case "exists":
117
131
  return expected ? actual !== void 0 && actual !== null : actual === void 0 || actual === null;
118
132
  case "matches":
119
- if (typeof actual !== "string" || typeof expected !== "string") return false;
120
- if (expected.length > 256) return false;
121
- if (/(\+\+|\*\*|\{\d+,\d*\}\{)/.test(expected)) return false;
122
- try {
123
- return new RegExp(expected).test(actual);
124
- } catch {
125
- return false;
126
- }
133
+ return typeof actual === "string" && typeof expected === "string" && new RegExp(expected).test(actual);
127
134
  default:
128
135
  return false;
129
136
  }
@@ -159,6 +166,7 @@ function evaluateAbac(policy, ctx) {
159
166
  const actual = resolveDotPath(envelope, condition.path);
160
167
  const expected = resolveValue(condition.value, ctx);
161
168
  const reported = reportableActual(condition.path, actual);
169
+ const unmatchable = condition.op === "matches" ? unmatchableReason(actual, expected) : void 0;
162
170
  if (expected === void 0) {
163
171
  unresolved ??= unresolvedAttribute(
164
172
  "attributes.conditions",
@@ -167,6 +175,14 @@ function evaluateAbac(policy, ctx) {
167
175
  condition.value,
168
176
  reported
169
177
  );
178
+ } else if (unmatchable !== void 0) {
179
+ unresolved ??= {
180
+ granted: false,
181
+ unresolved: true,
182
+ deniedBy: `attributes.conditions: '${condition.path}' could not be checked: ${unmatchable}`,
183
+ denial: { kind: "attributes", path: denialPath, actual: reported },
184
+ evaluatedPolicies: ["attributes.conditions"]
185
+ };
170
186
  } else if (!applyOperator(actual, condition.op, expected)) {
171
187
  return {
172
188
  granted: false,
@@ -201,6 +217,15 @@ async function evaluateSingleRebac(policy, ctx) {
201
217
  evaluatedPolicies: ["relationships"]
202
218
  };
203
219
  }
220
+ if (ctx.relationships === noopRelationshipResolver) {
221
+ return {
222
+ granted: false,
223
+ unresolved: true,
224
+ deniedBy: `relationships: '${policy.type}' of ${policy.resource} could not be checked: no relationship resolver is configured (set authorities.relationshipResolver)`,
225
+ denial: { kind: "relationships", path: "relationships", expected: `${policy.type}:${policy.resource}` },
226
+ evaluatedPolicies: ["relationships"]
227
+ };
228
+ }
204
229
  const resourceId = resolveResourceId(policy.resourceId, ctx);
205
230
  if (resourceId === void 0) {
206
231
  return {
@@ -247,5 +272,6 @@ export {
247
272
  evaluateRbacPermissions,
248
273
  evaluateRbacRoles,
249
274
  evaluateRebac,
250
- resolveResourceId
275
+ resolveResourceId,
276
+ unmatchableReason
251
277
  };
@@ -1,4 +1,5 @@
1
1
  // libs/auth/src/authorities/authorities.validation.ts
2
+ import { unmatchableReason } from "./authorities.evaluator.mjs";
2
3
  var ABAC_OPERATORS = /* @__PURE__ */ new Set([
3
4
  "eq",
4
5
  "neq",
@@ -82,7 +83,8 @@ function checkConditionValue(op, condition, path) {
82
83
  const expected = OPERATOR_VALUES[op];
83
84
  if (expected && !expected.accepts(value)) return [`${path} must be ${expected.needs} for "${op}"`];
84
85
  if (Array.isArray(value) && value.length === 0 && (op === "in" || op === "notIn")) return [`${path} is empty`];
85
- return [];
86
+ const unmatchable = op === "matches" ? unmatchableReason(void 0, value) : void 0;
87
+ return unmatchable === void 0 ? [] : [`${path} cannot be used: ${unmatchable}`];
86
88
  }
87
89
  function checkAttributes(value, path) {
88
90
  if (!isPlainObject(value)) return [`${path} must be an object with "match" or "conditions"`];
@@ -108,13 +108,13 @@ var AuthorizationBase = class _AuthorizationBase {
108
108
  * Check if a tool is authorized
109
109
  */
110
110
  canAccessTool(toolId) {
111
- return toolId in this.authorizedTools || this.authorizedToolIds.includes(toolId);
111
+ return Object.hasOwn(this.authorizedTools, toolId) || this.authorizedToolIds.includes(toolId);
112
112
  }
113
113
  /**
114
114
  * Check if a prompt is authorized
115
115
  */
116
116
  canAccessPrompt(promptId) {
117
- return promptId in this.authorizedPrompts || this.authorizedPromptIds.includes(promptId);
117
+ return Object.hasOwn(this.authorizedPrompts, promptId) || this.authorizedPromptIds.includes(promptId);
118
118
  }
119
119
  /**
120
120
  * Check if an app is authorized.
@@ -122,7 +122,7 @@ var AuthorizationBase = class _AuthorizationBase {
122
122
  * @param appId - App ID to check
123
123
  */
124
124
  isAppAuthorized(appId) {
125
- return appId in this.authorizedApps || this.authorizedAppIds.includes(appId);
125
+ return Object.hasOwn(this.authorizedApps, appId) || this.authorizedAppIds.includes(appId);
126
126
  }
127
127
  /**
128
128
  * Build URL for progressive/incremental authorization.
@@ -60,9 +60,17 @@ function splitRedirectUri(s) {
60
60
  }
61
61
  return { scheme, userinfo, host, port, rest };
62
62
  }
63
+ function hasAmbiguousCharacter(uri) {
64
+ for (let index = 0; index < uri.length; index++) {
65
+ const code = uri.charCodeAt(index);
66
+ if (code <= 32 || code === 92 || code === 127) return true;
67
+ }
68
+ return false;
69
+ }
63
70
  function globMatchRedirectUri(pattern, input) {
64
71
  const p = splitRedirectUri(pattern);
65
72
  if (!p) return globMatch(pattern, input);
73
+ if (hasAmbiguousCharacter(input)) return false;
66
74
  const u = splitRedirectUri(input);
67
75
  if (!u) return false;
68
76
  return globMatch(p.scheme, u.scheme) && globMatch(p.userinfo, u.userinfo) && globMatch(p.host, u.host) && globMatch(p.port, u.port) && globMatch(p.rest, u.rest);
@@ -8,9 +8,13 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
8
8
  * Issuer identifier for the anonymous authorization
9
9
  */
10
10
  issuer;
11
+ #allTools;
12
+ #allPrompts;
11
13
  constructor(ctx) {
12
14
  super(ctx);
13
15
  this.issuer = ctx.issuer;
16
+ this.#allTools = ctx.allTools;
17
+ this.#allPrompts = ctx.allPrompts;
14
18
  }
15
19
  /**
16
20
  * Create a new PublicAuthorization for anonymous access
@@ -72,6 +76,8 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
72
76
  scopes,
73
77
  expiresAt,
74
78
  issuer,
79
+ allTools: allowedTools === "all",
80
+ allPrompts: allowedPrompts === "all",
75
81
  authorizedTools: allowedTools === "all" ? void 0 : authorizedTools,
76
82
  authorizedToolIds: allowedTools === "all" ? void 0 : authorizedToolIds,
77
83
  authorizedPrompts: allowedPrompts === "all" ? void 0 : authorizedPrompts,
@@ -89,16 +95,16 @@ var PublicAuthorization = class _PublicAuthorization extends AuthorizationBase {
89
95
  );
90
96
  }
91
97
  /**
92
- * Check if all tools are allowed (public access)
98
+ * Check if all tools are allowed (`allowedTools: 'all'`); an empty list allows none
93
99
  */
94
100
  get allowsAllTools() {
95
- return this.authorizedToolIds.length === 0 && Object.keys(this.authorizedTools).length === 0;
101
+ return this.#allTools;
96
102
  }
97
103
  /**
98
- * Check if all prompts are allowed (public access)
104
+ * Check if all prompts are allowed (`allowedPrompts: 'all'`); an empty list allows none
99
105
  */
100
106
  get allowsAllPrompts() {
101
- return this.authorizedPromptIds.length === 0 && Object.keys(this.authorizedPrompts).length === 0;
107
+ return this.#allPrompts;
102
108
  }
103
109
  /**
104
110
  * Override canAccessTool to support 'all' mode
@@ -20,7 +20,9 @@ var RedisCimdCache = class {
20
20
  this.keyPrefix = config.redis.keyPrefix ?? "cimd:";
21
21
  const redisOptions = {};
22
22
  if (config.redis.url) {
23
+ const { port, password, db, tls } = config.redis;
23
24
  redisOptions.url = config.redis.url;
25
+ redisOptions.config = { port, password, db, tls };
24
26
  } else if (config.redis.host) {
25
27
  redisOptions.config = {
26
28
  host: config.redis.host,
@@ -21,7 +21,13 @@ import {
21
21
  clientJwksSchema,
22
22
  clientMetadataDocumentSchema
23
23
  } from "./cimd.types.mjs";
24
- import { assertHostNotSsrf, hasOnlyLocalhostRedirectUris, isCimdClientId, validateClientIdUrl } from "./cimd.validator.mjs";
24
+ import {
25
+ assertHostNotSsrf,
26
+ blocksPrivateAddressesFor,
27
+ hasOnlyLocalhostRedirectUris,
28
+ isCimdClientId,
29
+ validateClientIdUrl
30
+ } from "./cimd.validator.mjs";
25
31
  var MAX_CACHED_KEY_SETS = 500;
26
32
  var KEY_SET_REFRESH_COOLDOWN_MS = 3e4;
27
33
  var CimdService = class {
@@ -130,15 +136,15 @@ var CimdService = class {
130
136
  }
131
137
  this.logger.info(`Fetching CIMD document: ${clientId}`);
132
138
  const { document, headers } = await this.fetchMetadataDocument(clientId);
133
- this.validateDocument(clientId, document);
134
- if (this.securityConfig.warnOnLocalhostRedirects && hasOnlyLocalhostRedirectUris(document.redirect_uris)) {
139
+ const metadata = this.validateDocument(clientId, document);
140
+ if (this.securityConfig.warnOnLocalhostRedirects && hasOnlyLocalhostRedirectUris(metadata.redirect_uris)) {
135
141
  this.logger.warn(`CIMD client "${clientId}" has only localhost redirect URIs - this may be a development client`);
136
142
  }
137
- await cache.set(clientId, document, headers);
143
+ await cache.set(clientId, metadata, headers);
138
144
  const entry = await cache.get(clientId);
139
145
  return {
140
146
  isCimdClient: true,
141
- metadata: document,
147
+ metadata,
142
148
  fromCache: false,
143
149
  expiresAt: entry?.expiresAt,
144
150
  etag: entry?.etag,
@@ -300,8 +306,9 @@ var CimdService = class {
300
306
  let redirectCount = 0;
301
307
  let isFirstRequest = true;
302
308
  while (true) {
303
- if (this.securityConfig.blockPrivateIPs && !this.securityConfig.allowInsecureForTesting) {
304
- await assertHostNotSsrf(new URL(currentUrl).hostname, url);
309
+ const hostname = new URL(currentUrl).hostname;
310
+ if (blocksPrivateAddressesFor(hostname, this.securityConfig)) {
311
+ await assertHostNotSsrf(hostname, url);
305
312
  }
306
313
  const headers = {
307
314
  Accept: "application/json"
@@ -436,6 +443,7 @@ var CimdService = class {
436
443
  *
437
444
  * @param clientId - The URL from which the document was fetched
438
445
  * @param document - The document to validate
446
+ * @returns The parsed document, with the schema's defaults for the fields it leaves out
439
447
  */
440
448
  validateDocument(clientId, document) {
441
449
  const result = clientMetadataDocumentSchema.safeParse(document);
@@ -449,6 +457,7 @@ var CimdService = class {
449
457
  if (result.data.client_id !== clientId) {
450
458
  throw new CimdClientIdMismatchError(clientId, result.data.client_id);
451
459
  }
460
+ return result.data;
452
461
  }
453
462
  };
454
463
  var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "[::1]", "localhost"]);
@@ -34,6 +34,10 @@ function isLocalhostHost(hostname) {
34
34
  const lower = hostname.toLowerCase();
35
35
  return lower === "localhost" || lower === "127.0.0.1" || lower === "[::1]" || lower.endsWith(".localhost");
36
36
  }
37
+ function blocksPrivateAddressesFor(hostname, securityConfig) {
38
+ if (!(securityConfig?.blockPrivateIPs ?? true)) return false;
39
+ return !(securityConfig?.allowInsecureForTesting && isLocalhostHost(hostname));
40
+ }
37
41
  function validateClientIdUrl(clientId, securityConfig) {
38
42
  if (!clientId || typeof clientId !== "string") {
39
43
  throw new InvalidClientIdUrlError(clientId || "", "client_id must be a non-empty string");
@@ -57,7 +61,6 @@ function validateClientIdUrl(clientId, securityConfig) {
57
61
  );
58
62
  }
59
63
  const config = {
60
- blockPrivateIPs: securityConfig?.blockPrivateIPs ?? true,
61
64
  allowedDomains: securityConfig?.allowedDomains,
62
65
  blockedDomains: securityConfig?.blockedDomains
63
66
  };
@@ -71,7 +74,7 @@ function validateClientIdUrl(clientId, securityConfig) {
71
74
  throw new CimdSecurityError(clientId, `Domain "${url.hostname}" is blocked`);
72
75
  }
73
76
  }
74
- if (config.blockPrivateIPs && !allowInsecure) {
77
+ if (blocksPrivateAddressesFor(url.hostname, securityConfig)) {
75
78
  const ssrfCheck = checkSsrfProtection(url.hostname);
76
79
  if (!ssrfCheck.allowed) {
77
80
  throw new CimdSecurityError(clientId, ssrfCheck.reason);
@@ -209,6 +212,7 @@ function hasOnlyLocalhostRedirectUris(redirectUris) {
209
212
  }
210
213
  export {
211
214
  assertHostNotSsrf,
215
+ blocksPrivateAddressesFor,
212
216
  checkSsrfProtection,
213
217
  hasOnlyLocalhostRedirectUris,
214
218
  isCimdClientId,
@@ -81,6 +81,13 @@ function detectAuthProviders(parentAuth, apps) {
81
81
  }
82
82
  const providerId = deriveProviderId(app.auth);
83
83
  const existing = providers.get(providerId);
84
+ const providerUrl = getProviderUrl(app.auth);
85
+ if (existing && providerUrl && existing.providerUrl && !sameIssuer(providerUrl, existing.providerUrl)) {
86
+ const owner = existing.isParentProvider ? "the server" : `app "${existing.appIds[0]}"`;
87
+ validationErrors.push(
88
+ `App "${app.id}" names the identity provider ${providerUrl} and ${owner} names ${existing.providerUrl}, but both get the provider id "${providerId}", so a token from one would be accepted for the other. Set a distinct providerConfig.id on each.`
89
+ );
90
+ }
84
91
  if (existing) {
85
92
  existing.appIds.push(app.id);
86
93
  const newScopes = extractScopes(app.auth);
@@ -137,6 +144,14 @@ function staticParentEnforces(parentAuth, appAuth) {
137
144
  const sameChallenge = parent.data.header.toLowerCase() === app.data.header.toLowerCase() && parent.data.scheme === app.data.scheme;
138
145
  return sameChallenge && parent.data.tokens.every((token) => app.data.tokens.includes(token));
139
146
  }
147
+ function sameIssuer(first, second) {
148
+ return issuerIdentity(first) === issuerIdentity(second);
149
+ }
150
+ function issuerIdentity(url) {
151
+ let identity = URL.canParse(url) ? new URL(url).href : url;
152
+ while (identity.endsWith("/")) identity = identity.slice(0, -1);
153
+ return identity;
154
+ }
140
155
  function getProviderUrl(options) {
141
156
  if (isTransparentMode(options)) {
142
157
  return options.provider;
@@ -9,7 +9,14 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
9
  });
10
10
 
11
11
  // libs/auth/src/jwks/jwks.service.ts
12
- import { bytesToHex, isProduction, isRedirectResponse, randomBytes, rsaVerify } from "@frontmcp/utils";
12
+ import {
13
+ bytesToHex,
14
+ isProduction,
15
+ isRedirectResponse,
16
+ randomBytes,
17
+ readTextWithLimit,
18
+ rsaVerify
19
+ } from "@frontmcp/utils";
13
20
  import { resolveAndCheckHostname } from "../cimd/cimd.validator.mjs";
14
21
  import { noopAuthLogger } from "../common/auth-logger.interface.mjs";
15
22
  import { loadJose } from "./jose.loader.mjs";
@@ -438,14 +445,7 @@ var JwksService = class {
438
445
  continue;
439
446
  }
440
447
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
441
- const contentLength = res.headers.get("content-length");
442
- if (contentLength && Number(contentLength) > MAX_JWKS_FETCH_BYTES) {
443
- throw new Error("response too large");
444
- }
445
- const text = await res.text();
446
- if (text.length > MAX_JWKS_FETCH_BYTES) {
447
- throw new Error("response too large");
448
- }
448
+ const text = await readTextWithLimit(res, MAX_JWKS_FETCH_BYTES);
449
449
  return JSON.parse(text);
450
450
  }
451
451
  } finally {
@@ -87,13 +87,20 @@ var LoopbackTokenAuth = class {
87
87
  const previous = this.failures.get(client);
88
88
  const count = previous && now - previous.lastAt <= lockoutMs ? previous.count + 1 : 1;
89
89
  const locked = count >= maxFailedAttempts;
90
- if (!previous && this.failures.size >= MAX_TRACKED_CLIENTS) this.forgetIdleClients(now);
90
+ this.failures.delete(client);
91
+ if (this.failures.size >= MAX_TRACKED_CLIENTS) this.forgetOldestClients(now);
91
92
  this.failures.set(client, { count: locked ? 0 : count, lastAt: now, lockedUntil: locked ? now + lockoutMs : 0 });
92
93
  return locked ? LOCKED : INVALID;
93
94
  }
94
- forgetIdleClients(now) {
95
+ /**
96
+ * Clients are kept in the order of their last failure, so the idle ones come first: drop them, and stop at the
97
+ * first active one, unless the map is still full, when that oldest active one goes too.
98
+ */
99
+ forgetOldestClients(now) {
95
100
  for (const [client, failures] of this.failures) {
96
- if (failures.lockedUntil <= now && now - failures.lastAt > this.options.lockoutMs) this.failures.delete(client);
101
+ const idle = failures.lockedUntil <= now && now - failures.lastAt > this.options.lockoutMs;
102
+ if (!idle && this.failures.size < MAX_TRACKED_CLIENTS) return;
103
+ this.failures.delete(client);
97
104
  }
98
105
  }
99
106
  };