ofauth-shared-core 0.1.0-alpha.0 → 0.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +10 -0
  2. package/dist/OfauthCore.d.ts +0 -1
  3. package/dist/contracts/AuthAuditContract.d.ts +6 -0
  4. package/dist/contracts/AuthErrorContract.d.ts +1 -1
  5. package/dist/contracts/AuthPolicyContract.d.ts +13 -0
  6. package/dist/contracts/ContextContract.d.ts +23 -4
  7. package/dist/contracts/IdentityContract.d.ts +14 -0
  8. package/dist/contracts/SessionContract.d.ts +20 -1
  9. package/dist/index.d.ts +6 -4
  10. package/dist/index.esm.js +1 -0
  11. package/dist/index.js +1 -36
  12. package/dist/services/AuthAuthorityAdapter.d.ts +42 -0
  13. package/dist/services/AuthHostComposition.d.ts +5 -2
  14. package/dist/services/AuthOfflinePolicy.d.ts +11 -0
  15. package/dist/services/AuthSessionCacheAdapter.d.ts +16 -0
  16. package/dist/services/contractCompatibility.d.ts +12 -0
  17. package/dist/services/createContractOnlyOfauthServices.d.ts +8 -8
  18. package/dist/services/createDbAdapterOfauthServices.d.ts +0 -8
  19. package/dist/services/createServerAuthoritativeAuthBridge.d.ts +25 -0
  20. package/dist/services/errors.d.ts +10 -0
  21. package/dist/services/impl/DbAdapterSessionService.d.ts +2 -0
  22. package/dist/services/impl/runtimeSupport.d.ts +1 -1
  23. package/dist/services/localProvisioning.d.ts +23 -0
  24. package/dist/services/responseEnvelope.d.ts +10 -0
  25. package/package.json +21 -10
  26. package/dist/OfauthCore.js +0 -200
  27. package/dist/contracts/AuthAuditContract.js +0 -16
  28. package/dist/contracts/AuthErrorContract.js +0 -2
  29. package/dist/contracts/AuthPolicyContract.js +0 -2
  30. package/dist/contracts/ContextContract.js +0 -8
  31. package/dist/contracts/IdentityContract.js +0 -2
  32. package/dist/contracts/SessionContract.js +0 -10
  33. package/dist/data/applyPendingMigrations.js +0 -30
  34. package/dist/data/migrations.js +0 -47
  35. package/dist/data/schemas.js +0 -109
  36. package/dist/runtime/ContractStage.js +0 -4
  37. package/dist/services/AuthAuditService.js +0 -2
  38. package/dist/services/AuthHostComposition.js +0 -100
  39. package/dist/services/AuthPolicyService.js +0 -2
  40. package/dist/services/ContextService.js +0 -2
  41. package/dist/services/IdentityService.js +0 -2
  42. package/dist/services/SessionService.js +0 -2
  43. package/dist/services/createContractOnlyOfauthServices.js +0 -82
  44. package/dist/services/createDbAdapterOfauthServices.js +0 -22
  45. package/dist/services/errors.js +0 -20
  46. package/dist/services/impl/DbAdapterAuthAuditService.js +0 -107
  47. package/dist/services/impl/DbAdapterAuthPolicyService.js +0 -114
  48. package/dist/services/impl/DbAdapterContextService.js +0 -79
  49. package/dist/services/impl/DbAdapterIdentityService.js +0 -146
  50. package/dist/services/impl/DbAdapterSessionService.js +0 -63
  51. package/dist/services/impl/runtimeSupport.js +0 -112
