@naylence/runtime 0.3.16 → 0.3.18
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 +65 -2
- package/dist/browser/index.mjs +65 -2
- package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer-factory.js +19 -0
- package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer.js +41 -0
- package/dist/cjs/naylence/fame/security/node-security-profile-factory.js +3 -1
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/security/auth/oauth2-authorizer-factory.js +19 -0
- package/dist/esm/naylence/fame/security/auth/oauth2-authorizer.js +42 -1
- package/dist/esm/naylence/fame/security/node-security-profile-factory.js +2 -0
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +65 -2
- package/dist/node/index.mjs +65 -2
- package/dist/node/node.cjs +65 -2
- package/dist/node/node.mjs +65 -2
- 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 +3 -0
- package/dist/types/naylence/fame/security/node-security-profile-factory.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/browser/index.cjs
CHANGED
|
@@ -515,12 +515,12 @@ async function ensureRuntimeFactoriesRegistered(registry = factory.Registry) {
|
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
// This file is auto-generated during build - do not edit manually
|
|
518
|
-
// Generated from package.json version: 0.3.
|
|
518
|
+
// Generated from package.json version: 0.3.18
|
|
519
519
|
/**
|
|
520
520
|
* The package version, injected at build time.
|
|
521
521
|
* @internal
|
|
522
522
|
*/
|
|
523
|
-
const VERSION = '0.3.
|
|
523
|
+
const VERSION = '0.3.18';
|
|
524
524
|
|
|
525
525
|
let initialized = false;
|
|
526
526
|
const runtimePlugin = {
|
|
@@ -28228,6 +28228,7 @@ const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
28228
28228
|
const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
28229
28229
|
const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
28230
28230
|
const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
28231
|
+
const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
28231
28232
|
const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
28232
28233
|
const PROFILE_NAME_OVERLAY = 'overlay';
|
|
28233
28234
|
const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -28463,6 +28464,7 @@ const GATED_PROFILE = {
|
|
|
28463
28464
|
max_ttl_sec: 86400,
|
|
28464
28465
|
algorithm: factory.Expressions.env(ENV_VAR_JWT_ALGORITHM, 'RS256'),
|
|
28465
28466
|
audience: factory.Expressions.env(ENV_VAR_JWT_AUDIENCE$1),
|
|
28467
|
+
enforce_token_subject_node_identity: factory.Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
28466
28468
|
},
|
|
28467
28469
|
};
|
|
28468
28470
|
const GATED_CALLBACK_PROFILE = {
|
|
@@ -28669,6 +28671,7 @@ function deepClone$3(value) {
|
|
|
28669
28671
|
var nodeSecurityProfileFactory = /*#__PURE__*/Object.freeze({
|
|
28670
28672
|
__proto__: null,
|
|
28671
28673
|
ENV_VAR_DEFAULT_ENCRYPTION_LEVEL: ENV_VAR_DEFAULT_ENCRYPTION_LEVEL,
|
|
28674
|
+
ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY: ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY,
|
|
28672
28675
|
ENV_VAR_HMAC_SECRET: ENV_VAR_HMAC_SECRET,
|
|
28673
28676
|
ENV_VAR_JWKS_URL: ENV_VAR_JWKS_URL,
|
|
28674
28677
|
ENV_VAR_JWT_ALGORITHM: ENV_VAR_JWT_ALGORITHM,
|
|
@@ -34710,6 +34713,7 @@ class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
34710
34713
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
34711
34714
|
maxTtlSec: normalized.maxTtlSec,
|
|
34712
34715
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
34716
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
34713
34717
|
};
|
|
34714
34718
|
if (tokenIssuer) {
|
|
34715
34719
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -34777,6 +34781,8 @@ function normalizeConfig$c(config) {
|
|
|
34777
34781
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
34778
34782
|
? source.reverse_auth_ttl_sec
|
|
34779
34783
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
34784
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
34785
|
+
source.enforce_token_subject_node_identity, false);
|
|
34780
34786
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
34781
34787
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
34782
34788
|
config: tokenVerifierConfigInput,
|
|
@@ -34795,6 +34801,7 @@ function normalizeConfig$c(config) {
|
|
|
34795
34801
|
maxTtlSec,
|
|
34796
34802
|
tokenVerifierConfig,
|
|
34797
34803
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
34804
|
+
enforceTokenSubjectNodeIdentity,
|
|
34798
34805
|
...(audience ? { audience } : {}),
|
|
34799
34806
|
};
|
|
34800
34807
|
if (tokenIssuerConfig) {
|
|
@@ -34815,6 +34822,21 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
34815
34822
|
};
|
|
34816
34823
|
return defaultConfig;
|
|
34817
34824
|
}
|
|
34825
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
34826
|
+
if (typeof value === 'boolean') {
|
|
34827
|
+
return value;
|
|
34828
|
+
}
|
|
34829
|
+
if (typeof value === 'string') {
|
|
34830
|
+
const lower = value.toLowerCase().trim();
|
|
34831
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
34832
|
+
return true;
|
|
34833
|
+
}
|
|
34834
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
34835
|
+
return false;
|
|
34836
|
+
}
|
|
34837
|
+
}
|
|
34838
|
+
return defaultValue;
|
|
34839
|
+
}
|
|
34818
34840
|
|
|
34819
34841
|
var oauth2AuthorizerFactory = /*#__PURE__*/Object.freeze({
|
|
34820
34842
|
__proto__: null,
|
|
@@ -39832,6 +39854,10 @@ function normalizeOptions$4(raw) {
|
|
|
39832
39854
|
: typeof snake.aud === 'string'
|
|
39833
39855
|
? snake.aud
|
|
39834
39856
|
: undefined);
|
|
39857
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
39858
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
39859
|
+
? snake.enforce_token_subject_node_identity
|
|
39860
|
+
: undefined);
|
|
39835
39861
|
return {
|
|
39836
39862
|
tokenVerifier,
|
|
39837
39863
|
tokenIssuer,
|
|
@@ -39841,6 +39867,7 @@ function normalizeOptions$4(raw) {
|
|
|
39841
39867
|
defaultTtlSec,
|
|
39842
39868
|
maxTtlSec,
|
|
39843
39869
|
reverseAuthTtlSec,
|
|
39870
|
+
enforceTokenSubjectNodeIdentity,
|
|
39844
39871
|
};
|
|
39845
39872
|
}
|
|
39846
39873
|
class OAuth2Authorizer {
|
|
@@ -39854,6 +39881,8 @@ class OAuth2Authorizer {
|
|
|
39854
39881
|
this.requireScope = options.requireScope ?? true;
|
|
39855
39882
|
this.reverseAuthTtlSec =
|
|
39856
39883
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
39884
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
39885
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
39857
39886
|
}
|
|
39858
39887
|
get tokenVerifier() {
|
|
39859
39888
|
return this.tokenVerifierImpl;
|
|
@@ -39983,6 +40012,13 @@ class OAuth2Authorizer {
|
|
|
39983
40012
|
});
|
|
39984
40013
|
return undefined;
|
|
39985
40014
|
}
|
|
40015
|
+
// Enforce token subject node identity if enabled
|
|
40016
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
40017
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
40018
|
+
if (!validationResult) {
|
|
40019
|
+
return undefined;
|
|
40020
|
+
}
|
|
40021
|
+
}
|
|
39986
40022
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
39987
40023
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
39988
40024
|
claims.accepted_capabilities =
|
|
@@ -40060,6 +40096,33 @@ class OAuth2Authorizer {
|
|
|
40060
40096
|
}
|
|
40061
40097
|
return false;
|
|
40062
40098
|
}
|
|
40099
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
40100
|
+
const sub = claims.sub;
|
|
40101
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
40102
|
+
logger$3.warning('oauth2_attach_missing_subject_claim', {
|
|
40103
|
+
system_id: systemId,
|
|
40104
|
+
});
|
|
40105
|
+
return false;
|
|
40106
|
+
}
|
|
40107
|
+
const expectedPrefix = await core.generateIdAsync({
|
|
40108
|
+
mode: 'fingerprint',
|
|
40109
|
+
material: sub,
|
|
40110
|
+
length: 8,
|
|
40111
|
+
});
|
|
40112
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
40113
|
+
logger$3.warning('oauth2_attach_node_identity_mismatch', {
|
|
40114
|
+
system_id: systemId,
|
|
40115
|
+
expected_prefix: expectedPrefix,
|
|
40116
|
+
subject: sub,
|
|
40117
|
+
});
|
|
40118
|
+
return false;
|
|
40119
|
+
}
|
|
40120
|
+
logger$3.debug('oauth2_attach_node_identity_verified', {
|
|
40121
|
+
system_id: systemId,
|
|
40122
|
+
expected_prefix: expectedPrefix,
|
|
40123
|
+
});
|
|
40124
|
+
return true;
|
|
40125
|
+
}
|
|
40063
40126
|
}
|
|
40064
40127
|
|
|
40065
40128
|
var oauth2Authorizer = /*#__PURE__*/Object.freeze({
|
package/dist/browser/index.mjs
CHANGED
|
@@ -513,12 +513,12 @@ async function ensureRuntimeFactoriesRegistered(registry = Registry) {
|
|
|
513
513
|
}
|
|
514
514
|
|
|
515
515
|
// This file is auto-generated during build - do not edit manually
|
|
516
|
-
// Generated from package.json version: 0.3.
|
|
516
|
+
// Generated from package.json version: 0.3.18
|
|
517
517
|
/**
|
|
518
518
|
* The package version, injected at build time.
|
|
519
519
|
* @internal
|
|
520
520
|
*/
|
|
521
|
-
const VERSION = '0.3.
|
|
521
|
+
const VERSION = '0.3.18';
|
|
522
522
|
|
|
523
523
|
let initialized = false;
|
|
524
524
|
const runtimePlugin = {
|
|
@@ -28226,6 +28226,7 @@ const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
28226
28226
|
const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
28227
28227
|
const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
28228
28228
|
const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
28229
|
+
const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
28229
28230
|
const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
28230
28231
|
const PROFILE_NAME_OVERLAY = 'overlay';
|
|
28231
28232
|
const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -28461,6 +28462,7 @@ const GATED_PROFILE = {
|
|
|
28461
28462
|
max_ttl_sec: 86400,
|
|
28462
28463
|
algorithm: Expressions.env(ENV_VAR_JWT_ALGORITHM, 'RS256'),
|
|
28463
28464
|
audience: Expressions.env(ENV_VAR_JWT_AUDIENCE$1),
|
|
28465
|
+
enforce_token_subject_node_identity: Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
28464
28466
|
},
|
|
28465
28467
|
};
|
|
28466
28468
|
const GATED_CALLBACK_PROFILE = {
|
|
@@ -28667,6 +28669,7 @@ function deepClone$3(value) {
|
|
|
28667
28669
|
var nodeSecurityProfileFactory = /*#__PURE__*/Object.freeze({
|
|
28668
28670
|
__proto__: null,
|
|
28669
28671
|
ENV_VAR_DEFAULT_ENCRYPTION_LEVEL: ENV_VAR_DEFAULT_ENCRYPTION_LEVEL,
|
|
28672
|
+
ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY: ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY,
|
|
28670
28673
|
ENV_VAR_HMAC_SECRET: ENV_VAR_HMAC_SECRET,
|
|
28671
28674
|
ENV_VAR_JWKS_URL: ENV_VAR_JWKS_URL,
|
|
28672
28675
|
ENV_VAR_JWT_ALGORITHM: ENV_VAR_JWT_ALGORITHM,
|
|
@@ -34708,6 +34711,7 @@ class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
34708
34711
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
34709
34712
|
maxTtlSec: normalized.maxTtlSec,
|
|
34710
34713
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
34714
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
34711
34715
|
};
|
|
34712
34716
|
if (tokenIssuer) {
|
|
34713
34717
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -34775,6 +34779,8 @@ function normalizeConfig$c(config) {
|
|
|
34775
34779
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
34776
34780
|
? source.reverse_auth_ttl_sec
|
|
34777
34781
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
34782
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
34783
|
+
source.enforce_token_subject_node_identity, false);
|
|
34778
34784
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
34779
34785
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
34780
34786
|
config: tokenVerifierConfigInput,
|
|
@@ -34793,6 +34799,7 @@ function normalizeConfig$c(config) {
|
|
|
34793
34799
|
maxTtlSec,
|
|
34794
34800
|
tokenVerifierConfig,
|
|
34795
34801
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
34802
|
+
enforceTokenSubjectNodeIdentity,
|
|
34796
34803
|
...(audience ? { audience } : {}),
|
|
34797
34804
|
};
|
|
34798
34805
|
if (tokenIssuerConfig) {
|
|
@@ -34813,6 +34820,21 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
34813
34820
|
};
|
|
34814
34821
|
return defaultConfig;
|
|
34815
34822
|
}
|
|
34823
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
34824
|
+
if (typeof value === 'boolean') {
|
|
34825
|
+
return value;
|
|
34826
|
+
}
|
|
34827
|
+
if (typeof value === 'string') {
|
|
34828
|
+
const lower = value.toLowerCase().trim();
|
|
34829
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
34830
|
+
return true;
|
|
34831
|
+
}
|
|
34832
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
34833
|
+
return false;
|
|
34834
|
+
}
|
|
34835
|
+
}
|
|
34836
|
+
return defaultValue;
|
|
34837
|
+
}
|
|
34816
34838
|
|
|
34817
34839
|
var oauth2AuthorizerFactory = /*#__PURE__*/Object.freeze({
|
|
34818
34840
|
__proto__: null,
|
|
@@ -39830,6 +39852,10 @@ function normalizeOptions$4(raw) {
|
|
|
39830
39852
|
: typeof snake.aud === 'string'
|
|
39831
39853
|
? snake.aud
|
|
39832
39854
|
: undefined);
|
|
39855
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
39856
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
39857
|
+
? snake.enforce_token_subject_node_identity
|
|
39858
|
+
: undefined);
|
|
39833
39859
|
return {
|
|
39834
39860
|
tokenVerifier,
|
|
39835
39861
|
tokenIssuer,
|
|
@@ -39839,6 +39865,7 @@ function normalizeOptions$4(raw) {
|
|
|
39839
39865
|
defaultTtlSec,
|
|
39840
39866
|
maxTtlSec,
|
|
39841
39867
|
reverseAuthTtlSec,
|
|
39868
|
+
enforceTokenSubjectNodeIdentity,
|
|
39842
39869
|
};
|
|
39843
39870
|
}
|
|
39844
39871
|
class OAuth2Authorizer {
|
|
@@ -39852,6 +39879,8 @@ class OAuth2Authorizer {
|
|
|
39852
39879
|
this.requireScope = options.requireScope ?? true;
|
|
39853
39880
|
this.reverseAuthTtlSec =
|
|
39854
39881
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
39882
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
39883
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
39855
39884
|
}
|
|
39856
39885
|
get tokenVerifier() {
|
|
39857
39886
|
return this.tokenVerifierImpl;
|
|
@@ -39981,6 +40010,13 @@ class OAuth2Authorizer {
|
|
|
39981
40010
|
});
|
|
39982
40011
|
return undefined;
|
|
39983
40012
|
}
|
|
40013
|
+
// Enforce token subject node identity if enabled
|
|
40014
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
40015
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
40016
|
+
if (!validationResult) {
|
|
40017
|
+
return undefined;
|
|
40018
|
+
}
|
|
40019
|
+
}
|
|
39984
40020
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
39985
40021
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
39986
40022
|
claims.accepted_capabilities =
|
|
@@ -40058,6 +40094,33 @@ class OAuth2Authorizer {
|
|
|
40058
40094
|
}
|
|
40059
40095
|
return false;
|
|
40060
40096
|
}
|
|
40097
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
40098
|
+
const sub = claims.sub;
|
|
40099
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
40100
|
+
logger$3.warning('oauth2_attach_missing_subject_claim', {
|
|
40101
|
+
system_id: systemId,
|
|
40102
|
+
});
|
|
40103
|
+
return false;
|
|
40104
|
+
}
|
|
40105
|
+
const expectedPrefix = await generateIdAsync({
|
|
40106
|
+
mode: 'fingerprint',
|
|
40107
|
+
material: sub,
|
|
40108
|
+
length: 8,
|
|
40109
|
+
});
|
|
40110
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
40111
|
+
logger$3.warning('oauth2_attach_node_identity_mismatch', {
|
|
40112
|
+
system_id: systemId,
|
|
40113
|
+
expected_prefix: expectedPrefix,
|
|
40114
|
+
subject: sub,
|
|
40115
|
+
});
|
|
40116
|
+
return false;
|
|
40117
|
+
}
|
|
40118
|
+
logger$3.debug('oauth2_attach_node_identity_verified', {
|
|
40119
|
+
system_id: systemId,
|
|
40120
|
+
expected_prefix: expectedPrefix,
|
|
40121
|
+
});
|
|
40122
|
+
return true;
|
|
40123
|
+
}
|
|
40061
40124
|
}
|
|
40062
40125
|
|
|
40063
40126
|
var oauth2Authorizer = /*#__PURE__*/Object.freeze({
|
|
@@ -86,6 +86,7 @@ class OAuth2AuthorizerFactory extends authorizer_factory_js_1.AuthorizerFactory
|
|
|
86
86
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
87
87
|
maxTtlSec: normalized.maxTtlSec,
|
|
88
88
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
89
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
89
90
|
};
|
|
90
91
|
if (tokenIssuer) {
|
|
91
92
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -154,6 +155,8 @@ function normalizeConfig(config) {
|
|
|
154
155
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
155
156
|
? source.reverse_auth_ttl_sec
|
|
156
157
|
: ttl_constants_js_1.DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
158
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
159
|
+
source.enforce_token_subject_node_identity, false);
|
|
157
160
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
158
161
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
159
162
|
config: tokenVerifierConfigInput,
|
|
@@ -172,6 +175,7 @@ function normalizeConfig(config) {
|
|
|
172
175
|
maxTtlSec,
|
|
173
176
|
tokenVerifierConfig,
|
|
174
177
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
178
|
+
enforceTokenSubjectNodeIdentity,
|
|
175
179
|
...(audience ? { audience } : {}),
|
|
176
180
|
};
|
|
177
181
|
if (tokenIssuerConfig) {
|
|
@@ -192,4 +196,19 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
192
196
|
};
|
|
193
197
|
return defaultConfig;
|
|
194
198
|
}
|
|
199
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
200
|
+
if (typeof value === 'boolean') {
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
if (typeof value === 'string') {
|
|
204
|
+
const lower = value.toLowerCase().trim();
|
|
205
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return defaultValue;
|
|
213
|
+
}
|
|
195
214
|
exports.default = OAuth2AuthorizerFactory;
|
|
@@ -37,6 +37,10 @@ function normalizeOptions(raw) {
|
|
|
37
37
|
: typeof snake.aud === 'string'
|
|
38
38
|
? snake.aud
|
|
39
39
|
: undefined);
|
|
40
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
41
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
42
|
+
? snake.enforce_token_subject_node_identity
|
|
43
|
+
: undefined);
|
|
40
44
|
return {
|
|
41
45
|
tokenVerifier,
|
|
42
46
|
tokenIssuer,
|
|
@@ -46,6 +50,7 @@ function normalizeOptions(raw) {
|
|
|
46
50
|
defaultTtlSec,
|
|
47
51
|
maxTtlSec,
|
|
48
52
|
reverseAuthTtlSec,
|
|
53
|
+
enforceTokenSubjectNodeIdentity,
|
|
49
54
|
};
|
|
50
55
|
}
|
|
51
56
|
class OAuth2Authorizer {
|
|
@@ -59,6 +64,8 @@ class OAuth2Authorizer {
|
|
|
59
64
|
this.requireScope = options.requireScope ?? true;
|
|
60
65
|
this.reverseAuthTtlSec =
|
|
61
66
|
options.reverseAuthTtlSec ?? ttl_constants_js_1.DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
67
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
68
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
62
69
|
}
|
|
63
70
|
get tokenVerifier() {
|
|
64
71
|
return this.tokenVerifierImpl;
|
|
@@ -188,6 +195,13 @@ class OAuth2Authorizer {
|
|
|
188
195
|
});
|
|
189
196
|
return undefined;
|
|
190
197
|
}
|
|
198
|
+
// Enforce token subject node identity if enabled
|
|
199
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
200
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
201
|
+
if (!validationResult) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
191
205
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
192
206
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
193
207
|
claims.accepted_capabilities =
|
|
@@ -265,5 +279,32 @@ class OAuth2Authorizer {
|
|
|
265
279
|
}
|
|
266
280
|
return false;
|
|
267
281
|
}
|
|
282
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
283
|
+
const sub = claims.sub;
|
|
284
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
285
|
+
logger.warning('oauth2_attach_missing_subject_claim', {
|
|
286
|
+
system_id: systemId,
|
|
287
|
+
});
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
const expectedPrefix = await (0, core_1.generateIdAsync)({
|
|
291
|
+
mode: 'fingerprint',
|
|
292
|
+
material: sub,
|
|
293
|
+
length: 8,
|
|
294
|
+
});
|
|
295
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
296
|
+
logger.warning('oauth2_attach_node_identity_mismatch', {
|
|
297
|
+
system_id: systemId,
|
|
298
|
+
expected_prefix: expectedPrefix,
|
|
299
|
+
subject: sub,
|
|
300
|
+
});
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
logger.debug('oauth2_attach_node_identity_verified', {
|
|
304
|
+
system_id: systemId,
|
|
305
|
+
expected_prefix: expectedPrefix,
|
|
306
|
+
});
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
268
309
|
}
|
|
269
310
|
exports.OAuth2Authorizer = OAuth2Authorizer;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NodeSecurityProfileFactory = exports.FACTORY_META = exports.PROFILE_NAME_OPEN = exports.PROFILE_NAME_GATED_CALLBACK = exports.PROFILE_NAME_GATED = exports.PROFILE_NAME_OVERLAY_CALLBACK = exports.PROFILE_NAME_OVERLAY = exports.PROFILE_NAME_STRICT_OVERLAY = exports.ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = exports.ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = exports.ENV_VAR_HMAC_SECRET = exports.ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = exports.ENV_VAR_JWKS_URL = exports.ENV_VAR_JWT_AUDIENCE = exports.ENV_VAR_JWT_ALGORITHM = exports.ENV_VAR_JWT_TRUSTED_ISSUER = void 0;
|
|
3
|
+
exports.NodeSecurityProfileFactory = exports.FACTORY_META = exports.PROFILE_NAME_OPEN = exports.PROFILE_NAME_GATED_CALLBACK = exports.PROFILE_NAME_GATED = exports.PROFILE_NAME_OVERLAY_CALLBACK = exports.PROFILE_NAME_OVERLAY = exports.PROFILE_NAME_STRICT_OVERLAY = exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = exports.ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = exports.ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = exports.ENV_VAR_HMAC_SECRET = exports.ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = exports.ENV_VAR_JWKS_URL = exports.ENV_VAR_JWT_AUDIENCE = exports.ENV_VAR_JWT_ALGORITHM = exports.ENV_VAR_JWT_TRUSTED_ISSUER = void 0;
|
|
4
4
|
const factory_1 = require("@naylence/factory");
|
|
5
5
|
const security_manager_factory_js_1 = require("./security-manager-factory.js");
|
|
6
6
|
const logging_js_1 = require("../util/logging.js");
|
|
@@ -13,6 +13,7 @@ exports.ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
13
13
|
exports.ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
14
14
|
exports.ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
15
15
|
exports.ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
16
|
+
exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
16
17
|
exports.PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
17
18
|
exports.PROFILE_NAME_OVERLAY = 'overlay';
|
|
18
19
|
exports.PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -248,6 +249,7 @@ const GATED_PROFILE = {
|
|
|
248
249
|
max_ttl_sec: 86400,
|
|
249
250
|
algorithm: factory_1.Expressions.env(exports.ENV_VAR_JWT_ALGORITHM, 'RS256'),
|
|
250
251
|
audience: factory_1.Expressions.env(exports.ENV_VAR_JWT_AUDIENCE),
|
|
252
|
+
enforce_token_subject_node_identity: factory_1.Expressions.env(exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
251
253
|
},
|
|
252
254
|
};
|
|
253
255
|
const GATED_CALLBACK_PROFILE = {
|
package/dist/cjs/version.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// This file is auto-generated during build - do not edit manually
|
|
3
|
-
// Generated from package.json version: 0.3.
|
|
3
|
+
// Generated from package.json version: 0.3.18
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.VERSION = void 0;
|
|
6
6
|
/**
|
|
7
7
|
* The package version, injected at build time.
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
|
-
exports.VERSION = '0.3.
|
|
10
|
+
exports.VERSION = '0.3.18';
|
|
@@ -50,6 +50,7 @@ export class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
50
50
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
51
51
|
maxTtlSec: normalized.maxTtlSec,
|
|
52
52
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
53
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
53
54
|
};
|
|
54
55
|
if (tokenIssuer) {
|
|
55
56
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -117,6 +118,8 @@ function normalizeConfig(config) {
|
|
|
117
118
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
118
119
|
? source.reverse_auth_ttl_sec
|
|
119
120
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
121
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
122
|
+
source.enforce_token_subject_node_identity, false);
|
|
120
123
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
121
124
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
122
125
|
config: tokenVerifierConfigInput,
|
|
@@ -135,6 +138,7 @@ function normalizeConfig(config) {
|
|
|
135
138
|
maxTtlSec,
|
|
136
139
|
tokenVerifierConfig,
|
|
137
140
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
141
|
+
enforceTokenSubjectNodeIdentity,
|
|
138
142
|
...(audience ? { audience } : {}),
|
|
139
143
|
};
|
|
140
144
|
if (tokenIssuerConfig) {
|
|
@@ -155,4 +159,19 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
155
159
|
};
|
|
156
160
|
return defaultConfig;
|
|
157
161
|
}
|
|
162
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
163
|
+
if (typeof value === 'boolean') {
|
|
164
|
+
return value;
|
|
165
|
+
}
|
|
166
|
+
if (typeof value === 'string') {
|
|
167
|
+
const lower = value.toLowerCase().trim();
|
|
168
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return defaultValue;
|
|
176
|
+
}
|
|
158
177
|
export default OAuth2AuthorizerFactory;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAuthorizationContext } from '@naylence/core';
|
|
1
|
+
import { createAuthorizationContext, generateIdAsync } from '@naylence/core';
|
|
2
2
|
import { DEFAULT_REVERSE_AUTH_TTL_SEC } from '../../constants/ttl-constants.js';
|
|
3
3
|
import { getLogger } from '../../util/logging.js';
|
|
4
4
|
const logger = getLogger('naylence.fame.security.auth.oauth2_authorizer');
|
|
@@ -34,6 +34,10 @@ function normalizeOptions(raw) {
|
|
|
34
34
|
: typeof snake.aud === 'string'
|
|
35
35
|
? snake.aud
|
|
36
36
|
: undefined);
|
|
37
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
38
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
39
|
+
? snake.enforce_token_subject_node_identity
|
|
40
|
+
: undefined);
|
|
37
41
|
return {
|
|
38
42
|
tokenVerifier,
|
|
39
43
|
tokenIssuer,
|
|
@@ -43,6 +47,7 @@ function normalizeOptions(raw) {
|
|
|
43
47
|
defaultTtlSec,
|
|
44
48
|
maxTtlSec,
|
|
45
49
|
reverseAuthTtlSec,
|
|
50
|
+
enforceTokenSubjectNodeIdentity,
|
|
46
51
|
};
|
|
47
52
|
}
|
|
48
53
|
export class OAuth2Authorizer {
|
|
@@ -56,6 +61,8 @@ export class OAuth2Authorizer {
|
|
|
56
61
|
this.requireScope = options.requireScope ?? true;
|
|
57
62
|
this.reverseAuthTtlSec =
|
|
58
63
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
64
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
65
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
59
66
|
}
|
|
60
67
|
get tokenVerifier() {
|
|
61
68
|
return this.tokenVerifierImpl;
|
|
@@ -185,6 +192,13 @@ export class OAuth2Authorizer {
|
|
|
185
192
|
});
|
|
186
193
|
return undefined;
|
|
187
194
|
}
|
|
195
|
+
// Enforce token subject node identity if enabled
|
|
196
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
197
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
198
|
+
if (!validationResult) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
188
202
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
189
203
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
190
204
|
claims.accepted_capabilities =
|
|
@@ -262,4 +276,31 @@ export class OAuth2Authorizer {
|
|
|
262
276
|
}
|
|
263
277
|
return false;
|
|
264
278
|
}
|
|
279
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
280
|
+
const sub = claims.sub;
|
|
281
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
282
|
+
logger.warning('oauth2_attach_missing_subject_claim', {
|
|
283
|
+
system_id: systemId,
|
|
284
|
+
});
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
const expectedPrefix = await generateIdAsync({
|
|
288
|
+
mode: 'fingerprint',
|
|
289
|
+
material: sub,
|
|
290
|
+
length: 8,
|
|
291
|
+
});
|
|
292
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
293
|
+
logger.warning('oauth2_attach_node_identity_mismatch', {
|
|
294
|
+
system_id: systemId,
|
|
295
|
+
expected_prefix: expectedPrefix,
|
|
296
|
+
subject: sub,
|
|
297
|
+
});
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
logger.debug('oauth2_attach_node_identity_verified', {
|
|
301
|
+
system_id: systemId,
|
|
302
|
+
expected_prefix: expectedPrefix,
|
|
303
|
+
});
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
265
306
|
}
|
|
@@ -10,6 +10,7 @@ export const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
10
10
|
export const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
11
11
|
export const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
12
12
|
export const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
13
|
+
export const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
13
14
|
export const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
14
15
|
export const PROFILE_NAME_OVERLAY = 'overlay';
|
|
15
16
|
export const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -245,6 +246,7 @@ const GATED_PROFILE = {
|
|
|
245
246
|
max_ttl_sec: 86400,
|
|
246
247
|
algorithm: Expressions.env(ENV_VAR_JWT_ALGORITHM, 'RS256'),
|
|
247
248
|
audience: Expressions.env(ENV_VAR_JWT_AUDIENCE),
|
|
249
|
+
enforce_token_subject_node_identity: Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
248
250
|
},
|
|
249
251
|
};
|
|
250
252
|
const GATED_CALLBACK_PROFILE = {
|
package/dist/esm/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This file is auto-generated during build - do not edit manually
|
|
2
|
-
// Generated from package.json version: 0.3.
|
|
2
|
+
// Generated from package.json version: 0.3.18
|
|
3
3
|
/**
|
|
4
4
|
* The package version, injected at build time.
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
|
-
export const VERSION = '0.3.
|
|
7
|
+
export const VERSION = '0.3.18';
|
package/dist/node/index.cjs
CHANGED
|
@@ -14,12 +14,12 @@ var fastify = require('fastify');
|
|
|
14
14
|
var websocketPlugin = require('@fastify/websocket');
|
|
15
15
|
|
|
16
16
|
// This file is auto-generated during build - do not edit manually
|
|
17
|
-
// Generated from package.json version: 0.3.
|
|
17
|
+
// Generated from package.json version: 0.3.18
|
|
18
18
|
/**
|
|
19
19
|
* The package version, injected at build time.
|
|
20
20
|
* @internal
|
|
21
21
|
*/
|
|
22
|
-
const VERSION = '0.3.
|
|
22
|
+
const VERSION = '0.3.18';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -28115,6 +28115,7 @@ const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
28115
28115
|
const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
28116
28116
|
const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
28117
28117
|
const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
28118
|
+
const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
28118
28119
|
const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
28119
28120
|
const PROFILE_NAME_OVERLAY = 'overlay';
|
|
28120
28121
|
const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -28350,6 +28351,7 @@ const GATED_PROFILE = {
|
|
|
28350
28351
|
max_ttl_sec: 86400,
|
|
28351
28352
|
algorithm: factory.Expressions.env(ENV_VAR_JWT_ALGORITHM, 'RS256'),
|
|
28352
28353
|
audience: factory.Expressions.env(ENV_VAR_JWT_AUDIENCE$1),
|
|
28354
|
+
enforce_token_subject_node_identity: factory.Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
28353
28355
|
},
|
|
28354
28356
|
};
|
|
28355
28357
|
const GATED_CALLBACK_PROFILE = {
|
|
@@ -28556,6 +28558,7 @@ function deepClone$3(value) {
|
|
|
28556
28558
|
var nodeSecurityProfileFactory = /*#__PURE__*/Object.freeze({
|
|
28557
28559
|
__proto__: null,
|
|
28558
28560
|
ENV_VAR_DEFAULT_ENCRYPTION_LEVEL: ENV_VAR_DEFAULT_ENCRYPTION_LEVEL,
|
|
28561
|
+
ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY: ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY,
|
|
28559
28562
|
ENV_VAR_HMAC_SECRET: ENV_VAR_HMAC_SECRET,
|
|
28560
28563
|
ENV_VAR_JWKS_URL: ENV_VAR_JWKS_URL,
|
|
28561
28564
|
ENV_VAR_JWT_ALGORITHM: ENV_VAR_JWT_ALGORITHM,
|
|
@@ -33260,6 +33263,7 @@ class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
33260
33263
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
33261
33264
|
maxTtlSec: normalized.maxTtlSec,
|
|
33262
33265
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
33266
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
33263
33267
|
};
|
|
33264
33268
|
if (tokenIssuer) {
|
|
33265
33269
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -33327,6 +33331,8 @@ function normalizeConfig$c(config) {
|
|
|
33327
33331
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
33328
33332
|
? source.reverse_auth_ttl_sec
|
|
33329
33333
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
33334
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
33335
|
+
source.enforce_token_subject_node_identity, false);
|
|
33330
33336
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
33331
33337
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
33332
33338
|
config: tokenVerifierConfigInput,
|
|
@@ -33345,6 +33351,7 @@ function normalizeConfig$c(config) {
|
|
|
33345
33351
|
maxTtlSec,
|
|
33346
33352
|
tokenVerifierConfig,
|
|
33347
33353
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
33354
|
+
enforceTokenSubjectNodeIdentity,
|
|
33348
33355
|
...(audience ? { audience } : {}),
|
|
33349
33356
|
};
|
|
33350
33357
|
if (tokenIssuerConfig) {
|
|
@@ -33365,6 +33372,21 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
33365
33372
|
};
|
|
33366
33373
|
return defaultConfig;
|
|
33367
33374
|
}
|
|
33375
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
33376
|
+
if (typeof value === 'boolean') {
|
|
33377
|
+
return value;
|
|
33378
|
+
}
|
|
33379
|
+
if (typeof value === 'string') {
|
|
33380
|
+
const lower = value.toLowerCase().trim();
|
|
33381
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
33382
|
+
return true;
|
|
33383
|
+
}
|
|
33384
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
33385
|
+
return false;
|
|
33386
|
+
}
|
|
33387
|
+
}
|
|
33388
|
+
return defaultValue;
|
|
33389
|
+
}
|
|
33368
33390
|
|
|
33369
33391
|
var oauth2AuthorizerFactory = /*#__PURE__*/Object.freeze({
|
|
33370
33392
|
__proto__: null,
|
|
@@ -39634,6 +39656,10 @@ function normalizeOptions$4(raw) {
|
|
|
39634
39656
|
: typeof snake.aud === 'string'
|
|
39635
39657
|
? snake.aud
|
|
39636
39658
|
: undefined);
|
|
39659
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
39660
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
39661
|
+
? snake.enforce_token_subject_node_identity
|
|
39662
|
+
: undefined);
|
|
39637
39663
|
return {
|
|
39638
39664
|
tokenVerifier,
|
|
39639
39665
|
tokenIssuer,
|
|
@@ -39643,6 +39669,7 @@ function normalizeOptions$4(raw) {
|
|
|
39643
39669
|
defaultTtlSec,
|
|
39644
39670
|
maxTtlSec,
|
|
39645
39671
|
reverseAuthTtlSec,
|
|
39672
|
+
enforceTokenSubjectNodeIdentity,
|
|
39646
39673
|
};
|
|
39647
39674
|
}
|
|
39648
39675
|
class OAuth2Authorizer {
|
|
@@ -39656,6 +39683,8 @@ class OAuth2Authorizer {
|
|
|
39656
39683
|
this.requireScope = options.requireScope ?? true;
|
|
39657
39684
|
this.reverseAuthTtlSec =
|
|
39658
39685
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
39686
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
39687
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
39659
39688
|
}
|
|
39660
39689
|
get tokenVerifier() {
|
|
39661
39690
|
return this.tokenVerifierImpl;
|
|
@@ -39785,6 +39814,13 @@ class OAuth2Authorizer {
|
|
|
39785
39814
|
});
|
|
39786
39815
|
return undefined;
|
|
39787
39816
|
}
|
|
39817
|
+
// Enforce token subject node identity if enabled
|
|
39818
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
39819
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
39820
|
+
if (!validationResult) {
|
|
39821
|
+
return undefined;
|
|
39822
|
+
}
|
|
39823
|
+
}
|
|
39788
39824
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
39789
39825
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
39790
39826
|
claims.accepted_capabilities =
|
|
@@ -39862,6 +39898,33 @@ class OAuth2Authorizer {
|
|
|
39862
39898
|
}
|
|
39863
39899
|
return false;
|
|
39864
39900
|
}
|
|
39901
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
39902
|
+
const sub = claims.sub;
|
|
39903
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
39904
|
+
logger$3.warning('oauth2_attach_missing_subject_claim', {
|
|
39905
|
+
system_id: systemId,
|
|
39906
|
+
});
|
|
39907
|
+
return false;
|
|
39908
|
+
}
|
|
39909
|
+
const expectedPrefix = await core.generateIdAsync({
|
|
39910
|
+
mode: 'fingerprint',
|
|
39911
|
+
material: sub,
|
|
39912
|
+
length: 8,
|
|
39913
|
+
});
|
|
39914
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
39915
|
+
logger$3.warning('oauth2_attach_node_identity_mismatch', {
|
|
39916
|
+
system_id: systemId,
|
|
39917
|
+
expected_prefix: expectedPrefix,
|
|
39918
|
+
subject: sub,
|
|
39919
|
+
});
|
|
39920
|
+
return false;
|
|
39921
|
+
}
|
|
39922
|
+
logger$3.debug('oauth2_attach_node_identity_verified', {
|
|
39923
|
+
system_id: systemId,
|
|
39924
|
+
expected_prefix: expectedPrefix,
|
|
39925
|
+
});
|
|
39926
|
+
return true;
|
|
39927
|
+
}
|
|
39865
39928
|
}
|
|
39866
39929
|
|
|
39867
39930
|
var oauth2Authorizer = /*#__PURE__*/Object.freeze({
|
package/dist/node/index.mjs
CHANGED
|
@@ -13,12 +13,12 @@ import fastify from 'fastify';
|
|
|
13
13
|
import websocketPlugin from '@fastify/websocket';
|
|
14
14
|
|
|
15
15
|
// This file is auto-generated during build - do not edit manually
|
|
16
|
-
// Generated from package.json version: 0.3.
|
|
16
|
+
// Generated from package.json version: 0.3.18
|
|
17
17
|
/**
|
|
18
18
|
* The package version, injected at build time.
|
|
19
19
|
* @internal
|
|
20
20
|
*/
|
|
21
|
-
const VERSION = '0.3.
|
|
21
|
+
const VERSION = '0.3.18';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -28114,6 +28114,7 @@ const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
28114
28114
|
const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
28115
28115
|
const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
28116
28116
|
const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
28117
|
+
const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
28117
28118
|
const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
28118
28119
|
const PROFILE_NAME_OVERLAY = 'overlay';
|
|
28119
28120
|
const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -28349,6 +28350,7 @@ const GATED_PROFILE = {
|
|
|
28349
28350
|
max_ttl_sec: 86400,
|
|
28350
28351
|
algorithm: Expressions.env(ENV_VAR_JWT_ALGORITHM, 'RS256'),
|
|
28351
28352
|
audience: Expressions.env(ENV_VAR_JWT_AUDIENCE$1),
|
|
28353
|
+
enforce_token_subject_node_identity: Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
28352
28354
|
},
|
|
28353
28355
|
};
|
|
28354
28356
|
const GATED_CALLBACK_PROFILE = {
|
|
@@ -28555,6 +28557,7 @@ function deepClone$3(value) {
|
|
|
28555
28557
|
var nodeSecurityProfileFactory = /*#__PURE__*/Object.freeze({
|
|
28556
28558
|
__proto__: null,
|
|
28557
28559
|
ENV_VAR_DEFAULT_ENCRYPTION_LEVEL: ENV_VAR_DEFAULT_ENCRYPTION_LEVEL,
|
|
28560
|
+
ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY: ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY,
|
|
28558
28561
|
ENV_VAR_HMAC_SECRET: ENV_VAR_HMAC_SECRET,
|
|
28559
28562
|
ENV_VAR_JWKS_URL: ENV_VAR_JWKS_URL,
|
|
28560
28563
|
ENV_VAR_JWT_ALGORITHM: ENV_VAR_JWT_ALGORITHM,
|
|
@@ -33259,6 +33262,7 @@ class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
33259
33262
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
33260
33263
|
maxTtlSec: normalized.maxTtlSec,
|
|
33261
33264
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
33265
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
33262
33266
|
};
|
|
33263
33267
|
if (tokenIssuer) {
|
|
33264
33268
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -33326,6 +33330,8 @@ function normalizeConfig$c(config) {
|
|
|
33326
33330
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
33327
33331
|
? source.reverse_auth_ttl_sec
|
|
33328
33332
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
33333
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
33334
|
+
source.enforce_token_subject_node_identity, false);
|
|
33329
33335
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
33330
33336
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
33331
33337
|
config: tokenVerifierConfigInput,
|
|
@@ -33344,6 +33350,7 @@ function normalizeConfig$c(config) {
|
|
|
33344
33350
|
maxTtlSec,
|
|
33345
33351
|
tokenVerifierConfig,
|
|
33346
33352
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
33353
|
+
enforceTokenSubjectNodeIdentity,
|
|
33347
33354
|
...(audience ? { audience } : {}),
|
|
33348
33355
|
};
|
|
33349
33356
|
if (tokenIssuerConfig) {
|
|
@@ -33364,6 +33371,21 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
33364
33371
|
};
|
|
33365
33372
|
return defaultConfig;
|
|
33366
33373
|
}
|
|
33374
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
33375
|
+
if (typeof value === 'boolean') {
|
|
33376
|
+
return value;
|
|
33377
|
+
}
|
|
33378
|
+
if (typeof value === 'string') {
|
|
33379
|
+
const lower = value.toLowerCase().trim();
|
|
33380
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
33381
|
+
return true;
|
|
33382
|
+
}
|
|
33383
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
33384
|
+
return false;
|
|
33385
|
+
}
|
|
33386
|
+
}
|
|
33387
|
+
return defaultValue;
|
|
33388
|
+
}
|
|
33367
33389
|
|
|
33368
33390
|
var oauth2AuthorizerFactory = /*#__PURE__*/Object.freeze({
|
|
33369
33391
|
__proto__: null,
|
|
@@ -39633,6 +39655,10 @@ function normalizeOptions$4(raw) {
|
|
|
39633
39655
|
: typeof snake.aud === 'string'
|
|
39634
39656
|
? snake.aud
|
|
39635
39657
|
: undefined);
|
|
39658
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
39659
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
39660
|
+
? snake.enforce_token_subject_node_identity
|
|
39661
|
+
: undefined);
|
|
39636
39662
|
return {
|
|
39637
39663
|
tokenVerifier,
|
|
39638
39664
|
tokenIssuer,
|
|
@@ -39642,6 +39668,7 @@ function normalizeOptions$4(raw) {
|
|
|
39642
39668
|
defaultTtlSec,
|
|
39643
39669
|
maxTtlSec,
|
|
39644
39670
|
reverseAuthTtlSec,
|
|
39671
|
+
enforceTokenSubjectNodeIdentity,
|
|
39645
39672
|
};
|
|
39646
39673
|
}
|
|
39647
39674
|
class OAuth2Authorizer {
|
|
@@ -39655,6 +39682,8 @@ class OAuth2Authorizer {
|
|
|
39655
39682
|
this.requireScope = options.requireScope ?? true;
|
|
39656
39683
|
this.reverseAuthTtlSec =
|
|
39657
39684
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
39685
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
39686
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
39658
39687
|
}
|
|
39659
39688
|
get tokenVerifier() {
|
|
39660
39689
|
return this.tokenVerifierImpl;
|
|
@@ -39784,6 +39813,13 @@ class OAuth2Authorizer {
|
|
|
39784
39813
|
});
|
|
39785
39814
|
return undefined;
|
|
39786
39815
|
}
|
|
39816
|
+
// Enforce token subject node identity if enabled
|
|
39817
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
39818
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
39819
|
+
if (!validationResult) {
|
|
39820
|
+
return undefined;
|
|
39821
|
+
}
|
|
39822
|
+
}
|
|
39787
39823
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
39788
39824
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
39789
39825
|
claims.accepted_capabilities =
|
|
@@ -39861,6 +39897,33 @@ class OAuth2Authorizer {
|
|
|
39861
39897
|
}
|
|
39862
39898
|
return false;
|
|
39863
39899
|
}
|
|
39900
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
39901
|
+
const sub = claims.sub;
|
|
39902
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
39903
|
+
logger$3.warning('oauth2_attach_missing_subject_claim', {
|
|
39904
|
+
system_id: systemId,
|
|
39905
|
+
});
|
|
39906
|
+
return false;
|
|
39907
|
+
}
|
|
39908
|
+
const expectedPrefix = await generateIdAsync({
|
|
39909
|
+
mode: 'fingerprint',
|
|
39910
|
+
material: sub,
|
|
39911
|
+
length: 8,
|
|
39912
|
+
});
|
|
39913
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
39914
|
+
logger$3.warning('oauth2_attach_node_identity_mismatch', {
|
|
39915
|
+
system_id: systemId,
|
|
39916
|
+
expected_prefix: expectedPrefix,
|
|
39917
|
+
subject: sub,
|
|
39918
|
+
});
|
|
39919
|
+
return false;
|
|
39920
|
+
}
|
|
39921
|
+
logger$3.debug('oauth2_attach_node_identity_verified', {
|
|
39922
|
+
system_id: systemId,
|
|
39923
|
+
expected_prefix: expectedPrefix,
|
|
39924
|
+
});
|
|
39925
|
+
return true;
|
|
39926
|
+
}
|
|
39864
39927
|
}
|
|
39865
39928
|
|
|
39866
39929
|
var oauth2Authorizer = /*#__PURE__*/Object.freeze({
|
package/dist/node/node.cjs
CHANGED
|
@@ -4426,12 +4426,12 @@ async function ensureRuntimeFactoriesRegistered(registry = factory.Registry) {
|
|
|
4426
4426
|
}
|
|
4427
4427
|
|
|
4428
4428
|
// This file is auto-generated during build - do not edit manually
|
|
4429
|
-
// Generated from package.json version: 0.3.
|
|
4429
|
+
// Generated from package.json version: 0.3.18
|
|
4430
4430
|
/**
|
|
4431
4431
|
* The package version, injected at build time.
|
|
4432
4432
|
* @internal
|
|
4433
4433
|
*/
|
|
4434
|
-
const VERSION = '0.3.
|
|
4434
|
+
const VERSION = '0.3.18';
|
|
4435
4435
|
|
|
4436
4436
|
let initialized = false;
|
|
4437
4437
|
const runtimePlugin = {
|
|
@@ -29319,6 +29319,7 @@ const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
29319
29319
|
const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
29320
29320
|
const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
29321
29321
|
const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
29322
|
+
const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
29322
29323
|
const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
29323
29324
|
const PROFILE_NAME_OVERLAY = 'overlay';
|
|
29324
29325
|
const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -29554,6 +29555,7 @@ const GATED_PROFILE = {
|
|
|
29554
29555
|
max_ttl_sec: 86400,
|
|
29555
29556
|
algorithm: factory.Expressions.env(ENV_VAR_JWT_ALGORITHM$2, 'RS256'),
|
|
29556
29557
|
audience: factory.Expressions.env(ENV_VAR_JWT_AUDIENCE$2),
|
|
29558
|
+
enforce_token_subject_node_identity: factory.Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
29557
29559
|
},
|
|
29558
29560
|
};
|
|
29559
29561
|
const GATED_CALLBACK_PROFILE = {
|
|
@@ -29760,6 +29762,7 @@ function deepClone$3(value) {
|
|
|
29760
29762
|
var nodeSecurityProfileFactory = /*#__PURE__*/Object.freeze({
|
|
29761
29763
|
__proto__: null,
|
|
29762
29764
|
ENV_VAR_DEFAULT_ENCRYPTION_LEVEL: ENV_VAR_DEFAULT_ENCRYPTION_LEVEL,
|
|
29765
|
+
ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY: ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY,
|
|
29763
29766
|
ENV_VAR_HMAC_SECRET: ENV_VAR_HMAC_SECRET,
|
|
29764
29767
|
ENV_VAR_JWKS_URL: ENV_VAR_JWKS_URL,
|
|
29765
29768
|
ENV_VAR_JWT_ALGORITHM: ENV_VAR_JWT_ALGORITHM$2,
|
|
@@ -38001,6 +38004,7 @@ class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
38001
38004
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
38002
38005
|
maxTtlSec: normalized.maxTtlSec,
|
|
38003
38006
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
38007
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
38004
38008
|
};
|
|
38005
38009
|
if (tokenIssuer) {
|
|
38006
38010
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -38068,6 +38072,8 @@ function normalizeConfig$c(config) {
|
|
|
38068
38072
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
38069
38073
|
? source.reverse_auth_ttl_sec
|
|
38070
38074
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
38075
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
38076
|
+
source.enforce_token_subject_node_identity, false);
|
|
38071
38077
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
38072
38078
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
38073
38079
|
config: tokenVerifierConfigInput,
|
|
@@ -38086,6 +38092,7 @@ function normalizeConfig$c(config) {
|
|
|
38086
38092
|
maxTtlSec,
|
|
38087
38093
|
tokenVerifierConfig,
|
|
38088
38094
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
38095
|
+
enforceTokenSubjectNodeIdentity,
|
|
38089
38096
|
...(audience ? { audience } : {}),
|
|
38090
38097
|
};
|
|
38091
38098
|
if (tokenIssuerConfig) {
|
|
@@ -38106,6 +38113,21 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
38106
38113
|
};
|
|
38107
38114
|
return defaultConfig;
|
|
38108
38115
|
}
|
|
38116
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
38117
|
+
if (typeof value === 'boolean') {
|
|
38118
|
+
return value;
|
|
38119
|
+
}
|
|
38120
|
+
if (typeof value === 'string') {
|
|
38121
|
+
const lower = value.toLowerCase().trim();
|
|
38122
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
38123
|
+
return true;
|
|
38124
|
+
}
|
|
38125
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
38126
|
+
return false;
|
|
38127
|
+
}
|
|
38128
|
+
}
|
|
38129
|
+
return defaultValue;
|
|
38130
|
+
}
|
|
38109
38131
|
|
|
38110
38132
|
var oauth2AuthorizerFactory = /*#__PURE__*/Object.freeze({
|
|
38111
38133
|
__proto__: null,
|
|
@@ -41968,6 +41990,10 @@ function normalizeOptions$4(raw) {
|
|
|
41968
41990
|
: typeof snake.aud === 'string'
|
|
41969
41991
|
? snake.aud
|
|
41970
41992
|
: undefined);
|
|
41993
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
41994
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
41995
|
+
? snake.enforce_token_subject_node_identity
|
|
41996
|
+
: undefined);
|
|
41971
41997
|
return {
|
|
41972
41998
|
tokenVerifier,
|
|
41973
41999
|
tokenIssuer,
|
|
@@ -41977,6 +42003,7 @@ function normalizeOptions$4(raw) {
|
|
|
41977
42003
|
defaultTtlSec,
|
|
41978
42004
|
maxTtlSec,
|
|
41979
42005
|
reverseAuthTtlSec,
|
|
42006
|
+
enforceTokenSubjectNodeIdentity,
|
|
41980
42007
|
};
|
|
41981
42008
|
}
|
|
41982
42009
|
class OAuth2Authorizer {
|
|
@@ -41990,6 +42017,8 @@ class OAuth2Authorizer {
|
|
|
41990
42017
|
this.requireScope = options.requireScope ?? true;
|
|
41991
42018
|
this.reverseAuthTtlSec =
|
|
41992
42019
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
42020
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
42021
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
41993
42022
|
}
|
|
41994
42023
|
get tokenVerifier() {
|
|
41995
42024
|
return this.tokenVerifierImpl;
|
|
@@ -42119,6 +42148,13 @@ class OAuth2Authorizer {
|
|
|
42119
42148
|
});
|
|
42120
42149
|
return undefined;
|
|
42121
42150
|
}
|
|
42151
|
+
// Enforce token subject node identity if enabled
|
|
42152
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
42153
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
42154
|
+
if (!validationResult) {
|
|
42155
|
+
return undefined;
|
|
42156
|
+
}
|
|
42157
|
+
}
|
|
42122
42158
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
42123
42159
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
42124
42160
|
claims.accepted_capabilities =
|
|
@@ -42196,6 +42232,33 @@ class OAuth2Authorizer {
|
|
|
42196
42232
|
}
|
|
42197
42233
|
return false;
|
|
42198
42234
|
}
|
|
42235
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
42236
|
+
const sub = claims.sub;
|
|
42237
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
42238
|
+
logger$3.warning('oauth2_attach_missing_subject_claim', {
|
|
42239
|
+
system_id: systemId,
|
|
42240
|
+
});
|
|
42241
|
+
return false;
|
|
42242
|
+
}
|
|
42243
|
+
const expectedPrefix = await core.generateIdAsync({
|
|
42244
|
+
mode: 'fingerprint',
|
|
42245
|
+
material: sub,
|
|
42246
|
+
length: 8,
|
|
42247
|
+
});
|
|
42248
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
42249
|
+
logger$3.warning('oauth2_attach_node_identity_mismatch', {
|
|
42250
|
+
system_id: systemId,
|
|
42251
|
+
expected_prefix: expectedPrefix,
|
|
42252
|
+
subject: sub,
|
|
42253
|
+
});
|
|
42254
|
+
return false;
|
|
42255
|
+
}
|
|
42256
|
+
logger$3.debug('oauth2_attach_node_identity_verified', {
|
|
42257
|
+
system_id: systemId,
|
|
42258
|
+
expected_prefix: expectedPrefix,
|
|
42259
|
+
});
|
|
42260
|
+
return true;
|
|
42261
|
+
}
|
|
42199
42262
|
}
|
|
42200
42263
|
|
|
42201
42264
|
var oauth2Authorizer = /*#__PURE__*/Object.freeze({
|
package/dist/node/node.mjs
CHANGED
|
@@ -4425,12 +4425,12 @@ async function ensureRuntimeFactoriesRegistered(registry = Registry) {
|
|
|
4425
4425
|
}
|
|
4426
4426
|
|
|
4427
4427
|
// This file is auto-generated during build - do not edit manually
|
|
4428
|
-
// Generated from package.json version: 0.3.
|
|
4428
|
+
// Generated from package.json version: 0.3.18
|
|
4429
4429
|
/**
|
|
4430
4430
|
* The package version, injected at build time.
|
|
4431
4431
|
* @internal
|
|
4432
4432
|
*/
|
|
4433
|
-
const VERSION = '0.3.
|
|
4433
|
+
const VERSION = '0.3.18';
|
|
4434
4434
|
|
|
4435
4435
|
let initialized = false;
|
|
4436
4436
|
const runtimePlugin = {
|
|
@@ -29318,6 +29318,7 @@ const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = 'FAME_DEFAULT_ENCRYPTION_LEVEL';
|
|
|
29318
29318
|
const ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
|
|
29319
29319
|
const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
|
|
29320
29320
|
const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
|
|
29321
|
+
const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
|
|
29321
29322
|
const PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
|
|
29322
29323
|
const PROFILE_NAME_OVERLAY = 'overlay';
|
|
29323
29324
|
const PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
|
|
@@ -29553,6 +29554,7 @@ const GATED_PROFILE = {
|
|
|
29553
29554
|
max_ttl_sec: 86400,
|
|
29554
29555
|
algorithm: Expressions.env(ENV_VAR_JWT_ALGORITHM$2, 'RS256'),
|
|
29555
29556
|
audience: Expressions.env(ENV_VAR_JWT_AUDIENCE$2),
|
|
29557
|
+
enforce_token_subject_node_identity: Expressions.env(ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
|
|
29556
29558
|
},
|
|
29557
29559
|
};
|
|
29558
29560
|
const GATED_CALLBACK_PROFILE = {
|
|
@@ -29759,6 +29761,7 @@ function deepClone$3(value) {
|
|
|
29759
29761
|
var nodeSecurityProfileFactory = /*#__PURE__*/Object.freeze({
|
|
29760
29762
|
__proto__: null,
|
|
29761
29763
|
ENV_VAR_DEFAULT_ENCRYPTION_LEVEL: ENV_VAR_DEFAULT_ENCRYPTION_LEVEL,
|
|
29764
|
+
ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY: ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY,
|
|
29762
29765
|
ENV_VAR_HMAC_SECRET: ENV_VAR_HMAC_SECRET,
|
|
29763
29766
|
ENV_VAR_JWKS_URL: ENV_VAR_JWKS_URL,
|
|
29764
29767
|
ENV_VAR_JWT_ALGORITHM: ENV_VAR_JWT_ALGORITHM$2,
|
|
@@ -38000,6 +38003,7 @@ class OAuth2AuthorizerFactory extends AuthorizerFactory {
|
|
|
38000
38003
|
defaultTtlSec: normalized.defaultTtlSec,
|
|
38001
38004
|
maxTtlSec: normalized.maxTtlSec,
|
|
38002
38005
|
reverseAuthTtlSec: normalized.reverseAuthTtlSec,
|
|
38006
|
+
enforceTokenSubjectNodeIdentity: normalized.enforceTokenSubjectNodeIdentity,
|
|
38003
38007
|
};
|
|
38004
38008
|
if (tokenIssuer) {
|
|
38005
38009
|
authorizerOptions.tokenIssuer = tokenIssuer;
|
|
@@ -38067,6 +38071,8 @@ function normalizeConfig$c(config) {
|
|
|
38067
38071
|
: typeof source.reverse_auth_ttl_sec === 'number'
|
|
38068
38072
|
? source.reverse_auth_ttl_sec
|
|
38069
38073
|
: DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
38074
|
+
const enforceTokenSubjectNodeIdentity = normalizeBooleanOption(source.enforceTokenSubjectNodeIdentity ??
|
|
38075
|
+
source.enforce_token_subject_node_identity, false);
|
|
38070
38076
|
const tokenVerifierConfigInput = source.tokenVerifierConfig ?? source.token_verifier_config ?? null;
|
|
38071
38077
|
const tokenVerifierConfig = normalizeTokenVerifierConfig({
|
|
38072
38078
|
config: tokenVerifierConfigInput,
|
|
@@ -38085,6 +38091,7 @@ function normalizeConfig$c(config) {
|
|
|
38085
38091
|
maxTtlSec,
|
|
38086
38092
|
tokenVerifierConfig,
|
|
38087
38093
|
reverseAuthTtlSec: reverseAuthCandidate,
|
|
38094
|
+
enforceTokenSubjectNodeIdentity,
|
|
38088
38095
|
...(audience ? { audience } : {}),
|
|
38089
38096
|
};
|
|
38090
38097
|
if (tokenIssuerConfig) {
|
|
@@ -38105,6 +38112,21 @@ function normalizeTokenVerifierConfig({ config, issuer, jwksUrl, algorithm, }) {
|
|
|
38105
38112
|
};
|
|
38106
38113
|
return defaultConfig;
|
|
38107
38114
|
}
|
|
38115
|
+
function normalizeBooleanOption(value, defaultValue) {
|
|
38116
|
+
if (typeof value === 'boolean') {
|
|
38117
|
+
return value;
|
|
38118
|
+
}
|
|
38119
|
+
if (typeof value === 'string') {
|
|
38120
|
+
const lower = value.toLowerCase().trim();
|
|
38121
|
+
if (lower === 'true' || lower === '1' || lower === 'yes') {
|
|
38122
|
+
return true;
|
|
38123
|
+
}
|
|
38124
|
+
if (lower === 'false' || lower === '0' || lower === 'no') {
|
|
38125
|
+
return false;
|
|
38126
|
+
}
|
|
38127
|
+
}
|
|
38128
|
+
return defaultValue;
|
|
38129
|
+
}
|
|
38108
38130
|
|
|
38109
38131
|
var oauth2AuthorizerFactory = /*#__PURE__*/Object.freeze({
|
|
38110
38132
|
__proto__: null,
|
|
@@ -41967,6 +41989,10 @@ function normalizeOptions$4(raw) {
|
|
|
41967
41989
|
: typeof snake.aud === 'string'
|
|
41968
41990
|
? snake.aud
|
|
41969
41991
|
: undefined);
|
|
41992
|
+
const enforceTokenSubjectNodeIdentity = camel.enforceTokenSubjectNodeIdentity ??
|
|
41993
|
+
(typeof snake.enforce_token_subject_node_identity === 'boolean'
|
|
41994
|
+
? snake.enforce_token_subject_node_identity
|
|
41995
|
+
: undefined);
|
|
41970
41996
|
return {
|
|
41971
41997
|
tokenVerifier,
|
|
41972
41998
|
tokenIssuer,
|
|
@@ -41976,6 +42002,7 @@ function normalizeOptions$4(raw) {
|
|
|
41976
42002
|
defaultTtlSec,
|
|
41977
42003
|
maxTtlSec,
|
|
41978
42004
|
reverseAuthTtlSec,
|
|
42005
|
+
enforceTokenSubjectNodeIdentity,
|
|
41979
42006
|
};
|
|
41980
42007
|
}
|
|
41981
42008
|
class OAuth2Authorizer {
|
|
@@ -41989,6 +42016,8 @@ class OAuth2Authorizer {
|
|
|
41989
42016
|
this.requireScope = options.requireScope ?? true;
|
|
41990
42017
|
this.reverseAuthTtlSec =
|
|
41991
42018
|
options.reverseAuthTtlSec ?? DEFAULT_REVERSE_AUTH_TTL_SEC;
|
|
42019
|
+
this.enforceTokenSubjectNodeIdentity =
|
|
42020
|
+
options.enforceTokenSubjectNodeIdentity ?? false;
|
|
41992
42021
|
}
|
|
41993
42022
|
get tokenVerifier() {
|
|
41994
42023
|
return this.tokenVerifierImpl;
|
|
@@ -42118,6 +42147,13 @@ class OAuth2Authorizer {
|
|
|
42118
42147
|
});
|
|
42119
42148
|
return undefined;
|
|
42120
42149
|
}
|
|
42150
|
+
// Enforce token subject node identity if enabled
|
|
42151
|
+
if (this.enforceTokenSubjectNodeIdentity) {
|
|
42152
|
+
const validationResult = await this.validateTokenSubjectNodeIdentity(frame.systemId, claims);
|
|
42153
|
+
if (!validationResult) {
|
|
42154
|
+
return undefined;
|
|
42155
|
+
}
|
|
42156
|
+
}
|
|
42121
42157
|
claims.instance_id = claims.instance_id ?? frame.instanceId;
|
|
42122
42158
|
claims.assigned_path = claims.assigned_path ?? frame.assignedPath;
|
|
42123
42159
|
claims.accepted_capabilities =
|
|
@@ -42195,6 +42231,33 @@ class OAuth2Authorizer {
|
|
|
42195
42231
|
}
|
|
42196
42232
|
return false;
|
|
42197
42233
|
}
|
|
42234
|
+
async validateTokenSubjectNodeIdentity(systemId, claims) {
|
|
42235
|
+
const sub = claims.sub;
|
|
42236
|
+
if (typeof sub !== 'string' || sub.trim().length === 0) {
|
|
42237
|
+
logger$3.warning('oauth2_attach_missing_subject_claim', {
|
|
42238
|
+
system_id: systemId,
|
|
42239
|
+
});
|
|
42240
|
+
return false;
|
|
42241
|
+
}
|
|
42242
|
+
const expectedPrefix = await generateIdAsync({
|
|
42243
|
+
mode: 'fingerprint',
|
|
42244
|
+
material: sub,
|
|
42245
|
+
length: 8,
|
|
42246
|
+
});
|
|
42247
|
+
if (!systemId.startsWith(`${expectedPrefix}-`)) {
|
|
42248
|
+
logger$3.warning('oauth2_attach_node_identity_mismatch', {
|
|
42249
|
+
system_id: systemId,
|
|
42250
|
+
expected_prefix: expectedPrefix,
|
|
42251
|
+
subject: sub,
|
|
42252
|
+
});
|
|
42253
|
+
return false;
|
|
42254
|
+
}
|
|
42255
|
+
logger$3.debug('oauth2_attach_node_identity_verified', {
|
|
42256
|
+
system_id: systemId,
|
|
42257
|
+
expected_prefix: expectedPrefix,
|
|
42258
|
+
});
|
|
42259
|
+
return true;
|
|
42260
|
+
}
|
|
42198
42261
|
}
|
|
42199
42262
|
|
|
42200
42263
|
var oauth2Authorizer = /*#__PURE__*/Object.freeze({
|
|
@@ -23,6 +23,8 @@ export interface OAuth2AuthorizerConfig extends AuthorizerConfig {
|
|
|
23
23
|
token_issuer_config?: TokenIssuerConfig;
|
|
24
24
|
reverseAuthTtlSec?: number;
|
|
25
25
|
reverse_auth_ttl_sec?: number;
|
|
26
|
+
enforceTokenSubjectNodeIdentity?: boolean;
|
|
27
|
+
enforce_token_subject_node_identity?: boolean;
|
|
26
28
|
}
|
|
27
29
|
export declare const FACTORY_META: {
|
|
28
30
|
readonly base: "AuthorizerFactory";
|
|
@@ -14,6 +14,7 @@ export interface OAuth2AuthorizerOptions {
|
|
|
14
14
|
defaultTtlSec?: number;
|
|
15
15
|
maxTtlSec?: number;
|
|
16
16
|
reverseAuthTtlSec?: number;
|
|
17
|
+
enforceTokenSubjectNodeIdentity?: boolean;
|
|
17
18
|
}
|
|
18
19
|
export declare class OAuth2Authorizer implements Authorizer, TokenVerifierProvider, NodeEventListener {
|
|
19
20
|
readonly priority = 1000;
|
|
@@ -23,6 +24,7 @@ export declare class OAuth2Authorizer implements Authorizer, TokenVerifierProvid
|
|
|
23
24
|
private readonly requiredScopes;
|
|
24
25
|
private readonly requireScope;
|
|
25
26
|
private readonly reverseAuthTtlSec;
|
|
27
|
+
private readonly enforceTokenSubjectNodeIdentity;
|
|
26
28
|
private node?;
|
|
27
29
|
constructor(rawOptions: OAuth2AuthorizerOptions | Record<string, unknown>);
|
|
28
30
|
get tokenVerifier(): TokenVerifier;
|
|
@@ -35,4 +37,5 @@ export declare class OAuth2Authorizer implements Authorizer, TokenVerifierProvid
|
|
|
35
37
|
private extractScopes;
|
|
36
38
|
private mergeScopes;
|
|
37
39
|
private hasRequiredScope;
|
|
40
|
+
private validateTokenSubjectNodeIdentity;
|
|
38
41
|
}
|
|
@@ -10,6 +10,7 @@ export declare const ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = "FAME_DEFAULT_ENCRYPTION
|
|
|
10
10
|
export declare const ENV_VAR_HMAC_SECRET = "FAME_HMAC_SECRET";
|
|
11
11
|
export declare const ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = "FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER";
|
|
12
12
|
export declare const ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = "FAME_JWT_REVERSE_AUTH_AUDIENCE";
|
|
13
|
+
export declare const ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = "FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY";
|
|
13
14
|
export declare const PROFILE_NAME_STRICT_OVERLAY = "strict-overlay";
|
|
14
15
|
export declare const PROFILE_NAME_OVERLAY = "overlay";
|
|
15
16
|
export declare const PROFILE_NAME_OVERLAY_CALLBACK = "overlay-callback";
|
package/dist/types/version.d.ts
CHANGED