@naylence/runtime 0.3.21 → 0.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.
Files changed (85) hide show
  1. package/dist/browser/index.cjs +3144 -1307
  2. package/dist/browser/index.mjs +3116 -1301
  3. package/dist/cjs/naylence/fame/factory-manifest.js +6 -0
  4. package/dist/cjs/naylence/fame/node/node-event-listener.js +4 -0
  5. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer-factory.js +147 -0
  6. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer.js +291 -0
  7. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  8. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  9. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-definition.js +60 -0
  10. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-factory.js +35 -0
  11. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +35 -0
  12. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source.js +2 -0
  13. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy.js +2 -0
  14. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +99 -0
  15. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy.js +449 -0
  16. package/dist/cjs/naylence/fame/security/auth/policy/index.js +40 -0
  17. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +101 -0
  18. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +164 -0
  19. package/dist/cjs/naylence/fame/security/auth/policy/pattern-matcher.js +195 -0
  20. package/dist/cjs/naylence/fame/security/auth/policy/scope-matcher.js +169 -0
  21. package/dist/cjs/naylence/fame/security/auth/policy-authorizer.js +2 -0
  22. package/dist/cjs/naylence/fame/security/default-security-manager.js +94 -0
  23. package/dist/cjs/naylence/fame/security/index.js +3 -0
  24. package/dist/cjs/naylence/fame/security/node-security-profile-factory.js +3 -1
  25. package/dist/cjs/naylence/fame/sentinel/router.js +67 -1
  26. package/dist/cjs/naylence/fame/sentinel/sentinel.js +46 -2
  27. package/dist/cjs/naylence/fame/util/register-runtime-factories.js +2 -0
  28. package/dist/cjs/version.js +2 -2
  29. package/dist/esm/naylence/fame/factory-manifest.js +6 -0
  30. package/dist/esm/naylence/fame/node/node-event-listener.js +4 -0
  31. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer-factory.js +110 -0
  32. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer.js +287 -0
  33. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  34. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  35. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-definition.js +57 -0
  36. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-factory.js +31 -0
  37. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +31 -0
  38. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source.js +1 -0
  39. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy.js +1 -0
  40. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +62 -0
  41. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy.js +445 -0
  42. package/dist/esm/naylence/fame/security/auth/policy/index.js +20 -0
  43. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +64 -0
  44. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +127 -0
  45. package/dist/esm/naylence/fame/security/auth/policy/pattern-matcher.js +185 -0
  46. package/dist/esm/naylence/fame/security/auth/policy/scope-matcher.js +162 -0
  47. package/dist/esm/naylence/fame/security/auth/policy-authorizer.js +1 -0
  48. package/dist/esm/naylence/fame/security/default-security-manager.js +94 -0
  49. package/dist/esm/naylence/fame/security/index.js +3 -0
  50. package/dist/esm/naylence/fame/security/node-security-profile-factory.js +2 -0
  51. package/dist/esm/naylence/fame/sentinel/router.js +64 -0
  52. package/dist/esm/naylence/fame/sentinel/sentinel.js +47 -3
  53. package/dist/esm/naylence/fame/util/register-runtime-factories.js +2 -0
  54. package/dist/esm/version.js +2 -2
  55. package/dist/node/index.cjs +3140 -1303
  56. package/dist/node/index.mjs +3116 -1301
  57. package/dist/node/node.cjs +3191 -1338
  58. package/dist/node/node.mjs +3167 -1336
  59. package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
  60. package/dist/types/naylence/fame/node/node-event-listener.d.ts +31 -0
  61. package/dist/types/naylence/fame/security/auth/authorizer.d.ts +37 -0
  62. package/dist/types/naylence/fame/security/auth/default-policy-authorizer-factory.d.ts +55 -0
  63. package/dist/types/naylence/fame/security/auth/default-policy-authorizer.d.ts +99 -0
  64. package/dist/types/naylence/fame/security/auth/oauth2-authorizer-factory.d.ts +2 -0
  65. package/dist/types/naylence/fame/security/auth/oauth2-authorizer.d.ts +2 -0
  66. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-definition.d.ts +166 -0
  67. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-factory.d.ts +38 -0
  68. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source-factory.d.ts +38 -0
  69. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source.d.ts +20 -0
  70. package/dist/types/naylence/fame/security/auth/policy/authorization-policy.d.ts +55 -0
  71. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy-factory.d.ts +42 -0
  72. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy.d.ts +78 -0
  73. package/dist/types/naylence/fame/security/auth/policy/index.d.ts +19 -0
  74. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.d.ts +51 -0
  75. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source.d.ts +67 -0
  76. package/dist/types/naylence/fame/security/auth/policy/pattern-matcher.d.ts +84 -0
  77. package/dist/types/naylence/fame/security/auth/policy/scope-matcher.d.ts +61 -0
  78. package/dist/types/naylence/fame/security/auth/policy-authorizer.d.ts +12 -0
  79. package/dist/types/naylence/fame/security/default-security-manager.d.ts +22 -0
  80. package/dist/types/naylence/fame/security/index.d.ts +2 -0
  81. package/dist/types/naylence/fame/security/node-security-profile-factory.d.ts +1 -0
  82. package/dist/types/naylence/fame/sentinel/router.d.ts +68 -0
  83. package/dist/types/naylence/fame/sentinel/sentinel.d.ts +16 -0
  84. package/dist/types/version.d.ts +1 -1
  85. package/package.json +1 -1
