ofauth-shared-core 0.1.0-alpha.0 → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +1 -0
- package/dist/index.js +1 -36
- package/package.json +18 -8
- package/dist/OfauthCore.js +0 -200
- package/dist/contracts/AuthAuditContract.js +0 -16
- package/dist/contracts/AuthErrorContract.js +0 -2
- package/dist/contracts/AuthPolicyContract.js +0 -2
- package/dist/contracts/ContextContract.js +0 -8
- package/dist/contracts/IdentityContract.js +0 -2
- package/dist/contracts/SessionContract.js +0 -10
- package/dist/data/applyPendingMigrations.js +0 -30
- package/dist/data/migrations.js +0 -47
- package/dist/data/schemas.js +0 -109
- package/dist/runtime/ContractStage.js +0 -4
- package/dist/services/AuthAuditService.js +0 -2
- package/dist/services/AuthHostComposition.js +0 -100
- package/dist/services/AuthPolicyService.js +0 -2
- package/dist/services/ContextService.js +0 -2
- package/dist/services/IdentityService.js +0 -2
- package/dist/services/SessionService.js +0 -2
- package/dist/services/createContractOnlyOfauthServices.js +0 -82
- package/dist/services/createDbAdapterOfauthServices.js +0 -22
- package/dist/services/errors.js +0 -20
- package/dist/services/impl/DbAdapterAuthAuditService.js +0 -107
- package/dist/services/impl/DbAdapterAuthPolicyService.js +0 -114
- package/dist/services/impl/DbAdapterContextService.js +0 -79
- package/dist/services/impl/DbAdapterIdentityService.js +0 -146
- package/dist/services/impl/DbAdapterSessionService.js +0 -63
- package/dist/services/impl/runtimeSupport.js +0 -112
package/dist/data/schemas.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ofauthSchema = exports.OFAUTH_TABLES = void 0;
|
|
4
|
-
exports.getOfauthTableSchemas = getOfauthTableSchemas;
|
|
5
|
-
exports.OFAUTH_TABLES = {
|
|
6
|
-
identities: 'ofauth_identities',
|
|
7
|
-
assignments: 'ofauth_assignments',
|
|
8
|
-
sessions: 'ofauth_sessions',
|
|
9
|
-
policyProfiles: 'ofauth_policy_profiles',
|
|
10
|
-
policyStepups: 'ofauth_policy_stepups',
|
|
11
|
-
auditEvents: 'ofauth_audit_events',
|
|
12
|
-
};
|
|
13
|
-
const tableSchemas = [
|
|
14
|
-
{
|
|
15
|
-
name: exports.OFAUTH_TABLES.identities,
|
|
16
|
-
columns: [
|
|
17
|
-
{ name: 'id', type: 'string' },
|
|
18
|
-
{ name: 'principal', type: 'string', isIndexed: true },
|
|
19
|
-
{ name: 'secretHash', type: 'string' },
|
|
20
|
-
{ name: 'verifyMethod', type: 'string', enum: ['pin', 'password', 'custom'] },
|
|
21
|
-
{ name: 'status', type: 'string', enum: ['active', 'disabled', 'locked'], isIndexed: true },
|
|
22
|
-
{ name: 'failedAttempts', type: 'number' },
|
|
23
|
-
{ name: 'lockoutUntil', type: 'string', isOptional: true },
|
|
24
|
-
{ name: 'version', type: 'number' },
|
|
25
|
-
{ name: 'lastModified', type: 'string' },
|
|
26
|
-
{ name: 'deleted', type: 'boolean', isIndexed: true },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: exports.OFAUTH_TABLES.assignments,
|
|
31
|
-
columns: [
|
|
32
|
-
{ name: 'id', type: 'string' },
|
|
33
|
-
{ name: 'identityId', type: 'string', isIndexed: true },
|
|
34
|
-
{ name: 'roleRef', type: 'string', isIndexed: true },
|
|
35
|
-
{ name: 'tenantId', type: 'string', isOptional: true, isIndexed: true },
|
|
36
|
-
{ name: 'branchId', type: 'string', isOptional: true, isIndexed: true },
|
|
37
|
-
{ name: 'scopeAttributes', type: 'json', isOptional: true },
|
|
38
|
-
{ name: 'version', type: 'number' },
|
|
39
|
-
{ name: 'lastModified', type: 'string' },
|
|
40
|
-
{ name: 'deleted', type: 'boolean', isIndexed: true },
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: exports.OFAUTH_TABLES.sessions,
|
|
45
|
-
columns: [
|
|
46
|
-
{ name: 'id', type: 'string' },
|
|
47
|
-
{ name: 'identityId', type: 'string', isIndexed: true },
|
|
48
|
-
{ name: 'activeAssignmentId', type: 'string', isOptional: true, isIndexed: true },
|
|
49
|
-
{ name: 'assuranceLevel', type: 'string', enum: ['basic', 'elevated'], isIndexed: true },
|
|
50
|
-
{ name: 'issuedAt', type: 'string' },
|
|
51
|
-
{ name: 'expiresAt', type: 'string', isIndexed: true },
|
|
52
|
-
{ name: 'revokedAt', type: 'string', isOptional: true },
|
|
53
|
-
{ name: 'version', type: 'number' },
|
|
54
|
-
{ name: 'lastModified', type: 'string' },
|
|
55
|
-
{ name: 'deleted', type: 'boolean', isIndexed: true },
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: exports.OFAUTH_TABLES.policyProfiles,
|
|
60
|
-
columns: [
|
|
61
|
-
{ name: 'id', type: 'string' },
|
|
62
|
-
{ name: 'profileId', type: 'string', isIndexed: true },
|
|
63
|
-
{ name: 'defaultAssuranceLevel', type: 'string', enum: ['basic', 'elevated'] },
|
|
64
|
-
{ name: 'lockoutPolicyRef', type: 'string' },
|
|
65
|
-
{ name: 'version', type: 'number' },
|
|
66
|
-
{ name: 'lastModified', type: 'string' },
|
|
67
|
-
{ name: 'deleted', type: 'boolean', isIndexed: true },
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
name: exports.OFAUTH_TABLES.policyStepups,
|
|
72
|
-
columns: [
|
|
73
|
-
{ name: 'id', type: 'string' },
|
|
74
|
-
{ name: 'actionRef', type: 'string', isIndexed: true },
|
|
75
|
-
{ name: 'requiredAssuranceLevel', type: 'string', enum: ['basic', 'elevated'] },
|
|
76
|
-
{ name: 'reauthWindowSeconds', type: 'number', isOptional: true },
|
|
77
|
-
{ name: 'version', type: 'number' },
|
|
78
|
-
{ name: 'lastModified', type: 'string' },
|
|
79
|
-
{ name: 'deleted', type: 'boolean', isIndexed: true },
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
name: exports.OFAUTH_TABLES.auditEvents,
|
|
84
|
-
columns: [
|
|
85
|
-
{ name: 'id', type: 'string' },
|
|
86
|
-
{ name: 'eventType', type: 'string', isIndexed: true },
|
|
87
|
-
{ name: 'identityId', type: 'string', isOptional: true, isIndexed: true },
|
|
88
|
-
{ name: 'sessionId', type: 'string', isOptional: true, isIndexed: true },
|
|
89
|
-
{ name: 'tenantId', type: 'string', isOptional: true, isIndexed: true },
|
|
90
|
-
{ name: 'branchId', type: 'string', isOptional: true, isIndexed: true },
|
|
91
|
-
{ name: 'scopeAttributes', type: 'json', isOptional: true },
|
|
92
|
-
{ name: 'result', type: 'string', enum: ['success', 'failed'], isIndexed: true },
|
|
93
|
-
{ name: 'reasonCode', type: 'string', isOptional: true },
|
|
94
|
-
{ name: 'timestamp', type: 'string', isIndexed: true },
|
|
95
|
-
{ name: 'syncStatus', type: 'string', enum: ['pending', 'replayed'], isIndexed: true },
|
|
96
|
-
{ name: 'replayedAt', type: 'string', isOptional: true, isIndexed: true },
|
|
97
|
-
{ name: 'version', type: 'number' },
|
|
98
|
-
{ name: 'lastModified', type: 'string' },
|
|
99
|
-
{ name: 'deleted', type: 'boolean', isIndexed: true },
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
exports.ofauthSchema = {
|
|
104
|
-
version: 2,
|
|
105
|
-
tables: tableSchemas,
|
|
106
|
-
};
|
|
107
|
-
function getOfauthTableSchemas() {
|
|
108
|
-
return exports.ofauthSchema.tables;
|
|
109
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loginWithResolvedContext = loginWithResolvedContext;
|
|
4
|
-
exports.refreshResolvedContext = refreshResolvedContext;
|
|
5
|
-
exports.switchContextWithResolvedState = switchContextWithResolvedState;
|
|
6
|
-
exports.evaluateProtectedRouteGate = evaluateProtectedRouteGate;
|
|
7
|
-
const SessionContract_1 = require("../contracts/SessionContract");
|
|
8
|
-
function findAssignment(assignments, assignmentId) {
|
|
9
|
-
if (!assignmentId)
|
|
10
|
-
return undefined;
|
|
11
|
-
return assignments.find((row) => row.assignmentId === assignmentId);
|
|
12
|
-
}
|
|
13
|
-
function isScopeAllowed(scope, policy) {
|
|
14
|
-
if (policy.requiredTenantId && scope.tenantId !== policy.requiredTenantId)
|
|
15
|
-
return false;
|
|
16
|
-
if (policy.requiredBranchId && scope.branchId !== policy.requiredBranchId)
|
|
17
|
-
return false;
|
|
18
|
-
if (policy.requiredScopeAttributes) {
|
|
19
|
-
const attrs = scope.attributes ?? {};
|
|
20
|
-
for (const [key, value] of Object.entries(policy.requiredScopeAttributes)) {
|
|
21
|
-
if (attrs[key] !== value)
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
async function buildResolvedContext(services, input) {
|
|
28
|
-
const session = await services.sessionService.getActiveSession(input.sessionId);
|
|
29
|
-
if (!session)
|
|
30
|
-
return null;
|
|
31
|
-
const assignments = await services.contextService.listAssignments(input.identityId);
|
|
32
|
-
let activeContext = await services.contextService.getActiveContext(input.sessionId);
|
|
33
|
-
if (!activeContext && assignments[0]) {
|
|
34
|
-
const switched = await services.contextService.switchContext({
|
|
35
|
-
sessionId: input.sessionId,
|
|
36
|
-
targetAssignmentId: assignments[0].assignmentId,
|
|
37
|
-
...(input.assignmentFallbackReason ? { reasonCode: input.assignmentFallbackReason } : {}),
|
|
38
|
-
});
|
|
39
|
-
activeContext = switched.activeContext;
|
|
40
|
-
}
|
|
41
|
-
const activeAssignment = findAssignment(assignments, activeContext?.assignmentId);
|
|
42
|
-
return {
|
|
43
|
-
sessionId: input.sessionId,
|
|
44
|
-
identityId: input.identityId,
|
|
45
|
-
principal: input.principal,
|
|
46
|
-
assignments,
|
|
47
|
-
activeContextAssignmentId: activeContext?.assignmentId,
|
|
48
|
-
activeAssignment,
|
|
49
|
-
scopeRef: activeContext?.scopeRef ?? activeAssignment?.scopeRef ?? session.activeScopeRef ?? {},
|
|
50
|
-
roleRef: activeAssignment?.roleRef,
|
|
51
|
-
assuranceLevel: session.assuranceLevel,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
async function loginWithResolvedContext(services, input) {
|
|
55
|
-
const login = await services.identityService.login(input);
|
|
56
|
-
const resolved = await buildResolvedContext(services, {
|
|
57
|
-
sessionId: login.sessionId,
|
|
58
|
-
identityId: login.identity.identityId,
|
|
59
|
-
principal: login.identity.principal,
|
|
60
|
-
assignmentFallbackReason: 'AUTO_CONTEXT_AFTER_LOGIN',
|
|
61
|
-
});
|
|
62
|
-
if (!resolved) {
|
|
63
|
-
throw new Error('session is not active after login');
|
|
64
|
-
}
|
|
65
|
-
return resolved;
|
|
66
|
-
}
|
|
67
|
-
async function refreshResolvedContext(services, input) {
|
|
68
|
-
return buildResolvedContext(services, input);
|
|
69
|
-
}
|
|
70
|
-
async function switchContextWithResolvedState(services, input) {
|
|
71
|
-
await services.contextService.switchContext({
|
|
72
|
-
sessionId: input.sessionId,
|
|
73
|
-
targetAssignmentId: input.targetAssignmentId,
|
|
74
|
-
...(input.reasonCode ? { reasonCode: input.reasonCode } : {}),
|
|
75
|
-
});
|
|
76
|
-
const resolved = await buildResolvedContext(services, input);
|
|
77
|
-
if (!resolved) {
|
|
78
|
-
throw new Error('session is not active while switching context');
|
|
79
|
-
}
|
|
80
|
-
return resolved;
|
|
81
|
-
}
|
|
82
|
-
function evaluateProtectedRouteGate(resolved, policy = {}) {
|
|
83
|
-
if (!resolved) {
|
|
84
|
-
return { allowed: false, reasonCode: 'NO_SESSION' };
|
|
85
|
-
}
|
|
86
|
-
const minimumAssurance = policy.minimumAssuranceLevel ?? 'basic';
|
|
87
|
-
if (!(0, SessionContract_1.isAssuranceLevelAtLeast)(resolved.assuranceLevel, minimumAssurance)) {
|
|
88
|
-
return { allowed: false, reasonCode: 'ASSURANCE_TOO_LOW' };
|
|
89
|
-
}
|
|
90
|
-
if (policy.requiredRoleRefs?.length) {
|
|
91
|
-
const hasRole = !!resolved.roleRef && policy.requiredRoleRefs.includes(resolved.roleRef);
|
|
92
|
-
if (!hasRole) {
|
|
93
|
-
return { allowed: false, reasonCode: 'ROLE_FORBIDDEN' };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (!isScopeAllowed(resolved.scopeRef, policy)) {
|
|
97
|
-
return { allowed: false, reasonCode: 'SCOPE_FORBIDDEN' };
|
|
98
|
-
}
|
|
99
|
-
return { allowed: true };
|
|
100
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createContractOnlyOfauthServices = createContractOnlyOfauthServices;
|
|
4
|
-
function notImplemented(message) {
|
|
5
|
-
const error = {
|
|
6
|
-
code: 'AUTH_NOT_IMPLEMENTED',
|
|
7
|
-
message,
|
|
8
|
-
retryable: false,
|
|
9
|
-
};
|
|
10
|
-
throw error;
|
|
11
|
-
}
|
|
12
|
-
function createContractOnlyOfauthServices() {
|
|
13
|
-
return {
|
|
14
|
-
identityService: {
|
|
15
|
-
async verifyCredential() {
|
|
16
|
-
return notImplemented('identityService.verifyCredential not implemented yet');
|
|
17
|
-
},
|
|
18
|
-
async login() {
|
|
19
|
-
return notImplemented('identityService.login not implemented yet');
|
|
20
|
-
},
|
|
21
|
-
async logout() {
|
|
22
|
-
return notImplemented('identityService.logout not implemented yet');
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
sessionService: {
|
|
26
|
-
async createSession() {
|
|
27
|
-
return notImplemented('sessionService.createSession not implemented yet');
|
|
28
|
-
},
|
|
29
|
-
async refreshSession() {
|
|
30
|
-
return notImplemented('sessionService.refreshSession not implemented yet');
|
|
31
|
-
},
|
|
32
|
-
async revokeSession() {
|
|
33
|
-
return notImplemented('sessionService.revokeSession not implemented yet');
|
|
34
|
-
},
|
|
35
|
-
async getActiveSession() {
|
|
36
|
-
return notImplemented('sessionService.getActiveSession not implemented yet');
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
contextService: {
|
|
40
|
-
async listAssignments() {
|
|
41
|
-
return notImplemented('contextService.listAssignments not implemented yet');
|
|
42
|
-
},
|
|
43
|
-
async getActiveContext() {
|
|
44
|
-
return notImplemented('contextService.getActiveContext not implemented yet');
|
|
45
|
-
},
|
|
46
|
-
async switchContext() {
|
|
47
|
-
return notImplemented('contextService.switchContext not implemented yet');
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
authPolicyService: {
|
|
51
|
-
async getPolicySnapshot() {
|
|
52
|
-
return notImplemented('authPolicyService.getPolicySnapshot not implemented yet');
|
|
53
|
-
},
|
|
54
|
-
async getStepUpRequirement() {
|
|
55
|
-
return notImplemented('authPolicyService.getStepUpRequirement not implemented yet');
|
|
56
|
-
},
|
|
57
|
-
async evaluateStepUp() {
|
|
58
|
-
return notImplemented('authPolicyService.evaluateStepUp not implemented yet');
|
|
59
|
-
},
|
|
60
|
-
async enforceStepUp() {
|
|
61
|
-
return notImplemented('authPolicyService.enforceStepUp not implemented yet');
|
|
62
|
-
},
|
|
63
|
-
async markStepUpPassed() {
|
|
64
|
-
return notImplemented('authPolicyService.markStepUpPassed not implemented yet');
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
authAuditService: {
|
|
68
|
-
async appendEvent() {
|
|
69
|
-
return notImplemented('authAuditService.appendEvent not implemented yet');
|
|
70
|
-
},
|
|
71
|
-
async queryEvents() {
|
|
72
|
-
return notImplemented('authAuditService.queryEvents not implemented yet');
|
|
73
|
-
},
|
|
74
|
-
async listPendingReplay() {
|
|
75
|
-
return notImplemented('authAuditService.listPendingReplay not implemented yet');
|
|
76
|
-
},
|
|
77
|
-
async markReplayed() {
|
|
78
|
-
return notImplemented('authAuditService.markReplayed not implemented yet');
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createDbAdapterOfauthServices = createDbAdapterOfauthServices;
|
|
4
|
-
const DbAdapterAuthAuditService_1 = require("./impl/DbAdapterAuthAuditService");
|
|
5
|
-
const DbAdapterAuthPolicyService_1 = require("./impl/DbAdapterAuthPolicyService");
|
|
6
|
-
const DbAdapterContextService_1 = require("./impl/DbAdapterContextService");
|
|
7
|
-
const DbAdapterIdentityService_1 = require("./impl/DbAdapterIdentityService");
|
|
8
|
-
const DbAdapterSessionService_1 = require("./impl/DbAdapterSessionService");
|
|
9
|
-
async function createDbAdapterOfauthServices(db, options = {}) {
|
|
10
|
-
const authAuditService = new DbAdapterAuthAuditService_1.DbAdapterAuthAuditService(db, options);
|
|
11
|
-
const sessionService = new DbAdapterSessionService_1.DbAdapterSessionService(db, options);
|
|
12
|
-
const contextService = new DbAdapterContextService_1.DbAdapterContextService(db, authAuditService);
|
|
13
|
-
const authPolicyService = new DbAdapterAuthPolicyService_1.DbAdapterAuthPolicyService(db, authAuditService);
|
|
14
|
-
const identityService = new DbAdapterIdentityService_1.DbAdapterIdentityService(db, options, sessionService, contextService, authAuditService);
|
|
15
|
-
return {
|
|
16
|
-
identityService,
|
|
17
|
-
sessionService,
|
|
18
|
-
contextService,
|
|
19
|
-
authPolicyService,
|
|
20
|
-
authAuditService,
|
|
21
|
-
};
|
|
22
|
-
}
|
package/dist/services/errors.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OfauthDomainError = void 0;
|
|
4
|
-
exports.unauthorized = unauthorized;
|
|
5
|
-
exports.invalidState = invalidState;
|
|
6
|
-
class OfauthDomainError extends Error {
|
|
7
|
-
constructor(code, message, retryable = false) {
|
|
8
|
-
super(message);
|
|
9
|
-
this.code = code;
|
|
10
|
-
this.retryable = retryable;
|
|
11
|
-
this.name = 'OfauthDomainError';
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
exports.OfauthDomainError = OfauthDomainError;
|
|
15
|
-
function unauthorized(code, message) {
|
|
16
|
-
return new OfauthDomainError(code, message, false);
|
|
17
|
-
}
|
|
18
|
-
function invalidState(message) {
|
|
19
|
-
return new OfauthDomainError('AUTH_NOT_IMPLEMENTED', message, false);
|
|
20
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DbAdapterAuthAuditService = void 0;
|
|
4
|
-
const schemas_1 = require("../../data/schemas");
|
|
5
|
-
const runtimeSupport_1 = require("./runtimeSupport");
|
|
6
|
-
class DbAdapterAuthAuditService {
|
|
7
|
-
constructor(db, options) {
|
|
8
|
-
this.db = db;
|
|
9
|
-
this.options = options;
|
|
10
|
-
this.newId = (0, runtimeSupport_1.makeIdFactory)('auth-audit');
|
|
11
|
-
}
|
|
12
|
-
async appendEvent(event) {
|
|
13
|
-
const row = {
|
|
14
|
-
id: event.eventId || this.newId(),
|
|
15
|
-
eventType: event.eventType,
|
|
16
|
-
identityId: event.identityId ?? null,
|
|
17
|
-
sessionId: event.sessionId ?? null,
|
|
18
|
-
tenantId: event.scopeRef?.tenantId ?? null,
|
|
19
|
-
branchId: event.scopeRef?.branchId ?? null,
|
|
20
|
-
scopeAttributes: event.scopeRef?.attributes ?? null,
|
|
21
|
-
result: event.result,
|
|
22
|
-
reasonCode: event.reasonCode ?? null,
|
|
23
|
-
timestamp: event.timestamp,
|
|
24
|
-
syncStatus: event.syncStatus ?? 'pending',
|
|
25
|
-
replayedAt: event.replayedAt ?? null,
|
|
26
|
-
version: 1,
|
|
27
|
-
lastModified: (0, runtimeSupport_1.nowIso)(),
|
|
28
|
-
deleted: false,
|
|
29
|
-
};
|
|
30
|
-
await this.db.create(schemas_1.OFAUTH_TABLES.auditEvents, row);
|
|
31
|
-
await (0, runtimeSupport_1.emitAuthActivity)(this.options, event);
|
|
32
|
-
}
|
|
33
|
-
async queryEvents(query) {
|
|
34
|
-
const rows = await this.db.query(schemas_1.OFAUTH_TABLES.auditEvents, {
|
|
35
|
-
filters: { deleted: false },
|
|
36
|
-
sort: [{ field: 'timestamp', direction: 'desc' }],
|
|
37
|
-
});
|
|
38
|
-
return rows
|
|
39
|
-
.filter((row) => (query.identityId ? row.identityId === query.identityId : true))
|
|
40
|
-
.filter((row) => (query.sessionId ? row.sessionId === query.sessionId : true))
|
|
41
|
-
.filter((row) => (query.eventTypes?.length ? query.eventTypes.includes(row.eventType) : true))
|
|
42
|
-
.filter((row) => (query.fromTimestamp ? row.timestamp >= query.fromTimestamp : true))
|
|
43
|
-
.filter((row) => (query.toTimestamp ? row.timestamp <= query.toTimestamp : true))
|
|
44
|
-
.map((row) => ({
|
|
45
|
-
eventId: row.id,
|
|
46
|
-
eventType: row.eventType,
|
|
47
|
-
identityId: row.identityId ?? undefined,
|
|
48
|
-
sessionId: row.sessionId ?? undefined,
|
|
49
|
-
scopeRef: row.tenantId || row.branchId || row.scopeAttributes
|
|
50
|
-
? {
|
|
51
|
-
...(row.tenantId ? { tenantId: row.tenantId } : {}),
|
|
52
|
-
...(row.branchId ? { branchId: row.branchId } : {}),
|
|
53
|
-
...(row.scopeAttributes ? { attributes: row.scopeAttributes } : {}),
|
|
54
|
-
}
|
|
55
|
-
: undefined,
|
|
56
|
-
result: row.result,
|
|
57
|
-
reasonCode: row.reasonCode ?? undefined,
|
|
58
|
-
timestamp: row.timestamp,
|
|
59
|
-
syncStatus: row.syncStatus ?? 'pending',
|
|
60
|
-
replayedAt: row.replayedAt ?? undefined,
|
|
61
|
-
}));
|
|
62
|
-
}
|
|
63
|
-
async listPendingReplay(query = {}) {
|
|
64
|
-
const rows = await this.db.query(schemas_1.OFAUTH_TABLES.auditEvents, {
|
|
65
|
-
filters: { deleted: false },
|
|
66
|
-
sort: [{ field: 'timestamp', direction: 'asc' }],
|
|
67
|
-
});
|
|
68
|
-
return rows
|
|
69
|
-
.filter((row) => row.syncStatus !== 'replayed')
|
|
70
|
-
.slice(0, query.limit ?? rows.length)
|
|
71
|
-
.map((row) => ({
|
|
72
|
-
eventId: row.id,
|
|
73
|
-
eventType: row.eventType,
|
|
74
|
-
identityId: row.identityId ?? undefined,
|
|
75
|
-
sessionId: row.sessionId ?? undefined,
|
|
76
|
-
scopeRef: row.tenantId || row.branchId || row.scopeAttributes
|
|
77
|
-
? {
|
|
78
|
-
...(row.tenantId ? { tenantId: row.tenantId } : {}),
|
|
79
|
-
...(row.branchId ? { branchId: row.branchId } : {}),
|
|
80
|
-
...(row.scopeAttributes ? { attributes: row.scopeAttributes } : {}),
|
|
81
|
-
}
|
|
82
|
-
: undefined,
|
|
83
|
-
result: row.result,
|
|
84
|
-
reasonCode: row.reasonCode ?? undefined,
|
|
85
|
-
timestamp: row.timestamp,
|
|
86
|
-
syncStatus: row.syncStatus ?? 'pending',
|
|
87
|
-
replayedAt: row.replayedAt ?? undefined,
|
|
88
|
-
}));
|
|
89
|
-
}
|
|
90
|
-
async markReplayed(eventIds, replayedAt = (0, runtimeSupport_1.nowIso)()) {
|
|
91
|
-
let updatedCount = 0;
|
|
92
|
-
for (const eventId of eventIds) {
|
|
93
|
-
const row = await this.db.get(schemas_1.OFAUTH_TABLES.auditEvents, eventId);
|
|
94
|
-
if (!row || row.deleted || row.syncStatus === 'replayed')
|
|
95
|
-
continue;
|
|
96
|
-
await this.db.update(schemas_1.OFAUTH_TABLES.auditEvents, eventId, {
|
|
97
|
-
syncStatus: 'replayed',
|
|
98
|
-
replayedAt,
|
|
99
|
-
version: row.version + 1,
|
|
100
|
-
lastModified: (0, runtimeSupport_1.nowIso)(),
|
|
101
|
-
});
|
|
102
|
-
updatedCount += 1;
|
|
103
|
-
}
|
|
104
|
-
return updatedCount;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
exports.DbAdapterAuthAuditService = DbAdapterAuthAuditService;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DbAdapterAuthPolicyService = void 0;
|
|
4
|
-
const SessionContract_1 = require("../../contracts/SessionContract");
|
|
5
|
-
const schemas_1 = require("../../data/schemas");
|
|
6
|
-
const errors_1 = require("../errors");
|
|
7
|
-
const runtimeSupport_1 = require("./runtimeSupport");
|
|
8
|
-
class DbAdapterAuthPolicyService {
|
|
9
|
-
constructor(db, authAuditService) {
|
|
10
|
-
this.db = db;
|
|
11
|
-
this.authAuditService = authAuditService;
|
|
12
|
-
this.newEventId = (0, runtimeSupport_1.makeIdFactory)('auth-event');
|
|
13
|
-
}
|
|
14
|
-
async getActiveSessionOrThrow(sessionId) {
|
|
15
|
-
const row = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, sessionId);
|
|
16
|
-
if (!row || row.deleted || row.revokedAt || (0, runtimeSupport_1.isPast)(row.expiresAt)) {
|
|
17
|
-
throw (0, errors_1.unauthorized)('AUTH_SESSION_NOT_FOUND', 'Session not found');
|
|
18
|
-
}
|
|
19
|
-
return row;
|
|
20
|
-
}
|
|
21
|
-
async getPolicySnapshot() {
|
|
22
|
-
const profiles = await this.db.query(schemas_1.OFAUTH_TABLES.policyProfiles, {
|
|
23
|
-
filters: { deleted: false },
|
|
24
|
-
sort: [{ field: 'lastModified', direction: 'desc' }],
|
|
25
|
-
});
|
|
26
|
-
const stepups = await this.db.query(schemas_1.OFAUTH_TABLES.policyStepups, {
|
|
27
|
-
filters: { deleted: false },
|
|
28
|
-
sort: [{ field: 'lastModified', direction: 'desc' }],
|
|
29
|
-
});
|
|
30
|
-
return {
|
|
31
|
-
profiles: profiles.length > 0
|
|
32
|
-
? profiles.map((p) => ({
|
|
33
|
-
profileId: p.profileId,
|
|
34
|
-
defaultAssuranceLevel: p.defaultAssuranceLevel,
|
|
35
|
-
lockoutPolicyRef: p.lockoutPolicyRef,
|
|
36
|
-
}))
|
|
37
|
-
: (0, runtimeSupport_1.fallbackPolicyProfiles)(),
|
|
38
|
-
stepUpRequirements: stepups.map((s) => ({
|
|
39
|
-
actionRef: s.actionRef,
|
|
40
|
-
requiredAssuranceLevel: s.requiredAssuranceLevel,
|
|
41
|
-
reauthWindowSeconds: s.reauthWindowSeconds ?? undefined,
|
|
42
|
-
})),
|
|
43
|
-
version: '1',
|
|
44
|
-
updatedAt: (0, runtimeSupport_1.nowIso)(),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
async getStepUpRequirement(actionRef) {
|
|
48
|
-
const row = await this.db.query(schemas_1.OFAUTH_TABLES.policyStepups, {
|
|
49
|
-
filters: { actionRef, deleted: false },
|
|
50
|
-
limit: 1,
|
|
51
|
-
});
|
|
52
|
-
if (!row[0])
|
|
53
|
-
return null;
|
|
54
|
-
return {
|
|
55
|
-
actionRef: row[0].actionRef,
|
|
56
|
-
requiredAssuranceLevel: row[0].requiredAssuranceLevel,
|
|
57
|
-
reauthWindowSeconds: row[0].reauthWindowSeconds ?? undefined,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
async evaluateStepUp(sessionId, actionRef) {
|
|
61
|
-
const session = await this.getActiveSessionOrThrow(sessionId);
|
|
62
|
-
const requirement = await this.getStepUpRequirement(actionRef);
|
|
63
|
-
const requiredAssuranceLevel = requirement?.requiredAssuranceLevel ?? 'basic';
|
|
64
|
-
const requiresStepUp = !(0, SessionContract_1.isAssuranceLevelAtLeast)(session.assuranceLevel, requiredAssuranceLevel);
|
|
65
|
-
return {
|
|
66
|
-
actionRef,
|
|
67
|
-
requiredAssuranceLevel,
|
|
68
|
-
currentAssuranceLevel: session.assuranceLevel,
|
|
69
|
-
requiresStepUp,
|
|
70
|
-
reauthWindowSeconds: requirement?.reauthWindowSeconds,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
async enforceStepUp(sessionId, actionRef) {
|
|
74
|
-
const session = await this.getActiveSessionOrThrow(sessionId);
|
|
75
|
-
const evalResult = await this.evaluateStepUp(sessionId, actionRef);
|
|
76
|
-
if (!evalResult.requiresStepUp)
|
|
77
|
-
return;
|
|
78
|
-
await this.authAuditService.appendEvent({
|
|
79
|
-
eventId: this.newEventId(),
|
|
80
|
-
eventType: 'STEP_UP_CHALLENGED',
|
|
81
|
-
identityId: session.identityId,
|
|
82
|
-
sessionId,
|
|
83
|
-
result: 'failed',
|
|
84
|
-
reasonCode: 'AUTH_STEP_UP_REQUIRED',
|
|
85
|
-
timestamp: (0, runtimeSupport_1.nowIso)(),
|
|
86
|
-
});
|
|
87
|
-
throw (0, errors_1.unauthorized)('AUTH_STEP_UP_REQUIRED', `Step-up required for action '${actionRef}' (needs ${evalResult.requiredAssuranceLevel})`);
|
|
88
|
-
}
|
|
89
|
-
async markStepUpPassed(sessionId, actionRef) {
|
|
90
|
-
const session = await this.getActiveSessionOrThrow(sessionId);
|
|
91
|
-
const requirement = await this.getStepUpRequirement(actionRef);
|
|
92
|
-
const targetAssurance = requirement?.requiredAssuranceLevel ?? 'elevated';
|
|
93
|
-
await this.db.update(schemas_1.OFAUTH_TABLES.sessions, sessionId, {
|
|
94
|
-
assuranceLevel: targetAssurance,
|
|
95
|
-
version: session.version + 1,
|
|
96
|
-
lastModified: (0, runtimeSupport_1.nowIso)(),
|
|
97
|
-
});
|
|
98
|
-
await this.authAuditService.appendEvent({
|
|
99
|
-
eventId: this.newEventId(),
|
|
100
|
-
eventType: 'STEP_UP_PASSED',
|
|
101
|
-
identityId: session.identityId,
|
|
102
|
-
sessionId,
|
|
103
|
-
result: 'success',
|
|
104
|
-
reasonCode: actionRef,
|
|
105
|
-
timestamp: (0, runtimeSupport_1.nowIso)(),
|
|
106
|
-
});
|
|
107
|
-
const active = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, sessionId);
|
|
108
|
-
const assignment = active ? await (0, runtimeSupport_1.getAssignmentById)(this.db, active.activeAssignmentId) : null;
|
|
109
|
-
if (!active)
|
|
110
|
-
throw (0, errors_1.unauthorized)('AUTH_SESSION_NOT_FOUND', 'Session not found');
|
|
111
|
-
return (0, runtimeSupport_1.toSessionRef)(active, assignment ?? undefined);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
exports.DbAdapterAuthPolicyService = DbAdapterAuthPolicyService;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DbAdapterContextService = void 0;
|
|
4
|
-
const schemas_1 = require("../../data/schemas");
|
|
5
|
-
const errors_1 = require("../errors");
|
|
6
|
-
const runtimeSupport_1 = require("./runtimeSupport");
|
|
7
|
-
class DbAdapterContextService {
|
|
8
|
-
constructor(db, authAuditService) {
|
|
9
|
-
this.db = db;
|
|
10
|
-
this.authAuditService = authAuditService;
|
|
11
|
-
this.newEventId = (0, runtimeSupport_1.makeIdFactory)('auth-event');
|
|
12
|
-
}
|
|
13
|
-
async listAssignments(identityId) {
|
|
14
|
-
const rows = await this.db.query(schemas_1.OFAUTH_TABLES.assignments, {
|
|
15
|
-
filters: { identityId, deleted: false },
|
|
16
|
-
sort: [{ field: 'lastModified', direction: 'desc' }],
|
|
17
|
-
});
|
|
18
|
-
return rows.map(runtimeSupport_1.toAssignment);
|
|
19
|
-
}
|
|
20
|
-
async getActiveContext(sessionId) {
|
|
21
|
-
const session = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, sessionId);
|
|
22
|
-
if (!session || session.deleted || session.revokedAt || !session.activeAssignmentId)
|
|
23
|
-
return null;
|
|
24
|
-
const assignment = await (0, runtimeSupport_1.getAssignmentById)(this.db, session.activeAssignmentId);
|
|
25
|
-
if (!assignment)
|
|
26
|
-
return null;
|
|
27
|
-
return {
|
|
28
|
-
sessionId,
|
|
29
|
-
assignmentId: assignment.id,
|
|
30
|
-
scopeRef: {
|
|
31
|
-
...(assignment.tenantId ? { tenantId: assignment.tenantId } : {}),
|
|
32
|
-
...(assignment.branchId ? { branchId: assignment.branchId } : {}),
|
|
33
|
-
...(assignment.scopeAttributes ? { attributes: assignment.scopeAttributes } : {}),
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
async switchContext(input) {
|
|
38
|
-
const session = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, input.sessionId);
|
|
39
|
-
if (!session || session.deleted || session.revokedAt)
|
|
40
|
-
throw (0, errors_1.unauthorized)('AUTH_SESSION_NOT_FOUND', 'Session not found');
|
|
41
|
-
const target = await (0, runtimeSupport_1.getAssignmentById)(this.db, input.targetAssignmentId);
|
|
42
|
-
if (!target || target.identityId !== session.identityId) {
|
|
43
|
-
throw (0, errors_1.unauthorized)('AUTH_CONTEXT_FORBIDDEN', 'Requested context is not assigned to this identity');
|
|
44
|
-
}
|
|
45
|
-
const updatedSession = await this.db.update(schemas_1.OFAUTH_TABLES.sessions, input.sessionId, {
|
|
46
|
-
activeAssignmentId: target.id,
|
|
47
|
-
version: session.version + 1,
|
|
48
|
-
lastModified: (0, runtimeSupport_1.nowIso)(),
|
|
49
|
-
});
|
|
50
|
-
await this.authAuditService.appendEvent({
|
|
51
|
-
eventId: this.newEventId(),
|
|
52
|
-
eventType: 'CONTEXT_SWITCHED',
|
|
53
|
-
identityId: session.identityId,
|
|
54
|
-
sessionId: input.sessionId,
|
|
55
|
-
scopeRef: {
|
|
56
|
-
...(target.tenantId ? { tenantId: target.tenantId } : {}),
|
|
57
|
-
...(target.branchId ? { branchId: target.branchId } : {}),
|
|
58
|
-
...(target.scopeAttributes ? { attributes: target.scopeAttributes } : {}),
|
|
59
|
-
},
|
|
60
|
-
result: 'success',
|
|
61
|
-
reasonCode: input.reasonCode,
|
|
62
|
-
timestamp: updatedSession.lastModified,
|
|
63
|
-
});
|
|
64
|
-
return {
|
|
65
|
-
activeContext: {
|
|
66
|
-
sessionId: input.sessionId,
|
|
67
|
-
assignmentId: target.id,
|
|
68
|
-
scopeRef: {
|
|
69
|
-
...(target.tenantId ? { tenantId: target.tenantId } : {}),
|
|
70
|
-
...(target.branchId ? { branchId: target.branchId } : {}),
|
|
71
|
-
...(target.scopeAttributes ? { attributes: target.scopeAttributes } : {}),
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
requiresStepUp: false,
|
|
75
|
-
reasonCode: input.reasonCode,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
exports.DbAdapterContextService = DbAdapterContextService;
|