@@ -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
- }
@@ -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;
@@ -1,146 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DbAdapterIdentityService = void 0;
4
- const schemas_1 = require("../../data/schemas");
5
- const errors_1 = require("../errors");
6
- const runtimeSupport_1 = require("./runtimeSupport");
7
- class DbAdapterIdentityService {
8
- constructor(db, options, sessionService, contextService, authAuditService) {
9
- this.db = db;
10
- this.options = options;
11
- this.sessionService = sessionService;
12
- this.contextService = contextService;
13
- this.authAuditService = authAuditService;
14
- this.newEventId = (0, runtimeSupport_1.makeIdFactory)('auth-event');
15
- }
16
- async findIdentityByPrincipal(principal) {
17
- const rows = await this.db.query(schemas_1.OFAUTH_TABLES.identities, {
18
- filters: { principal, deleted: false },
19
- limit: 1,
20
- });
21
- return rows[0] ?? null;
22
- }
23
- async persistFailedAttempt(identity) {
24
- const failedAttempts = identity.failedAttempts + 1;
25
- const lockoutTriggered = failedAttempts >= runtimeSupport_1.DEFAULT_LOCKOUT_THRESHOLD;
26
- const lockoutUntil = lockoutTriggered ? (0, runtimeSupport_1.plusSecondsIso)((0, runtimeSupport_1.nowIso)(), runtimeSupport_1.DEFAULT_LOCKOUT_COOLDOWN_SECONDS) : null;
27
- const status = lockoutTriggered ? 'locked' : identity.status;
28
- return this.db.update(schemas_1.OFAUTH_TABLES.identities, identity.id, {
29
- failedAttempts,
30
- lockoutUntil,
31
- status,
32
- version: identity.version + 1,
33
- lastModified: (0, runtimeSupport_1.nowIso)(),
34
- });
35
- }
36
- async clearFailedAttempt(identity) {
37
- if (identity.failedAttempts === 0 && !identity.lockoutUntil && identity.status === 'active')
38
- return;
39
- await this.db.update(schemas_1.OFAUTH_TABLES.identities, identity.id, {
40
- failedAttempts: 0,
41
- lockoutUntil: null,
42
- status: 'active',
43
- version: identity.version + 1,
44
- lastModified: (0, runtimeSupport_1.nowIso)(),
45
- });
46
- }
47
- async emitAudit(event) {
48
- await this.authAuditService.appendEvent(event);
49
- }
50
- async verifyCredential(input) {
51
- const identity = await this.findIdentityByPrincipal(input.principal);
52
- if (!identity) {
53
- await this.emitAudit({
54
- eventId: this.newEventId(),
55
- eventType: 'LOGIN_FAILED',
56
- result: 'failed',
57
- reasonCode: 'INVALID_CREDENTIAL',
58
- timestamp: (0, runtimeSupport_1.nowIso)(),
59
- });
60
- return { ok: false, reasonCode: 'INVALID_CREDENTIAL', retryable: true };
61
- }
62
- if (identity.status === 'disabled') {
63
- await this.emitAudit({
64
- eventId: this.newEventId(),
65
- eventType: 'LOGIN_FAILED',
66
- identityId: identity.id,
67
- result: 'failed',
68
- reasonCode: 'IDENTITY_DISABLED',
69
- timestamp: (0, runtimeSupport_1.nowIso)(),
70
- });
71
- return { ok: false, reasonCode: 'IDENTITY_DISABLED', retryable: false };
72
- }
73
- if (identity.lockoutUntil && !(0, runtimeSupport_1.isPast)(identity.lockoutUntil)) {
74
- await this.emitAudit({
75
- eventId: this.newEventId(),
76
- eventType: 'LOCKOUT_TRIGGERED',
77
- identityId: identity.id,
78
- result: 'failed',
79
- reasonCode: 'IDENTITY_LOCKED',
80
- timestamp: (0, runtimeSupport_1.nowIso)(),
81
- });
82
- return { ok: false, reasonCode: 'IDENTITY_LOCKED', retryable: false };
83
- }
84
- const verified = await (0, runtimeSupport_1.verifySecret)(this.options.platformAdapter, input.secret, identity.secretHash);
85
- if (!verified) {
86
- const afterFail = await this.persistFailedAttempt(identity);
87
- const reasonCode = afterFail.status === 'locked' ? 'IDENTITY_LOCKED' : 'INVALID_CREDENTIAL';
88
- await this.emitAudit({
89
- eventId: this.newEventId(),
90
- eventType: reasonCode === 'IDENTITY_LOCKED' ? 'LOCKOUT_TRIGGERED' : 'LOGIN_FAILED',
91
- identityId: identity.id,
92
- result: 'failed',
93
- reasonCode,
94
- timestamp: (0, runtimeSupport_1.nowIso)(),
95
- });
96
- return { ok: false, reasonCode, retryable: reasonCode === 'INVALID_CREDENTIAL' };
97
- }
98
- await this.clearFailedAttempt(identity);
99
- const assignments = await this.contextService.listAssignments(identity.id);
100
- await this.emitAudit({
101
- eventId: this.newEventId(),
102
- eventType: 'LOGIN_SUCCESS',
103
- identityId: identity.id,
104
- scopeRef: input.scopeRef,
105
- result: 'success',
106
- timestamp: (0, runtimeSupport_1.nowIso)(),
107
- });
108
- return {
109
- ok: true,
110
- identity: (0, runtimeSupport_1.toIdentityRef)(identity),
111
- assignments,
112
- };
113
- }
114
- async login(input) {
115
- const verified = await this.verifyCredential({
116
- principal: input.principal,
117
- secret: input.secret,
118
- verifyMethod: input.verifyMethod,
119
- });
120
- if (!verified.ok) {
121
- throw (0, errors_1.unauthorized)('AUTH_INVALID_CREDENTIAL', `Authentication failed: ${verified.reasonCode}`);
122
- }
123
- const defaultAssignment = [...verified.assignments].sort((a, b) => a.assignmentId.localeCompare(b.assignmentId))[0];
124
- const session = await this.sessionService.createSession({
125
- identityId: verified.identity.identityId,
126
- assignmentId: defaultAssignment?.assignmentId,
127
- assuranceLevel: 'basic',
128
- });
129
- return {
130
- identity: verified.identity,
131
- sessionId: session.sessionId,
132
- };
133
- }
134
- async logout(sessionId) {
135
- await this.sessionService.revokeSession({ sessionId, reasonCode: 'LOGOUT' });
136
- await this.emitAudit({
137
- eventId: this.newEventId(),
138
- eventType: 'SESSION_REVOKED',
139
- sessionId,
140
- result: 'success',
141
- reasonCode: 'LOGOUT',
142
- timestamp: (0, runtimeSupport_1.nowIso)(),
143
- });
144
- }
145
- }
146
- exports.DbAdapterIdentityService = DbAdapterIdentityService;
@@ -1,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DbAdapterSessionService = void 0;
4
- const schemas_1 = require("../../data/schemas");
5
- const errors_1 = require("../errors");
6
- const runtimeSupport_1 = require("./runtimeSupport");
7
- class DbAdapterSessionService {
8
- constructor(db, options) {
9
- this.db = db;
10
- this.options = options;
11
- this.newId = (0, runtimeSupport_1.makeIdFactory)('auth-session');
12
- }
13
- async createSession(input) {
14
- const issuedAt = (0, runtimeSupport_1.nowIso)();
15
- const expiresAt = (0, runtimeSupport_1.plusSecondsIso)(issuedAt, input.ttlSeconds ?? runtimeSupport_1.DEFAULT_SESSION_TTL_SECONDS);
16
- const created = await this.db.create(schemas_1.OFAUTH_TABLES.sessions, {
17
- id: this.newId(),
18
- identityId: input.identityId,
19
- activeAssignmentId: input.assignmentId ?? null,
20
- assuranceLevel: input.assuranceLevel ?? 'basic',
21
- issuedAt,
22
- expiresAt,
23
- revokedAt: null,
24
- version: 1,
25
- lastModified: issuedAt,
26
- deleted: false,
27
- });
28
- const assignment = await (0, runtimeSupport_1.getAssignmentById)(this.db, created.activeAssignmentId);
29
- this.options.logger?.logInfo('[ofauth] session created', { sessionId: created.id, identityId: created.identityId });
30
- return (0, runtimeSupport_1.toSessionRef)(created, assignment);
31
- }
32
- async refreshSession(input) {
33
- const current = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, input.sessionId);
34
- if (!current || current.deleted || current.revokedAt)
35
- throw (0, errors_1.unauthorized)('AUTH_SESSION_NOT_FOUND', 'Session not found');
36
- const refreshed = await this.db.update(schemas_1.OFAUTH_TABLES.sessions, input.sessionId, {
37
- expiresAt: (0, runtimeSupport_1.plusSecondsIso)((0, runtimeSupport_1.nowIso)(), input.ttlSeconds ?? runtimeSupport_1.DEFAULT_SESSION_TTL_SECONDS),
38
- version: current.version + 1,
39
- lastModified: (0, runtimeSupport_1.nowIso)(),
40
- });
41
- const assignment = await (0, runtimeSupport_1.getAssignmentById)(this.db, refreshed.activeAssignmentId);
42
- return (0, runtimeSupport_1.toSessionRef)(refreshed, assignment);
43
- }
44
- async revokeSession(input) {
45
- const current = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, input.sessionId);
46
- if (!current || current.deleted || current.revokedAt)
47
- return;
48
- await this.db.update(schemas_1.OFAUTH_TABLES.sessions, input.sessionId, {
49
- revokedAt: (0, runtimeSupport_1.nowIso)(),
50
- version: current.version + 1,
51
- lastModified: (0, runtimeSupport_1.nowIso)(),
52
- });
53
- this.options.logger?.logInfo('[ofauth] session revoked', { sessionId: input.sessionId, reasonCode: input.reasonCode ?? null });
54
- }
55
- async getActiveSession(sessionId) {
56
- const row = await this.db.get(schemas_1.OFAUTH_TABLES.sessions, sessionId);
57
- if (!row || row.deleted || row.revokedAt || (0, runtimeSupport_1.isPast)(row.expiresAt))
58
- return null;
59
- const assignment = await (0, runtimeSupport_1.getAssignmentById)(this.db, row.activeAssignmentId);
60
- return (0, runtimeSupport_1.toSessionRef)(row, assignment);
61
- }
62
- }
63
- exports.DbAdapterSessionService = DbAdapterSessionService;