@@ -65,6 +65,7 @@ exports.MODULES = [
65
65
  "./placement/static-node-placement-strategy-factory.js",
66
66
  "./security/auth/bearer-token-header-auth-injection-strategy-factory.js",
67
67
  "./security/auth/default-authorizer-factory.js",
68
+ "./security/auth/default-policy-authorizer-factory.js",
68
69
  "./security/auth/jwks-jwt-token-verifier-factory.js",
69
70
  "./security/auth/jwt-token-issuer-factory.js",
70
71
  "./security/auth/jwt-token-verifier-factory.js",
@@ -76,6 +77,8 @@ exports.MODULES = [
76
77
  "./security/auth/oauth2-authorizer-factory.js",
77
78
  "./security/auth/oauth2-client-credentials-token-provider-factory.js",
78
79
  "./security/auth/oauth2-pkce-token-provider-factory.js",
80
+ "./security/auth/policy/basic-authorization-policy-factory.js",
81
+ "./security/auth/policy/local-file-authorization-policy-source-factory.js",
79
82
  "./security/auth/query-param-auth-injection-strategy-factory.js",
80
83
  "./security/auth/shared-secret-authorizer-factory.js",
81
84
  "./security/auth/shared-secret-token-provider-factory.js",
@@ -144,6 +147,7 @@ exports.MODULE_LOADERS = {
144
147
  "./placement/static-node-placement-strategy-factory.js": () => Promise.resolve().then(() => __importStar(require("./placement/static-node-placement-strategy-factory.js"))),
145
148
  "./security/auth/bearer-token-header-auth-injection-strategy-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/bearer-token-header-auth-injection-strategy-factory.js"))),
146
149
  "./security/auth/default-authorizer-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/default-authorizer-factory.js"))),
150
+ "./security/auth/default-policy-authorizer-factory.js": () => Promise.resolve().then(() => __importStar(require(/* webpackIgnore: true */ /* @vite-ignore */ "./security/auth/default-policy-authorizer-factory.js"))),
147
151
  "./security/auth/jwks-jwt-token-verifier-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/jwks-jwt-token-verifier-factory.js"))),
148
152
  "./security/auth/jwt-token-issuer-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/jwt-token-issuer-factory.js"))),
149
153
  "./security/auth/jwt-token-verifier-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/jwt-token-verifier-factory.js"))),
@@ -155,6 +159,8 @@ exports.MODULE_LOADERS = {
155
159
  "./security/auth/oauth2-authorizer-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/oauth2-authorizer-factory.js"))),
156
160
  "./security/auth/oauth2-client-credentials-token-provider-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/oauth2-client-credentials-token-provider-factory.js"))),
157
161
  "./security/auth/oauth2-pkce-token-provider-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/oauth2-pkce-token-provider-factory.js"))),
162
+ "./security/auth/policy/basic-authorization-policy-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/policy/basic-authorization-policy-factory.js"))),
163
+ "./security/auth/policy/local-file-authorization-policy-source-factory.js": () => Promise.resolve().then(() => __importStar(require(/* webpackIgnore: true */ /* @vite-ignore */ "./security/auth/policy/local-file-authorization-policy-source-factory.js"))),
158
164
  "./security/auth/query-param-auth-injection-strategy-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/query-param-auth-injection-strategy-factory.js"))),
