@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.
- package/dist/browser/index.cjs +3144 -1307
- package/dist/browser/index.mjs +3116 -1301
- package/dist/cjs/naylence/fame/factory-manifest.js +6 -0
- package/dist/cjs/naylence/fame/node/node-event-listener.js +4 -0
- package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer-factory.js +147 -0
- package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer.js +291 -0
- package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
- package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
- package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-definition.js +60 -0
- package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-factory.js +35 -0
- package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +35 -0
- package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source.js +2 -0
- package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy.js +2 -0
- package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +99 -0
- package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy.js +449 -0
- package/dist/cjs/naylence/fame/security/auth/policy/index.js +40 -0
- package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +101 -0
- package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +164 -0
- package/dist/cjs/naylence/fame/security/auth/policy/pattern-matcher.js +195 -0
- package/dist/cjs/naylence/fame/security/auth/policy/scope-matcher.js +169 -0
- package/dist/cjs/naylence/fame/security/auth/policy-authorizer.js +2 -0
- package/dist/cjs/naylence/fame/security/default-security-manager.js +94 -0
- package/dist/cjs/naylence/fame/security/index.js +3 -0
- package/dist/cjs/naylence/fame/security/node-security-profile-factory.js +3 -1
- package/dist/cjs/naylence/fame/sentinel/router.js +67 -1
- package/dist/cjs/naylence/fame/sentinel/sentinel.js +46 -2
- package/dist/cjs/naylence/fame/util/register-runtime-factories.js +2 -0
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/factory-manifest.js +6 -0
- package/dist/esm/naylence/fame/node/node-event-listener.js +4 -0
- package/dist/esm/naylence/fame/security/auth/default-policy-authorizer-factory.js +110 -0
- package/dist/esm/naylence/fame/security/auth/default-policy-authorizer.js +287 -0
- package/dist/esm/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
- package/dist/esm/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
- package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-definition.js +57 -0
- package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-factory.js +31 -0
- package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +31 -0
- package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source.js +1 -0
- package/dist/esm/naylence/fame/security/auth/policy/authorization-policy.js +1 -0
- package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +62 -0
- package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy.js +445 -0
- package/dist/esm/naylence/fame/security/auth/policy/index.js +20 -0
- package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +64 -0
- package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +127 -0
- package/dist/esm/naylence/fame/security/auth/policy/pattern-matcher.js +185 -0
- package/dist/esm/naylence/fame/security/auth/policy/scope-matcher.js +162 -0
- package/dist/esm/naylence/fame/security/auth/policy-authorizer.js +1 -0
- package/dist/esm/naylence/fame/security/default-security-manager.js +94 -0
- package/dist/esm/naylence/fame/security/index.js +3 -0
- package/dist/esm/naylence/fame/security/node-security-profile-factory.js +2 -0
- package/dist/esm/naylence/fame/sentinel/router.js +64 -0
- package/dist/esm/naylence/fame/sentinel/sentinel.js +47 -3
- package/dist/esm/naylence/fame/util/register-runtime-factories.js +2 -0
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +3140 -1303
- package/dist/node/index.mjs +3116 -1301
- package/dist/node/node.cjs +3191 -1338
- package/dist/node/node.mjs +3167 -1336
- package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
- package/dist/types/naylence/fame/node/node-event-listener.d.ts +31 -0
- package/dist/types/naylence/fame/security/auth/authorizer.d.ts +37 -0
- package/dist/types/naylence/fame/security/auth/default-policy-authorizer-factory.d.ts +55 -0
- package/dist/types/naylence/fame/security/auth/default-policy-authorizer.d.ts +99 -0
- package/dist/types/naylence/fame/security/auth/oauth2-authorizer-factory.d.ts +2 -0
- package/dist/types/naylence/fame/security/auth/oauth2-authorizer.d.ts +2 -0
- package/dist/types/naylence/fame/security/auth/policy/authorization-policy-definition.d.ts +166 -0
- package/dist/types/naylence/fame/security/auth/policy/authorization-policy-factory.d.ts +38 -0
- package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source-factory.d.ts +38 -0
- package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source.d.ts +20 -0
- package/dist/types/naylence/fame/security/auth/policy/authorization-policy.d.ts +55 -0
- package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy-factory.d.ts +42 -0
- package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy.d.ts +78 -0
- package/dist/types/naylence/fame/security/auth/policy/index.d.ts +19 -0
- package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.d.ts +51 -0
- package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source.d.ts +67 -0
- package/dist/types/naylence/fame/security/auth/policy/pattern-matcher.d.ts +84 -0
- package/dist/types/naylence/fame/security/auth/policy/scope-matcher.d.ts +61 -0
- package/dist/types/naylence/fame/security/auth/policy-authorizer.d.ts +12 -0
- package/dist/types/naylence/fame/security/default-security-manager.d.ts +22 -0
- package/dist/types/naylence/fame/security/index.d.ts +2 -0
- package/dist/types/naylence/fame/security/node-security-profile-factory.d.ts +1 -0
- package/dist/types/naylence/fame/sentinel/router.d.ts +68 -0
- package/dist/types/naylence/fame/sentinel/sentinel.d.ts +16 -0
- package/dist/types/version.d.ts +1 -1
- 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
|
|
201
|
-
if (
|
|
202
|
-
|
|
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;
|