@tstdl/base 0.93.78 → 0.93.81
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/api/server/gateway.js +1 -1
- package/authentication/authentication.api.d.ts +9 -0
- package/authentication/authentication.api.js +3 -0
- package/authentication/client/authentication.service.d.ts +23 -15
- package/authentication/client/authentication.service.js +30 -21
- package/authentication/index.d.ts +1 -0
- package/authentication/index.js +1 -0
- package/authentication/models/authentication-credentials.model.d.ts +2 -2
- package/authentication/models/authentication-credentials.model.js +5 -5
- package/authentication/models/authentication-session.model.d.ts +2 -2
- package/authentication/models/authentication-session.model.js +3 -3
- package/authentication/models/subject.model.js +5 -3
- package/authentication/models/token-payload-base.model.d.ts +5 -1
- package/authentication/models/token-payload-base.model.js +10 -2
- package/authentication/models/token.model.d.ts +9 -1
- package/authentication/server/authentication-ancillary.service.d.ts +12 -15
- package/authentication/server/authentication-ancillary.service.js +3 -0
- package/authentication/server/authentication.api-controller.js +5 -5
- package/authentication/server/authentication.audit.d.ts +7 -5
- package/authentication/server/authentication.service.d.ts +32 -22
- package/authentication/server/authentication.service.js +116 -65
- package/authentication/server/drizzle/{0001_condemned_pretty_boy.sql → 0000_violet_callisto.sql} +34 -5
- package/authentication/server/drizzle/meta/0000_snapshot.json +500 -6
- package/authentication/server/drizzle/meta/_journal.json +2 -9
- package/authentication/types.d.ts +6 -0
- package/authentication/types.js +1 -0
- package/document-management/server/drizzle/{0000_ordinary_pretty_boy.sql → 0000_glamorous_lorna_dane.sql} +96 -76
- package/document-management/server/drizzle/meta/0000_snapshot.json +360 -142
- package/document-management/server/drizzle/meta/_journal.json +2 -16
- package/examples/api/authentication.js +3 -2
- package/examples/api/custom-authentication.js +11 -9
- package/orm/server/drizzle/schema-converter.js +53 -32
- package/package.json +1 -1
- package/authentication/server/drizzle/0000_calm_warlock.sql +0 -28
- package/authentication/server/drizzle/meta/0001_snapshot.json +0 -651
- package/document-management/server/drizzle/0001_lyrical_wong.sql +0 -123
- package/document-management/server/drizzle/0002_round_warbird.sql +0 -1
- package/document-management/server/drizzle/meta/0001_snapshot.json +0 -2728
- package/document-management/server/drizzle/meta/0002_snapshot.json +0 -2722
package/api/server/gateway.js
CHANGED
|
@@ -206,7 +206,7 @@ let ApiGateway = ApiGateway_1 = class ApiGateway {
|
|
|
206
206
|
path: context.request.url.pathname,
|
|
207
207
|
ipAddress: context.request.ip,
|
|
208
208
|
userAgent: context.request.headers.tryGetSingle('User-Agent') ?? null,
|
|
209
|
-
sessionId: token?.payload.
|
|
209
|
+
sessionId: token?.payload.session ?? null,
|
|
210
210
|
},
|
|
211
211
|
});
|
|
212
212
|
},
|
|
@@ -27,6 +27,7 @@ export declare const authenticationApiDefinition: {
|
|
|
27
27
|
resource: string;
|
|
28
28
|
method: "POST";
|
|
29
29
|
parameters: ObjectSchema<{
|
|
30
|
+
readonly tenantId: string | undefined;
|
|
30
31
|
readonly subject: string;
|
|
31
32
|
readonly secret: string;
|
|
32
33
|
readonly data: undefined;
|
|
@@ -87,6 +88,7 @@ export declare const authenticationApiDefinition: {
|
|
|
87
88
|
resource: string;
|
|
88
89
|
method: "POST";
|
|
89
90
|
parameters: ObjectSchema<{
|
|
91
|
+
readonly tenantId: string | undefined;
|
|
90
92
|
readonly subject: string;
|
|
91
93
|
readonly currentSecret: string;
|
|
92
94
|
readonly newSecret: string;
|
|
@@ -98,6 +100,7 @@ export declare const authenticationApiDefinition: {
|
|
|
98
100
|
resource: string;
|
|
99
101
|
method: "POST";
|
|
100
102
|
parameters: ObjectSchema<{
|
|
103
|
+
readonly tenantId: string | undefined;
|
|
101
104
|
readonly subject: string;
|
|
102
105
|
readonly data: undefined;
|
|
103
106
|
}>;
|
|
@@ -146,6 +149,7 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
|
|
|
146
149
|
resource: string;
|
|
147
150
|
method: "POST";
|
|
148
151
|
parameters: ObjectSchema<{
|
|
152
|
+
readonly tenantId: string | undefined;
|
|
149
153
|
readonly subject: string;
|
|
150
154
|
readonly secret: string;
|
|
151
155
|
readonly data: AuthenticationData;
|
|
@@ -206,6 +210,7 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
|
|
|
206
210
|
resource: string;
|
|
207
211
|
method: "POST";
|
|
208
212
|
parameters: ObjectSchema<{
|
|
213
|
+
readonly tenantId: string | undefined;
|
|
209
214
|
readonly subject: string;
|
|
210
215
|
readonly currentSecret: string;
|
|
211
216
|
readonly newSecret: string;
|
|
@@ -217,6 +222,7 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
|
|
|
217
222
|
resource: string;
|
|
218
223
|
method: "POST";
|
|
219
224
|
parameters: ObjectSchema<{
|
|
225
|
+
readonly tenantId: string | undefined;
|
|
220
226
|
readonly subject: string;
|
|
221
227
|
readonly data: AdditionalInitSecretResetData;
|
|
222
228
|
}>;
|
|
@@ -260,6 +266,7 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
|
|
|
260
266
|
resource: string;
|
|
261
267
|
method: "POST";
|
|
262
268
|
parameters: ObjectSchema<{
|
|
269
|
+
readonly tenantId: string | undefined;
|
|
263
270
|
readonly subject: string;
|
|
264
271
|
readonly secret: string;
|
|
265
272
|
readonly data: AuthenticationData;
|
|
@@ -320,6 +327,7 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
|
|
|
320
327
|
resource: string;
|
|
321
328
|
method: "POST";
|
|
322
329
|
parameters: ObjectSchema<{
|
|
330
|
+
readonly tenantId: string | undefined;
|
|
323
331
|
readonly subject: string;
|
|
324
332
|
readonly currentSecret: string;
|
|
325
333
|
readonly newSecret: string;
|
|
@@ -331,6 +339,7 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
|
|
|
331
339
|
resource: string;
|
|
332
340
|
method: "POST";
|
|
333
341
|
parameters: ObjectSchema<{
|
|
342
|
+
readonly tenantId: string | undefined;
|
|
334
343
|
readonly subject: string;
|
|
335
344
|
readonly data: AdditionalInitSecretResetData;
|
|
336
345
|
}>;
|
|
@@ -48,6 +48,7 @@ export function getAuthenticationApiEndpointsDefinition(additionalTokenPayloadSc
|
|
|
48
48
|
resource: 'token',
|
|
49
49
|
method: 'POST',
|
|
50
50
|
parameters: explicitObject({
|
|
51
|
+
tenantId: optional(string()),
|
|
51
52
|
subject: string(),
|
|
52
53
|
secret: string(),
|
|
53
54
|
data: authenticationDataSchema,
|
|
@@ -108,6 +109,7 @@ export function getAuthenticationApiEndpointsDefinition(additionalTokenPayloadSc
|
|
|
108
109
|
resource: 'secret/change',
|
|
109
110
|
method: 'POST',
|
|
110
111
|
parameters: explicitObject({
|
|
112
|
+
tenantId: optional(string()),
|
|
111
113
|
subject: string(),
|
|
112
114
|
currentSecret: string(),
|
|
113
115
|
newSecret: string(),
|
|
@@ -119,6 +121,7 @@ export function getAuthenticationApiEndpointsDefinition(additionalTokenPayloadSc
|
|
|
119
121
|
resource: 'secret/init-reset',
|
|
120
122
|
method: 'POST',
|
|
121
123
|
parameters: explicitObject({
|
|
124
|
+
tenantId: optional(string()),
|
|
122
125
|
subject: string(),
|
|
123
126
|
data: additionalInitSecretResetDataSchema,
|
|
124
127
|
}),
|
|
@@ -2,6 +2,7 @@ import type { AfterResolve } from '../../injector/index.js';
|
|
|
2
2
|
import { afterResolve } from '../../injector/index.js';
|
|
3
3
|
import type { Record } from '../../types/index.js';
|
|
4
4
|
import type { SecretCheckResult, TokenPayload } from '../models/index.js';
|
|
5
|
+
import type { SubjectInput } from '../types.js';
|
|
5
6
|
/**
|
|
6
7
|
* Handles authentication on client side.
|
|
7
8
|
*
|
|
@@ -35,10 +36,12 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
|
|
|
35
36
|
readonly token: import("../../signals/api.js").WritableSignal<TokenPayload<AdditionalTokenPayload> | undefined>;
|
|
36
37
|
/** Whether the user is logged in */
|
|
37
38
|
readonly isLoggedIn: import("../../signals/api.js").Signal<boolean>;
|
|
38
|
-
/** Current subject */
|
|
39
|
-
readonly subject: import("../../signals/api.js").Signal<string | undefined>;
|
|
40
39
|
/** Current session id */
|
|
41
40
|
readonly sessionId: import("../../signals/api.js").Signal<string | undefined>;
|
|
41
|
+
/** Current tenant id */
|
|
42
|
+
readonly tenantId: import("../../signals/api.js").Signal<string | undefined>;
|
|
43
|
+
/** Current subject */
|
|
44
|
+
readonly subjectId: import("../../signals/api.js").Signal<string | undefined>;
|
|
42
45
|
/** Current impersonator */
|
|
43
46
|
readonly impersonator: import("../../signals/api.js").Signal<string | undefined>;
|
|
44
47
|
/** Whether the user is impersonated */
|
|
@@ -50,9 +53,9 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
|
|
|
50
53
|
/** Emits when a valid token is available (not undefined and not expired) */
|
|
51
54
|
readonly validToken$: import("rxjs").Observable<Exclude<TokenPayload<AdditionalTokenPayload>, void | undefined>>;
|
|
52
55
|
/** Current subject */
|
|
53
|
-
readonly
|
|
56
|
+
readonly subjectId$: import("rxjs").Observable<string | undefined>;
|
|
54
57
|
/** Emits when subject is available */
|
|
55
|
-
readonly
|
|
58
|
+
readonly definedSubjectId$: import("rxjs").Observable<string>;
|
|
56
59
|
/** Current session id */
|
|
57
60
|
readonly sessionId$: import("rxjs").Observable<string | undefined>;
|
|
58
61
|
/** Emits when session id is available */
|
|
@@ -70,16 +73,21 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
|
|
|
70
73
|
* @throws Will throw if token is not available
|
|
71
74
|
*/
|
|
72
75
|
get definedToken(): TokenPayload<AdditionalTokenPayload>;
|
|
73
|
-
/**
|
|
74
|
-
* Get current subject or throw if not available
|
|
75
|
-
* @throws Will throw if subject is not available
|
|
76
|
-
*/
|
|
77
|
-
get definedSubject(): string;
|
|
78
76
|
/**
|
|
79
77
|
* Get current session id or throw if not available
|
|
80
78
|
* @throws Will throw if session id is not available
|
|
81
79
|
*/
|
|
82
80
|
get definedSessionId(): string;
|
|
81
|
+
/**
|
|
82
|
+
* Get current tenant id or throw if not available
|
|
83
|
+
* @throws Will throw if tenant id is not available
|
|
84
|
+
*/
|
|
85
|
+
get definedTenantId(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Get current subject or throw if not available
|
|
88
|
+
* @throws Will throw if subject is not available
|
|
89
|
+
*/
|
|
90
|
+
get definedSubject(): string;
|
|
83
91
|
/** Whether a valid token is available (not undefined and not expired) */
|
|
84
92
|
get hasValidToken(): boolean;
|
|
85
93
|
constructor();
|
|
@@ -106,11 +114,11 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
|
|
|
106
114
|
setAdditionalData(data: AuthenticationData): void;
|
|
107
115
|
/**
|
|
108
116
|
* Login with subject and secret
|
|
109
|
-
* @param
|
|
117
|
+
* @param subjectInput The subject to login with
|
|
110
118
|
* @param secret The secret to login with
|
|
111
119
|
* @param data Additional authentication data
|
|
112
120
|
*/
|
|
113
|
-
login(
|
|
121
|
+
login(subjectInput: SubjectInput, secret: string, data?: AuthenticationData): Promise<void>;
|
|
114
122
|
/**
|
|
115
123
|
* Logout from the current session.
|
|
116
124
|
* This will attempt to end the session on the server and then clear local credentials.
|
|
@@ -139,17 +147,17 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
|
|
|
139
147
|
unimpersonate(data?: AuthenticationData): Promise<void>;
|
|
140
148
|
/**
|
|
141
149
|
* Change the secret for a subject.
|
|
142
|
-
* @param
|
|
150
|
+
* @param subjectInput The subject to change the secret for
|
|
143
151
|
* @param currentSecret The current secret
|
|
144
152
|
* @param newSecret The new secret
|
|
145
153
|
*/
|
|
146
|
-
changeSecret(
|
|
154
|
+
changeSecret(subjectInput: SubjectInput, currentSecret: string, newSecret: string): Promise<void>;
|
|
147
155
|
/**
|
|
148
156
|
* Initialize a secret reset.
|
|
149
|
-
* @param
|
|
157
|
+
* @param subjectInput The subject to reset the secret for
|
|
150
158
|
* @param data Additional data for secret reset
|
|
151
159
|
*/
|
|
152
|
-
initResetSecret(
|
|
160
|
+
initResetSecret(subjectInput: SubjectInput, data: AdditionalInitSecretResetData): Promise<void>;
|
|
153
161
|
/**
|
|
154
162
|
* Reset a secret using a reset token.
|
|
155
163
|
* @param token The secret reset token
|
|
@@ -78,10 +78,12 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
78
78
|
token = signal(undefined);
|
|
79
79
|
/** Whether the user is logged in */
|
|
80
80
|
isLoggedIn = computed(() => isDefined(this.token()));
|
|
81
|
-
/** Current subject */
|
|
82
|
-
subject = computed(() => this.token()?.subject);
|
|
83
81
|
/** Current session id */
|
|
84
|
-
sessionId = computed(() => this.token()?.
|
|
82
|
+
sessionId = computed(() => this.token()?.session);
|
|
83
|
+
/** Current tenant id */
|
|
84
|
+
tenantId = computed(() => this.token()?.tenant);
|
|
85
|
+
/** Current subject */
|
|
86
|
+
subjectId = computed(() => this.token()?.subject);
|
|
85
87
|
/** Current impersonator */
|
|
86
88
|
impersonator = computed(() => this.token()?.impersonator);
|
|
87
89
|
/** Whether the user is impersonated */
|
|
@@ -93,9 +95,9 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
93
95
|
/** Emits when a valid token is available (not undefined and not expired) */
|
|
94
96
|
validToken$ = this.definedToken$.pipe(filter((token) => token.exp > this.estimatedServerTimestampSeconds()));
|
|
95
97
|
/** Current subject */
|
|
96
|
-
|
|
98
|
+
subjectId$ = toObservable(this.subjectId);
|
|
97
99
|
/** Emits when subject is available */
|
|
98
|
-
|
|
100
|
+
definedSubjectId$ = this.subjectId$.pipe(filter(isDefined));
|
|
99
101
|
/** Current session id */
|
|
100
102
|
sessionId$ = toObservable(this.sessionId);
|
|
101
103
|
/** Emits when session id is available */
|
|
@@ -123,6 +125,20 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
123
125
|
get definedToken() {
|
|
124
126
|
return assertDefinedPass(this.token(), 'No token available.');
|
|
125
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Get current session id or throw if not available
|
|
130
|
+
* @throws Will throw if session id is not available
|
|
131
|
+
*/
|
|
132
|
+
get definedSessionId() {
|
|
133
|
+
return this.definedToken.session;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get current tenant id or throw if not available
|
|
137
|
+
* @throws Will throw if tenant id is not available
|
|
138
|
+
*/
|
|
139
|
+
get definedTenantId() {
|
|
140
|
+
return this.definedToken.tenant;
|
|
141
|
+
}
|
|
126
142
|
/**
|
|
127
143
|
* Get current subject or throw if not available
|
|
128
144
|
* @throws Will throw if subject is not available
|
|
@@ -130,13 +146,6 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
130
146
|
get definedSubject() {
|
|
131
147
|
return this.definedToken.subject;
|
|
132
148
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Get current session id or throw if not available
|
|
135
|
-
* @throws Will throw if session id is not available
|
|
136
|
-
*/
|
|
137
|
-
get definedSessionId() {
|
|
138
|
-
return this.definedToken.sessionId;
|
|
139
|
-
}
|
|
140
149
|
/** Whether a valid token is available (not undefined and not expired) */
|
|
141
150
|
get hasValidToken() {
|
|
142
151
|
return (this.token()?.exp ?? 0) > this.estimatedServerTimestampSeconds();
|
|
@@ -184,16 +193,16 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
184
193
|
}
|
|
185
194
|
/**
|
|
186
195
|
* Login with subject and secret
|
|
187
|
-
* @param
|
|
196
|
+
* @param subjectInput The subject to login with
|
|
188
197
|
* @param secret The secret to login with
|
|
189
198
|
* @param data Additional authentication data
|
|
190
199
|
*/
|
|
191
|
-
async login(
|
|
200
|
+
async login(subjectInput, secret, data) {
|
|
192
201
|
if (isDefined(data)) {
|
|
193
202
|
this.setAdditionalData(data);
|
|
194
203
|
}
|
|
195
204
|
const [token] = await Promise.all([
|
|
196
|
-
this.client.login({ subject, secret, data: this.authenticationData }),
|
|
205
|
+
this.client.login({ tenantId: subjectInput.tenantId, subject: subjectInput.subject, secret, data: this.authenticationData }),
|
|
197
206
|
this.syncClock(),
|
|
198
207
|
]);
|
|
199
208
|
this.setNewToken(token);
|
|
@@ -291,20 +300,20 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
291
300
|
}
|
|
292
301
|
/**
|
|
293
302
|
* Change the secret for a subject.
|
|
294
|
-
* @param
|
|
303
|
+
* @param subjectInput The subject to change the secret for
|
|
295
304
|
* @param currentSecret The current secret
|
|
296
305
|
* @param newSecret The new secret
|
|
297
306
|
*/
|
|
298
|
-
async changeSecret(
|
|
299
|
-
await this.client.changeSecret({ subject, currentSecret, newSecret });
|
|
307
|
+
async changeSecret(subjectInput, currentSecret, newSecret) {
|
|
308
|
+
await this.client.changeSecret({ tenantId: subjectInput.tenantId, subject: subjectInput.subject, currentSecret, newSecret });
|
|
300
309
|
}
|
|
301
310
|
/**
|
|
302
311
|
* Initialize a secret reset.
|
|
303
|
-
* @param
|
|
312
|
+
* @param subjectInput The subject to reset the secret for
|
|
304
313
|
* @param data Additional data for secret reset
|
|
305
314
|
*/
|
|
306
|
-
async initResetSecret(
|
|
307
|
-
await this.client.initSecretReset({ subject, data });
|
|
315
|
+
async initResetSecret(subjectInput, data) {
|
|
316
|
+
await this.client.initSecretReset({ tenantId: subjectInput.tenantId, subject: subjectInput.subject, data });
|
|
308
317
|
}
|
|
309
318
|
/**
|
|
310
319
|
* Reset a secret using a reset token.
|
package/authentication/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare class AuthenticationCredentials extends
|
|
1
|
+
import { TenantEntity, type Uuid } from '../../orm/index.js';
|
|
2
|
+
export declare class AuthenticationCredentials extends TenantEntity {
|
|
3
3
|
subject: Uuid;
|
|
4
4
|
hashVersion: number;
|
|
5
5
|
/**
|
|
@@ -7,10 +7,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { Table, TenantEntity, TenantReference, Unique, UuidProperty } from '../../orm/index.js';
|
|
11
11
|
import { Integer, Uint8ArrayProperty } from '../../schema/index.js';
|
|
12
12
|
import { Subject } from './subject.model.js';
|
|
13
|
-
let AuthenticationCredentials = class AuthenticationCredentials extends
|
|
13
|
+
let AuthenticationCredentials = class AuthenticationCredentials extends TenantEntity {
|
|
14
14
|
subject;
|
|
15
15
|
hashVersion;
|
|
16
16
|
/**
|
|
@@ -23,8 +23,7 @@ let AuthenticationCredentials = class AuthenticationCredentials extends Entity {
|
|
|
23
23
|
hash;
|
|
24
24
|
};
|
|
25
25
|
__decorate([
|
|
26
|
-
|
|
27
|
-
Unique(),
|
|
26
|
+
TenantReference(() => Subject),
|
|
28
27
|
UuidProperty(),
|
|
29
28
|
__metadata("design:type", String)
|
|
30
29
|
], AuthenticationCredentials.prototype, "subject", void 0);
|
|
@@ -41,6 +40,7 @@ __decorate([
|
|
|
41
40
|
__metadata("design:type", Uint8Array)
|
|
42
41
|
], AuthenticationCredentials.prototype, "hash", void 0);
|
|
43
42
|
AuthenticationCredentials = __decorate([
|
|
44
|
-
Table('credentials', { schema: 'authentication' })
|
|
43
|
+
Table('credentials', { schema: 'authentication' }),
|
|
44
|
+
Unique(['tenantId', 'subject'])
|
|
45
45
|
], AuthenticationCredentials);
|
|
46
46
|
export { AuthenticationCredentials };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Timestamp, Uuid } from '../../orm/index.js';
|
|
2
|
-
import {
|
|
3
|
-
export declare class AuthenticationSession extends
|
|
2
|
+
import { TenantEntity } from '../../orm/index.js';
|
|
3
|
+
export declare class AuthenticationSession extends TenantEntity {
|
|
4
4
|
subject: Uuid;
|
|
5
5
|
begin: Timestamp;
|
|
6
6
|
end: Timestamp;
|
|
@@ -7,10 +7,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { Table, TenantEntity, TenantReference, TimestampProperty, UuidProperty } from '../../orm/index.js';
|
|
11
11
|
import { Integer, Uint8ArrayProperty } from '../../schema/index.js';
|
|
12
12
|
import { Subject } from './subject.model.js';
|
|
13
|
-
let AuthenticationSession = class AuthenticationSession extends
|
|
13
|
+
let AuthenticationSession = class AuthenticationSession extends TenantEntity {
|
|
14
14
|
subject;
|
|
15
15
|
begin;
|
|
16
16
|
end;
|
|
@@ -25,7 +25,7 @@ let AuthenticationSession = class AuthenticationSession extends Entity {
|
|
|
25
25
|
refreshTokenHash;
|
|
26
26
|
};
|
|
27
27
|
__decorate([
|
|
28
|
-
|
|
28
|
+
TenantReference(() => Subject),
|
|
29
29
|
UuidProperty(),
|
|
30
30
|
__metadata("design:type", String)
|
|
31
31
|
], AuthenticationSession.prototype, "subject", void 0);
|
|
@@ -35,25 +35,27 @@ __decorate([
|
|
|
35
35
|
__metadata("design:type", String)
|
|
36
36
|
], Subject.prototype, "displayName", void 0);
|
|
37
37
|
__decorate([
|
|
38
|
-
Unique(),
|
|
39
38
|
TenantReference(() => SystemAccount),
|
|
40
39
|
UuidProperty({ nullable: true }),
|
|
41
40
|
__metadata("design:type", Object)
|
|
42
41
|
], Subject.prototype, "systemAccountId", void 0);
|
|
43
42
|
__decorate([
|
|
44
|
-
Unique(),
|
|
45
43
|
TenantReference(() => User),
|
|
46
44
|
UuidProperty({ nullable: true }),
|
|
47
45
|
__metadata("design:type", Object)
|
|
48
46
|
], Subject.prototype, "userId", void 0);
|
|
49
47
|
__decorate([
|
|
50
|
-
Unique(),
|
|
51
48
|
TenantReference(() => ServiceAccount),
|
|
52
49
|
UuidProperty({ nullable: true }),
|
|
53
50
|
__metadata("design:type", Object)
|
|
54
51
|
], Subject.prototype, "serviceAccountId", void 0);
|
|
55
52
|
Subject = __decorate([
|
|
56
53
|
Table('subject', { schema: 'authentication' }),
|
|
54
|
+
Unique(['id']) // for external systems that might not support composite identities
|
|
55
|
+
,
|
|
56
|
+
Unique(['tenantId', 'systemAccountId']),
|
|
57
|
+
Unique(['tenantId', 'userId']),
|
|
58
|
+
Unique(['tenantId', 'serviceAccountId']),
|
|
57
59
|
Check('authentication_subject_reference_check', (table) => exclusiveNotNull(table.systemAccountId, table.userId, table.serviceAccountId))
|
|
58
60
|
], Subject);
|
|
59
61
|
export { Subject };
|
|
@@ -31,7 +31,11 @@ export class TokenPayloadBase {
|
|
|
31
31
|
/**
|
|
32
32
|
* The id of the session.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
session;
|
|
35
|
+
/**
|
|
36
|
+
* The tenant id.
|
|
37
|
+
*/
|
|
38
|
+
tenant;
|
|
35
39
|
/**
|
|
36
40
|
* The subject of the token.
|
|
37
41
|
*/
|
|
@@ -60,7 +64,11 @@ __decorate([
|
|
|
60
64
|
__decorate([
|
|
61
65
|
StringProperty(),
|
|
62
66
|
__metadata("design:type", String)
|
|
63
|
-
], TokenPayloadBase.prototype, "
|
|
67
|
+
], TokenPayloadBase.prototype, "session", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
StringProperty(),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], TokenPayloadBase.prototype, "tenant", void 0);
|
|
64
72
|
__decorate([
|
|
65
73
|
StringProperty(),
|
|
66
74
|
__metadata("design:type", String)
|
|
@@ -22,6 +22,10 @@ export type RefreshToken = JwtToken<{
|
|
|
22
22
|
* Expiration timestamp in seconds.
|
|
23
23
|
*/
|
|
24
24
|
exp: number;
|
|
25
|
+
/**
|
|
26
|
+
* The tenant id.
|
|
27
|
+
*/
|
|
28
|
+
tenant: string;
|
|
25
29
|
/**
|
|
26
30
|
* The subject of the token.
|
|
27
31
|
*/
|
|
@@ -33,7 +37,7 @@ export type RefreshToken = JwtToken<{
|
|
|
33
37
|
/**
|
|
34
38
|
* The id of the session.
|
|
35
39
|
*/
|
|
36
|
-
|
|
40
|
+
session: string;
|
|
37
41
|
/**
|
|
38
42
|
* The secret to use for refreshing the token.
|
|
39
43
|
*/
|
|
@@ -44,6 +48,10 @@ export type SecretResetToken = JwtToken<{
|
|
|
44
48
|
* Expiration timestamp in seconds.
|
|
45
49
|
*/
|
|
46
50
|
exp: number;
|
|
51
|
+
/**
|
|
52
|
+
* The tenant id.
|
|
53
|
+
*/
|
|
54
|
+
tenant: string;
|
|
47
55
|
/**
|
|
48
56
|
* The subject for which to reset the secret.
|
|
49
57
|
*/
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type EnumType } from '../../enumeration/enumeration.js';
|
|
2
2
|
import type { Record } from '../../types/index.js';
|
|
3
|
-
import type
|
|
3
|
+
import { Subject, type TokenPayload } from '../models/index.js';
|
|
4
4
|
import type { InitSecretResetData } from '../models/init-secret-reset-data.model.js';
|
|
5
|
+
import type { SubjectInput } from '../types.js';
|
|
5
6
|
export declare const GetTokenPayloadContextAction: {
|
|
6
7
|
readonly GetToken: "get-token";
|
|
7
8
|
readonly Refresh: "refresh";
|
|
@@ -13,13 +14,6 @@ export type GetTokenPayloadContext = {
|
|
|
13
14
|
*/
|
|
14
15
|
action: GetTokenPayloadContextAction;
|
|
15
16
|
};
|
|
16
|
-
export type ResolveSubjectResult = {
|
|
17
|
-
success: true;
|
|
18
|
-
subject: string;
|
|
19
|
-
} | {
|
|
20
|
-
success: false;
|
|
21
|
-
subject?: undefined;
|
|
22
|
-
};
|
|
23
17
|
/**
|
|
24
18
|
* Ancillary service for authentication to hook into the authentication process.
|
|
25
19
|
*
|
|
@@ -28,14 +22,17 @@ export type ResolveSubjectResult = {
|
|
|
28
22
|
* @param AdditionalInitSecretResetData Type of additional secret reset data
|
|
29
23
|
*/
|
|
30
24
|
export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayload extends Record = Record<never>, AuthenticationData = void, AdditionalInitSecretResetData = void> {
|
|
25
|
+
readonly subjectRepository: import("../../orm/server/repository.js").EntityRepository<Subject>;
|
|
31
26
|
/**
|
|
32
|
-
* Resolve a provided subject
|
|
27
|
+
* Resolve a provided subject (like what was entered into login form) to all matching actual subjects.
|
|
33
28
|
* Useful for example if you want to be able to login via mail but actual subject is the user id.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* If
|
|
29
|
+
*
|
|
30
|
+
* If multiple subjects are found (like same mail in multiple tenants), all should be returned.
|
|
31
|
+
* If no subjects are found, an empty array should be returned.
|
|
32
|
+
* @param data The subject provided by the user, e.g. an email address and tenantId if available (for example by tenant specific subdomains).
|
|
33
|
+
* @returns An array of resolved subjects.
|
|
37
34
|
*/
|
|
38
|
-
abstract
|
|
35
|
+
abstract resolveSubjects(data: SubjectInput): Promise<Subject[]>;
|
|
39
36
|
/**
|
|
40
37
|
* Get the additional token payload for a subject.
|
|
41
38
|
* @param subject The subject for which to get the payload.
|
|
@@ -43,7 +40,7 @@ export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayl
|
|
|
43
40
|
* @param context Context for getting the token payload.
|
|
44
41
|
* @returns The additional token payload.
|
|
45
42
|
*/
|
|
46
|
-
abstract getTokenPayload(subject:
|
|
43
|
+
abstract getTokenPayload(subject: Subject, authenticationData: AuthenticationData, context: GetTokenPayloadContext): AdditionalTokenPayload | Promise<AdditionalTokenPayload>;
|
|
47
44
|
/**
|
|
48
45
|
* Handle the initialization of a secret reset.
|
|
49
46
|
* @param data Data for initializing the secret reset.
|
|
@@ -56,5 +53,5 @@ export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayl
|
|
|
56
53
|
* @param authenticationData Additional authentication data.
|
|
57
54
|
* @returns Whether impersonation is allowed.
|
|
58
55
|
*/
|
|
59
|
-
abstract canImpersonate(token: TokenPayload<AdditionalTokenPayload>, subject:
|
|
56
|
+
abstract canImpersonate(token: TokenPayload<AdditionalTokenPayload>, subject: Subject, authenticationData: AuthenticationData): boolean | Promise<boolean>;
|
|
60
57
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { defineEnum } from '../../enumeration/enumeration.js';
|
|
2
|
+
import { injectRepository } from '../../orm/server/repository.js';
|
|
3
|
+
import { Subject } from '../models/index.js';
|
|
2
4
|
export const GetTokenPayloadContextAction = defineEnum('GetTokenPayloadContextAction', {
|
|
3
5
|
GetToken: 'get-token',
|
|
4
6
|
Refresh: 'refresh',
|
|
@@ -11,4 +13,5 @@ export const GetTokenPayloadContextAction = defineEnum('GetTokenPayloadContextAc
|
|
|
11
13
|
* @param AdditionalInitSecretResetData Type of additional secret reset data
|
|
12
14
|
*/
|
|
13
15
|
export class AuthenticationAncillaryService {
|
|
16
|
+
subjectRepository = injectRepository(Subject);
|
|
14
17
|
}
|
|
@@ -34,7 +34,7 @@ let AuthenticationApiController = class AuthenticationApiController {
|
|
|
34
34
|
* @returns The token result.
|
|
35
35
|
*/
|
|
36
36
|
async login({ parameters, getAuditor }) {
|
|
37
|
-
const result = await this.authenticationService.login(parameters.subject, parameters.secret, parameters.data, await getAuditor());
|
|
37
|
+
const result = await this.authenticationService.login({ tenantId: parameters.tenantId, subject: parameters.subject }, parameters.secret, parameters.data, await getAuditor());
|
|
38
38
|
return this.getTokenResponse(result);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
@@ -81,13 +81,13 @@ let AuthenticationApiController = class AuthenticationApiController {
|
|
|
81
81
|
try {
|
|
82
82
|
const tokenString = tryGetAuthorizationTokenStringFromRequest(request) ?? '';
|
|
83
83
|
const token = await this.authenticationService.validateToken(tokenString);
|
|
84
|
-
sessionId = token.payload.
|
|
84
|
+
sessionId = token.payload.session;
|
|
85
85
|
}
|
|
86
86
|
catch (error) {
|
|
87
87
|
try {
|
|
88
88
|
const refreshTokenString = tryGetAuthorizationTokenStringFromRequest(request, 'refreshToken', true) ?? '';
|
|
89
89
|
const refreshToken = await this.authenticationService.validateRefreshToken(refreshTokenString);
|
|
90
|
-
sessionId = refreshToken.payload.
|
|
90
|
+
sessionId = refreshToken.payload.session;
|
|
91
91
|
}
|
|
92
92
|
catch {
|
|
93
93
|
throw error;
|
|
@@ -107,7 +107,7 @@ let AuthenticationApiController = class AuthenticationApiController {
|
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
async changeSecret({ parameters, getAuditor }) {
|
|
110
|
-
await this.authenticationService.changeSecret(parameters.subject, parameters.currentSecret, parameters.newSecret, await getAuditor());
|
|
110
|
+
await this.authenticationService.changeSecret({ tenantId: parameters.tenantId, subject: parameters.subject }, parameters.currentSecret, parameters.newSecret, await getAuditor());
|
|
111
111
|
return 'ok';
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
@@ -116,7 +116,7 @@ let AuthenticationApiController = class AuthenticationApiController {
|
|
|
116
116
|
* @returns 'ok' if the secret reset was initialized.
|
|
117
117
|
*/
|
|
118
118
|
async initSecretReset({ parameters, getAuditor }) {
|
|
119
|
-
await this.authenticationService.initSecretReset(parameters.subject, parameters.data, await getAuditor());
|
|
119
|
+
await this.authenticationService.initSecretReset({ tenantId: parameters.tenantId, subject: parameters.subject }, parameters.data, await getAuditor());
|
|
120
120
|
return 'ok';
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { SubjectInput } from '../types.js';
|
|
1
2
|
export type AuthenticationAuditEvents = {
|
|
2
3
|
'login-success': {
|
|
3
4
|
sessionId: string;
|
|
4
5
|
};
|
|
5
6
|
'login-failure': {
|
|
6
|
-
|
|
7
|
+
subjectInput: SubjectInput;
|
|
8
|
+
subjectId: string | null;
|
|
7
9
|
};
|
|
8
10
|
'logout': {
|
|
9
11
|
sessionId: string;
|
|
@@ -15,16 +17,16 @@ export type AuthenticationAuditEvents = {
|
|
|
15
17
|
reason: string;
|
|
16
18
|
};
|
|
17
19
|
'impersonate-success': {
|
|
18
|
-
|
|
20
|
+
impersonatedSubjectId: string;
|
|
19
21
|
};
|
|
20
22
|
'impersonate-failure': {
|
|
21
|
-
|
|
22
|
-
reason: string;
|
|
23
|
+
impersonatedSubjectId: string;
|
|
23
24
|
};
|
|
24
25
|
'unimpersonate-success': {};
|
|
25
26
|
'change-secret-success': {};
|
|
26
27
|
'change-secret-failure': {
|
|
27
|
-
|
|
28
|
+
subjectInput: SubjectInput;
|
|
29
|
+
subjectId: string | null;
|
|
28
30
|
};
|
|
29
31
|
'init-secret-reset': {};
|
|
30
32
|
'reset-secret-success': {};
|