159
165
  "./security/auth/shared-secret-authorizer-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/shared-secret-authorizer-factory.js"))),
160
166
  "./security/auth/shared-secret-token-provider-factory.js": () => Promise.resolve().then(() => __importStar(require("./security/auth/shared-secret-token-provider-factory.js"))),
@@ -48,6 +48,10 @@ class BaseNodeEventListener {
48
48
  // Default implementation passes envelope through unchanged
49
49
  return envelope;
50
50
  }
51
+ async onRoutingActionSelected(_node, _envelope, selected, _state, _context) {
52
+ // Default implementation returns the selected action unchanged
53
+ return selected;
54
+ }
51
55
  async onForwardUpstream(_node, envelope, _context) {
52
56
  // Default implementation passes envelope through unchanged
53
57
  return envelope;
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DefaultPolicyAuthorizerFactory = exports.FACTORY_META = void 0;
37
+ const lazy_import_js_1 = require("../../util/lazy-import.js");
38
+ const authorizer_factory_js_1 = require("./authorizer-factory.js");
39
+ const token_verifier_factory_js_1 = require("./token-verifier-factory.js");
40
+ const authorization_policy_source_factory_js_1 = require("./policy/authorization-policy-source-factory.js");
41
+ const authorization_policy_factory_js_1 = require("./policy/authorization-policy-factory.js");
42
+ let defaultPolicyAuthorizerModulePromise = null;
43
+ async function getDefaultPolicyAuthorizerModule() {
44
+ if (!defaultPolicyAuthorizerModulePromise) {
45
+ defaultPolicyAuthorizerModulePromise = (0, lazy_import_js_1.safeImport)(() => Promise.resolve().then(() => __importStar(require('./default-policy-authorizer.js'))), 'default-policy-authorizer');
46
+ }
47
+ return defaultPolicyAuthorizerModulePromise;
48
+ }
49
+ function normalizeConfig(config) {
50
+ if (!config) {
51
+ return {};
52
+ }
53
+ const candidate = config;
54
+ const verifierConfig = candidate.verifier ?? null;
55
+ if (verifierConfig && typeof verifierConfig !== 'object') {
56
+ throw new Error('PolicyAuthorizer verifier configuration must be an object');
57
+ }
58
+ const policyConfig = candidate.policy ?? null;
59
+ if (policyConfig && typeof policyConfig !== 'object') {
60
+ throw new Error('PolicyAuthorizer policy configuration must be an object');
61
+ }
62
+ const policySourceConfig = candidate.policySource ?? candidate.policy_source ?? null;
63
+ if (policySourceConfig && typeof policySourceConfig !== 'object') {
64
+ throw new Error('PolicyAuthorizer policySource configuration must be an object');
65
+ }
66
+ return {
67
+ verifier: verifierConfig,
68
+ policy: policyConfig,
69
+ policySource: policySourceConfig,
70
+ };
71
+ }
72
+ function isTokenVerifier(candidate) {
73
+ return Boolean(candidate && typeof candidate.verify === 'function');
74
+ }
75
+ function isAuthorizationPolicy(candidate) {
76
+ return Boolean(candidate &&
77
+ typeof candidate.evaluateRequest === 'function');
78
+ }
79
+ function isAuthorizationPolicySource(candidate) {
80
+ return Boolean(candidate &&
81
+ typeof candidate.loadPolicy === 'function');
82
+ }
83
+ /**
84
+ * Factory metadata for registration.
85
+ */
86
+ exports.FACTORY_META = {
87
+ base: authorizer_factory_js_1.AUTHORIZER_FACTORY_BASE_TYPE,
88
+ key: 'PolicyAuthorizer',
89
+ };
90
+ /**
91
+ * Factory for creating DefaultPolicyAuthorizer instances.
92
+ *
93
+ * This factory uses lazy loading to avoid pulling in Node.js-specific
94
+ * code in browser environments.
95
+ */
96
+ class DefaultPolicyAuthorizerFactory extends authorizer_factory_js_1.AuthorizerFactory {
97
+ constructor() {
98
+ super(...arguments);
99
+ this.type = 'PolicyAuthorizer';
100
+ this.isDefault = true;
101
+ }
102
+ /**
103
+ * Creates a DefaultPolicyAuthorizer from the given configuration.
104
+ *
105
+ * @param config - Configuration for the authorizer
106
+ * @param factoryArgs - Additional factory arguments:
107
+ * - TokenVerifier instance
108
+ * - AuthorizationPolicy instance
109
+ * - AuthorizationPolicySource instance
110
+ * @returns The created authorizer
111
+ */
112
+ async create(config, ...factoryArgs) {
113
+ const normalized = normalizeConfig(config);
114
+ // Resolve token verifier
115
+ let tokenVerifier = factoryArgs.find(isTokenVerifier);
116
+ if (!tokenVerifier && normalized.verifier) {
117
+ tokenVerifier = await token_verifier_factory_js_1.TokenVerifierFactory.createTokenVerifier(normalized.verifier);
118
+ }
119
+ if (!tokenVerifier) {
120
+ throw new Error('PolicyAuthorizer requires a verifier configuration or instance');
121
+ }
122
+ // Resolve policy or policy source
123
+ let policy = factoryArgs.find(isAuthorizationPolicy);
124
+ let policySource = factoryArgs.find(isAuthorizationPolicySource);
125
+ // Create policy from config if not provided as argument
126
+ if (!policy && normalized.policy) {
127
+ policy = await authorization_policy_factory_js_1.AuthorizationPolicyFactory.createAuthorizationPolicy(normalized.policy);
128
+ }
129
+ // Create policy source from config if not provided as argument
130
+ if (!policySource && normalized.policySource) {
131
+ policySource =
132
+ await authorization_policy_source_factory_js_1.AuthorizationPolicySourceFactory.createAuthorizationPolicySource(normalized.policySource);
133
+ }
134
+ // Validate that we have either policy or policy source
135
+ if (!policy && !policySource) {
136
+ throw new Error('PolicyAuthorizer requires either a policy or policySource configuration');
137
+ }
138
+ const { DefaultPolicyAuthorizer } = await getDefaultPolicyAuthorizerModule();
139
+ return new DefaultPolicyAuthorizer({
140
+ tokenVerifier,
141
+ policy,
142
+ policySource,
143
+ });
144
+ }
145
+ }
146
+ exports.DefaultPolicyAuthorizerFactory = DefaultPolicyAuthorizerFactory;
147
+ exports.default = DefaultPolicyAuthorizerFactory;
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultPolicyAuthorizer = void 0;
4
+ const core_1 = require("@naylence/core");
5
+ const logging_js_1 = require("../../util/logging.js");
6
+ const logger = (0, logging_js_1.getLogger)('naylence.fame.security.auth.default_policy_authorizer');
7
+ function decodeCredentials(credentials) {
8
+ if (typeof TextDecoder !== 'undefined') {
9
+ return new TextDecoder().decode(credentials);
10
+ }
11
+ if (typeof Buffer !== 'undefined') {
12
+ return Buffer.from(credentials).toString('utf-8');
13
+ }
14
+ throw new Error('Unable to decode credential bytes without TextDecoder support');
15
+ }
16
+ function normalizeToken(credentials) {
17
+ const raw = typeof credentials === 'string'
18
+ ? credentials
19
+ : decodeCredentials(credentials);
20
+ const trimmed = raw.trim();
21
+ if (trimmed.length === 0) {
22
+ return undefined;
23
+ }
24
+ if (trimmed.toLowerCase().startsWith('bearer ')) {
25
+ const candidate = trimmed.slice(7).trim();
26
+ return candidate.length > 0 ? candidate : undefined;
27
+ }
28
+ return trimmed;
29
+ }
30
+ function normalizeOptions(options) {
31
+ if (options === undefined || options === null) {
32
+ return {};
33
+ }
34
+ if (typeof options !== 'object') {
35
+ throw new TypeError('DefaultPolicyAuthorizer options must be an object');
36
+ }
37
+ const candidate = options;
38
+ return {
39
+ tokenVerifier: candidate.tokenVerifier ?? candidate.token_verifier,
40
+ policy: candidate.policy,
41
+ policySource: candidate.policySource ?? candidate.policy_source,
42
+ };
43
+ }
44
+ /**
45
+ * An authorizer that delegates authorization decisions to a pluggable policy.
46
+ *
47
+ * This authorizer combines token-based authentication with policy-based
48
+ * authorization. The token verifier handles authentication (validating
49
+ * credentials), while the authorization policy handles authorization
50
+ * decisions (allow/deny based on the request context).
51
+ */
52
+ class DefaultPolicyAuthorizer {
53
+ constructor(options = {}) {
54
+ this.policyLoaded = false;
55
+ const normalized = normalizeOptions(options);
56
+ if (normalized.tokenVerifier) {
57
+ this.tokenVerifierImpl = normalized.tokenVerifier;
58
+ }
59
+ if (normalized.policy) {
60
+ this.policyImpl = normalized.policy;
61
+ this.policyLoaded = true;
62
+ }
63
+ if (normalized.policySource) {
64
+ this.policySource = normalized.policySource;
65
+ }
66
+ // Validate that we have either a policy or a policy source
67
+ if (!normalized.policy && !normalized.policySource) {
68
+ throw new Error('DefaultPolicyAuthorizer requires either a policy or a policySource');
69
+ }
70
+ }
71
+ /**
72
+ * The currently active authorization policy.
73
+ */
74
+ get policy() {
75
+ if (!this.policyImpl) {
76
+ throw new Error('Authorization policy not loaded. Call ensurePolicyLoaded() first.');
77
+ }
78
+ return this.policyImpl;
79
+ }
80
+ /**
81
+ * The token verifier used for authentication.
82
+ */
83
+ get tokenVerifier() {
84
+ if (!this.tokenVerifierImpl) {
85
+ throw new Error('DefaultPolicyAuthorizer is not initialized properly, missing tokenVerifier');
86
+ }
87
+ return this.tokenVerifierImpl;
88
+ }
89
+ set tokenVerifier(verifier) {
90
+ this.tokenVerifierImpl = verifier;
91
+ }
92
+ /**
93
+ * Ensures the authorization policy is loaded.
94
+ * If using a policy source, loads the policy from it.
95
+ */
96
+ async ensurePolicyLoaded() {
97
+ if (this.policyLoaded && this.policyImpl) {
98
+ return;
99
+ }
100
+ if (!this.policySource) {
101
+ throw new Error('No policy source configured and no policy provided');
102
+ }
103
+ logger.debug('loading_policy_from_source');
104
+ this.policyImpl = await this.policySource.loadPolicy();
105
+ this.policyLoaded = true;
106
+ logger.info('policy_loaded_from_source');
107
+ }
108
+ /**
109
+ * Reloads the authorization policy from the policy source.
110
+ * Only works if a policy source was configured.
111
+ */
112
+ async reloadPolicy() {
113
+ if (!this.policySource) {
114
+ throw new Error('Cannot reload policy: no policy source configured');
115
+ }
116
+ logger.debug('reloading_policy_from_source');
117
+ this.policyImpl = await this.policySource.loadPolicy();
118
+ this.policyLoaded = true;
119
+ logger.info('policy_reloaded_from_source');
120
+ }
121
+ /**
122
+ * Authenticates credentials and returns an authorization context.
123
+ *
124
+ * @param credentials - The credentials to authenticate (token string or bytes)
125
+ * @returns The authorization context if authentication succeeds, undefined otherwise
126
+ */
127
+ async authenticate(credentials) {
128
+ const token = normalizeToken(credentials);
129
+ if (!token) {
130
+ return undefined;
131
+ }
132
+ try {
133
+ const verifier = this.tokenVerifier;
134
+ const context = await verifier.verify(token);
135
+ return (0, core_1.createAuthorizationContext)({
136
+ ...context,
137
+ authenticated: true,
138
+ authorized: false, // Authorization happens in authorize()
139
+ authMethod: context.authMethod ?? 'jwt',
140
+ });
141
+ }
142
+ catch (error) {
143
+ logger.warning('token_verification_failed', {
144
+ error: error instanceof Error ? error.message : String(error),
145
+ });
146
+ return undefined;
147
+ }
148
+ }
149
+ /**
150
+ * Authorizes a request using the configured authorization policy.
151
+ *
152
+ * For NodeAttach frames, evaluates policy with action='Connect'.
153
+ * For other frames, this method performs basic authentication validation
154
+ * but does NOT infer send/receive actions. Route-level authorization
155
+ * is handled separately via authorizeRoute().
156
+ *
157
+ * @param node - The node handling the request
158
+ * @param envelope - The FAME envelope being authorized
159
+ * @param context - Optional delivery context
160
+ * @returns The authorization context if authorized, undefined if denied
161
+ */
162
+ async authorize(node, envelope, context) {
163
+ const authorization = context?.security?.authorization;
164
+ // Must be authenticated first
165
+ if (!authorization || !authorization.authenticated) {
166
+ logger.debug('authorization_denied_not_authenticated');
167
+ return undefined;
168
+ }
169
+ // Ensure policy is loaded
170
+ await this.ensurePolicyLoaded();
171
+ // For NodeAttach frames, evaluate policy with 'Connect' action
172
+ const frameType = envelope.frame?.type;
173
+ if (frameType === 'NodeAttach') {
174
+ let decision;
175
+ try {
176
+ decision = await this.policy.evaluateRequest(node, envelope, context, 'Connect');
177
+ }
178
+ catch (error) {
179
+ logger.error('policy_evaluation_failed', {
180
+ error: error instanceof Error ? error.message : String(error),
181
+ action: 'Connect',
182
+ });
183
+ return undefined;
184
+ }
185
+ if (decision.effect === 'allow') {
186
+ logger.debug('authorization_allowed', {
187
+ matchedRule: decision.matchedRule,
188
+ reason: decision.reason,
189
+ action: 'Connect',
190
+ });
191
+ return (0, core_1.createAuthorizationContext)({
192
+ ...authorization,
193
+ authorized: true,
194
+ authMethod: authorization.authMethod ?? 'policy',
195
+ });
196
+ }
197
+ else {
198
+ logger.debug('authorization_denied', {
199
+ matchedRule: decision.matchedRule,
200
+ reason: decision.reason,
201
+ action: 'Connect',
202
+ });
203
+ return undefined;
204
+ }
205
+ }
206
+ // For non-NodeAttach frames, authentication is sufficient at this stage.
207
+ // Route-level authorization is performed via authorizeRoute() after
208
+ // the routing decision is made.
209
+ logger.debug('authorization_passed_authentication_only', {
210
+ envp_id: envelope.id,
211
+ frame_type: frameType,
212
+ });
213
+ return (0, core_1.createAuthorizationContext)({
214
+ ...authorization,
215
+ authorized: true,
216
+ authMethod: authorization.authMethod ?? 'policy',
217
+ });
218
+ }
219
+ /**
220
+ * Authorizes a routing action after the routing decision has been made.
221
+ *
222
+ * This method evaluates the authorization policy with the explicitly
223
+ * provided action token (ForwardUpstream, ForwardDownstream, ForwardPeer,
224
+ * DeliverLocal).
225
+ *
226
+ * @param node - The node handling the request
227
+ * @param envelope - The FAME envelope being routed
228
+ * @param action - The authorization action token from the routing decision
229
+ * @param context - Optional delivery context
230
+ * @returns RouteAuthorizationResult with authorization decision
231
+ */
232
+ async authorizeRoute(node, envelope, action, context) {
233
+ const authorization = context?.security?.authorization;
234
+ // If not authenticated, deny route authorization
235
+ if (!authorization || !authorization.authenticated) {
236
+ logger.debug('route_authorization_denied_not_authenticated', {
237
+ action,
238
+ });
239
+ return {
240
+ authorized: false,
241
+ denialReason: 'not_authenticated',
242
+ };
243
+ }
244
+ // Ensure policy is loaded
245
+ await this.ensurePolicyLoaded();
246
+ // Evaluate the policy with the provided action
247
+ let decision;
248
+ try {
249
+ decision = await this.policy.evaluateRequest(node, envelope, context, action);
250
+ }
251
+ catch (error) {
252
+ logger.error('route_policy_evaluation_failed', {
253
+ error: error instanceof Error ? error.message : String(error),
254
+ action,
255
+ });
256
+ return {
257
+ authorized: false,
258
+ denialReason: 'policy_evaluation_error',
259
+ };
260
+ }
261
+ if (decision.effect === 'allow') {
262
+ logger.debug('route_authorization_allowed', {
263
+ matchedRule: decision.matchedRule,
264
+ reason: decision.reason,
265
+ action,
266
+ });
267
+ return {
268
+ authorized: true,
269
+ authContext: (0, core_1.createAuthorizationContext)({
270
+ ...authorization,
271
+ authorized: true,
272
+ authMethod: authorization.authMethod ?? 'policy',
273
+ }),
274
+ matchedRule: decision.matchedRule,
275
+ };
276
+ }
277
+ else {
278
+ logger.debug('route_authorization_denied', {
279
+ matchedRule: decision.matchedRule,
280
+ reason: decision.reason,
281
+ action,
282
+ });
283
+ return {
284
+ authorized: false,
285
+ denialReason: decision.reason ?? 'policy_denied',
286
+ matchedRule: decision.matchedRule,
287
+ };
288
+ }
289
+ }
290
+ }
291
+ exports.DefaultPolicyAuthorizer = DefaultPolicyAuthorizer;
@@ -87,6 +87,7 @@ class OAuth2AuthorizerFactory extends authorizer_factory_js_1.AuthorizerFactory
87
87
  maxTtlSec: normalized.maxTtlSec,
88
88
  reverseAuthTtlSec: normalized.reverseAuthTtlSec,
89
89
  enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
90
+ trustedClientScope: normalized.trustedClientScope,
90
91
  };
91
92
  if (tokenIssuer) {
92
93
  authorizerOptions.tokenIssuer = tokenIssuer;
@@ -157,6 +158,11 @@ function normalizeConfig(config) {
157
158
  : ttl_constants_js_1.DEFAULT_REVERSE_AUTH_TTL_SEC;
158
159
  const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
159
160
  source.enforce_token_subject_node_identity, false);
161
+ const trustedClientScope = typeof source.trustedClientScope === 'string'
162
+ ? source.trustedClientScope
163
+ : typeof source.trusted_client_scope === 'string'
164
+ ? source.trusted_client_scope
165
+ : undefined;
160
166
  const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
161
167
  const tokenVerifierConfig = normalizeTokenVerifierConfig({
162
168
  config: tokenVerifierConfigInput,
@@ -177,6 +183,7 @@ function normalizeConfig(config) {
177
183
  reverseAuthTtlSec: reverseAuthCandidate,
178
184
  enforceTokenSubjectNodeIdentity,
179
185
  ...(audience ? { audience } : {}),
186
+ ...(trustedClientScope ? { trustedClientScope } : {}),
180
187
  };
181
188
  if (tokenIssuerConfig) {
182
189
  normalized.tokenIssuerConfig = tokenIssuerConfig;
@@ -41,6 +41,10 @@ function normalizeOptions(raw) {
41
41
  (typeof snake.enforce_token_subject_node_identity === 'boolean'
42
42
  ? snake.enforce_token_subject_node_identity
43
43
  : undefined);
44
+ const trustedClientScope = camel.trustedClientScope ??
45
+ (typeof snake.trusted_client_scope === 'string'
46
+ ? snake.trusted_client_scope
47
+ : undefined);
44
48
  return {
45
49
  tokenVerifier,
46
50
  tokenIssuer,
@@ -51,6 +55,7 @@ function normalizeOptions(raw) {
51
55
  maxTtlSec,
52
56
  reverseAuthTtlSec,
53
57
  enforceTokenSubjectNodeIdentity,
58
+ trustedClientScope,
54
59
  };
55
60
  }
56
61
  class OAuth2Authorizer {
@@ -66,6 +71,7 @@ class OAuth2Authorizer {
66
71
  options.reverseAuthTtlSec ?? ttl_constants_js_1.DEFAULT_REVERSE_AUTH_TTL_SEC;
67
72
  this.enforceTokenSubjectNodeIdentity =
68
73
  options.enforceTokenSubjectNodeIdentity ?? false;
74
+ this.trustedClientScope = options.trustedClientScope ?? 'node.trusted';
69
75
  }
70
76
  get tokenVerifier() {
71
77
  return this.tokenVerifierImpl;
@@ -195,11 +201,20 @@ class OAuth2Authorizer {
195
201
  });
196
202
  return undefined;
197
203
  }
198
- // Enforce token subject node identity if enabled
204
+ // Enforce token subject node identity if enabled and not a trusted client
199
205
  if (this.enforceTokenSubjectNodeIdentity) {
200
- const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
201
- if (!validationResult) {
202
- return undefined;
206
+ const isTrustedClient = scopes.has(this.trustedClientScope);
207
+ if (isTrustedClient) {
208
+ logger.debug('oauth2_attach_trusted_client_bypass', {
209
+ system_id: frame.systemId,
210
+ trusted_scope: this.trustedClientScope,
211
+ });
212
+ }
213
+ else {
214
+ const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
215
+ if (!validationResult) {
216
+ return undefined;
217
+ }
203
218
  }
204
219
  }
205
220
  claims.instance_id = claims.instance_id ?? frame.instanceId;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /**
3
+ * Authorization policy definition types.
4
+ *
5
+ * This module defines the schema for authorization policies that can be
6
+ * loaded from YAML/JSON files and evaluated at runtime.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.VALID_EFFECTS = exports.VALID_ORIGIN_TYPES = exports.VALID_ACTIONS = exports.KNOWN_RULE_FIELDS = exports.KNOWN_POLICY_FIELDS = exports.MAX_SCOPE_NESTING_DEPTH = void 0;
10
+ /**
11
+ * Maximum nesting depth for scope requirements.
12
+ */
13
+ exports.MAX_SCOPE_NESTING_DEPTH = 5;
14
+ /**
15
+ * Known fields in AuthorizationPolicyDefinition.
16
+ */
17
+ exports.KNOWN_POLICY_FIELDS = new Set([
18
+ 'version',
19
+ 'default_effect',
20
+ 'rules',
21
+ ]);
22
+ /**
23
+ * Known fields in AuthorizationRuleDefinition.
24
+ * Fields not in this set trigger a warning.
25
+ */
26
+ exports.KNOWN_RULE_FIELDS = new Set([
27
+ 'id',
28
+ 'description',
29
+ 'effect',
30
+ 'action',
31
+ 'address',
32
+ 'frame_type',
33
+ 'origin_type',
34
+ 'scope',
35
+ 'when', // Reserved for advanced-security
36
+ ]);
37
+ /**
38
+ * Valid action values.
39
+ */
40
+ exports.VALID_ACTIONS = [
41
+ 'Connect',
42
+ 'ForwardUpstream',
43
+ 'ForwardDownstream',
44
+ 'ForwardPeer',
45
+ 'DeliverLocal',
46
+ '*',
47
+ ];
48
+ /**
49
+ * Valid origin type values (lowercase, matching DeliveryOriginType string values).
50
+ */
51
+ exports.VALID_ORIGIN_TYPES = [
52
+ 'downstream',
53
+ 'upstream',
54
+ 'peer',
55
+ 'local',
56
+ ];
57
+ /**
58
+ * Valid effect values.
59
+ */
60
+ exports.VALID_EFFECTS = ['allow', 'deny'];
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthorizationPolicyFactory = exports.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE = void 0;
4
+ const factory_1 = require("@naylence/factory");
5
+ /**
6
+ * Base type identifier for authorization policy factories.
7
+ */
8
+ exports.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE = 'AuthorizationPolicyFactory';
9
+ /**
10
+ * Abstract factory base class for creating authorization policies.
11
+ *
12
+ * Implementations of this factory create specific types of authorization
13
+ * policies (e.g., expression-based, rule-based, etc.).
14
+ */
15
+ class AuthorizationPolicyFactory extends factory_1.AbstractResourceFactory {
16
+ /**
17
+ * Static helper to create an authorization policy using the factory registry.
18
+ *
19
+ * @param config - Configuration for the policy
20
+ * @param options - Resource creation options
21
+ * @returns The created policy, or undefined if no factory matched
22
+ */
23
+ static async createAuthorizationPolicy(config, options = {}) {
24
+ if (config) {
25
+ const policy = await (0, factory_1.createResource)(exports.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE, config, options);
26
+ if (!policy) {
27
+ throw new Error('Failed to create authorization policy from configuration');
28
+ }
29
+ return policy;
30
+ }
31
+ const policy = await (0, factory_1.createDefaultResource)(exports.AUTHORIZATION_POLICY_FACTORY_BASE_TYPE, null, options);
32
+ return policy ?? undefined;
33
+ }
34
+ }
35
+ exports.AuthorizationPolicyFactory = AuthorizationPolicyFactory;