@tsed/oidc-provider 8.11.1 → 8.12.0-rc.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/lib/esm/OidcModule.js +0 -1
- package/lib/esm/constants/constants.js +0 -1
- package/lib/esm/decorators/grantId.js +0 -1
- package/lib/esm/decorators/interaction.js +0 -1
- package/lib/esm/decorators/interactions.js +0 -1
- package/lib/esm/decorators/noCache.js +0 -1
- package/lib/esm/decorators/oidcCtx.js +0 -1
- package/lib/esm/decorators/oidcSession.js +0 -1
- package/lib/esm/decorators/params.js +0 -1
- package/lib/esm/decorators/prompt.js +0 -1
- package/lib/esm/decorators/uid.js +0 -1
- package/lib/esm/domain/InteractionMethods.js +0 -1
- package/lib/esm/domain/OidcAccountsMethods.js +0 -1
- package/lib/esm/domain/OidcBadInteractionName.js +0 -1
- package/lib/esm/domain/OidcInteractionMethods.js +0 -1
- package/lib/esm/domain/OidcInteractionOptions.js +0 -1
- package/lib/esm/domain/OidcInteractionPromptProps.js +0 -1
- package/lib/esm/domain/OidcSettings.js +0 -1
- package/lib/esm/domain/interfaces.js +0 -1
- package/lib/esm/index.js +0 -1
- package/lib/esm/middlewares/OidcInteractionMiddleware.js +0 -1
- package/lib/esm/middlewares/OidcNoCacheMiddleware.js +0 -1
- package/lib/esm/middlewares/OidcSecureMiddleware.js +0 -1
- package/lib/esm/services/OidcAdapters.js +0 -1
- package/lib/esm/services/OidcInteractionContext.js +0 -1
- package/lib/esm/services/OidcInteractions.js +0 -1
- package/lib/esm/services/OidcJwks.js +0 -1
- package/lib/esm/services/OidcPolicy.js +0 -1
- package/lib/esm/services/OidcProvider.js +0 -1
- package/lib/esm/utils/debug.js +0 -1
- package/lib/esm/utils/events.js +0 -1
- package/package.json +13 -10
- package/lib/esm/OidcModule.js.map +0 -1
- package/lib/esm/constants/constants.js.map +0 -1
- package/lib/esm/decorators/grantId.js.map +0 -1
- package/lib/esm/decorators/interaction.js.map +0 -1
- package/lib/esm/decorators/interactions.js.map +0 -1
- package/lib/esm/decorators/noCache.js.map +0 -1
- package/lib/esm/decorators/oidcCtx.js.map +0 -1
- package/lib/esm/decorators/oidcSession.js.map +0 -1
- package/lib/esm/decorators/params.js.map +0 -1
- package/lib/esm/decorators/prompt.js.map +0 -1
- package/lib/esm/decorators/uid.js.map +0 -1
- package/lib/esm/domain/InteractionMethods.js.map +0 -1
- package/lib/esm/domain/OidcAccountsMethods.js.map +0 -1
- package/lib/esm/domain/OidcBadInteractionName.js.map +0 -1
- package/lib/esm/domain/OidcInteractionMethods.js.map +0 -1
- package/lib/esm/domain/OidcInteractionOptions.js.map +0 -1
- package/lib/esm/domain/OidcInteractionPromptProps.js.map +0 -1
- package/lib/esm/domain/OidcSettings.js.map +0 -1
- package/lib/esm/domain/interfaces.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/middlewares/OidcInteractionMiddleware.js.map +0 -1
- package/lib/esm/middlewares/OidcNoCacheMiddleware.js.map +0 -1
- package/lib/esm/middlewares/OidcSecureMiddleware.js.map +0 -1
- package/lib/esm/services/OidcAdapters.js.map +0 -1
- package/lib/esm/services/OidcInteractionContext.js.map +0 -1
- package/lib/esm/services/OidcInteractions.js.map +0 -1
- package/lib/esm/services/OidcJwks.js.map +0 -1
- package/lib/esm/services/OidcPolicy.js.map +0 -1
- package/lib/esm/services/OidcProvider.js.map +0 -1
- package/lib/esm/utils/debug.js.map +0 -1
- package/lib/esm/utils/events.js.map +0 -1
- package/src/OidcModule.spec.ts +0 -116
- package/src/OidcModule.ts +0 -70
- package/src/constants/constants.ts +0 -10
- package/src/decorators/grantId.spec.ts +0 -17
- package/src/decorators/grantId.ts +0 -10
- package/src/decorators/interaction.spec.ts +0 -27
- package/src/decorators/interaction.ts +0 -18
- package/src/decorators/interactions.spec.ts +0 -23
- package/src/decorators/interactions.ts +0 -21
- package/src/decorators/noCache.ts +0 -7
- package/src/decorators/oidcCtx.spec.ts +0 -17
- package/src/decorators/oidcCtx.ts +0 -11
- package/src/decorators/oidcSession.spec.ts +0 -17
- package/src/decorators/oidcSession.ts +0 -14
- package/src/decorators/params.spec.ts +0 -17
- package/src/decorators/params.ts +0 -10
- package/src/decorators/prompt.spec.ts +0 -17
- package/src/decorators/prompt.ts +0 -11
- package/src/decorators/uid.spec.ts +0 -17
- package/src/decorators/uid.ts +0 -10
- package/src/domain/InteractionMethods.ts +0 -11
- package/src/domain/OidcAccountsMethods.ts +0 -10
- package/src/domain/OidcBadInteractionName.ts +0 -3
- package/src/domain/OidcInteractionMethods.ts +0 -3
- package/src/domain/OidcInteractionOptions.ts +0 -8
- package/src/domain/OidcInteractionPromptProps.ts +0 -11
- package/src/domain/OidcSettings.ts +0 -72
- package/src/domain/interfaces.ts +0 -13
- package/src/index.ts +0 -33
- package/src/middlewares/OidcInteractionMiddleware.spec.ts +0 -40
- package/src/middlewares/OidcInteractionMiddleware.ts +0 -14
- package/src/middlewares/OidcNoCacheMiddleware.spec.ts +0 -18
- package/src/middlewares/OidcNoCacheMiddleware.ts +0 -10
- package/src/middlewares/OidcSecureMiddleware.spec.ts +0 -106
- package/src/middlewares/OidcSecureMiddleware.ts +0 -30
- package/src/services/OidcAdapters.spec.ts +0 -100
- package/src/services/OidcAdapters.ts +0 -92
- package/src/services/OidcInteractionContext.spec.ts +0 -304
- package/src/services/OidcInteractionContext.ts +0 -206
- package/src/services/OidcInteractions.ts +0 -57
- package/src/services/OidcJwks.ts +0 -22
- package/src/services/OidcPolicy.spec.ts +0 -156
- package/src/services/OidcPolicy.ts +0 -92
- package/src/services/OidcProvider.spec.ts +0 -116
- package/src/services/OidcProvider.ts +0 -198
- package/src/utils/debug.spec.ts +0 -12
- package/src/utils/debug.ts +0 -26
- package/src/utils/events.ts +0 -61
- package/vitest.config.mts +0 -21
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import {Env} from "@tsed/core";
|
|
2
|
-
import {constant, context, inject, Injectable} from "@tsed/di";
|
|
3
|
-
import {Unauthorized} from "@tsed/exceptions";
|
|
4
|
-
import {PlatformContext} from "@tsed/platform-http";
|
|
5
|
-
import omit from "lodash/omit.js";
|
|
6
|
-
import type {Account, default as Provider, InteractionResults, PromptDetail} from "oidc-provider";
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
INTERACTION_CONTEXT,
|
|
10
|
-
INTERACTION_DETAILS,
|
|
11
|
-
INTERACTION_GRANT_ID,
|
|
12
|
-
INTERACTION_PARAMS,
|
|
13
|
-
INTERACTION_PROMPT,
|
|
14
|
-
INTERACTION_SESSION,
|
|
15
|
-
INTERACTION_UID
|
|
16
|
-
} from "../constants/constants.js";
|
|
17
|
-
import {OidcSession} from "../decorators/oidcSession.js";
|
|
18
|
-
import {OidcClient, OidcInteraction} from "../domain/interfaces.js";
|
|
19
|
-
import {OidcBadInteractionName} from "../domain/OidcBadInteractionName.js";
|
|
20
|
-
import {OidcInteractionPromptProps} from "../domain/OidcInteractionPromptProps.js";
|
|
21
|
-
import {debug} from "../utils/debug.js";
|
|
22
|
-
import {OidcInteractions} from "./OidcInteractions.js";
|
|
23
|
-
import {OidcProvider} from "./OidcProvider.js";
|
|
24
|
-
|
|
25
|
-
@Injectable()
|
|
26
|
-
export class OidcInteractionContext {
|
|
27
|
-
protected env = constant<Env>("env");
|
|
28
|
-
protected oidcProvider = inject(OidcProvider);
|
|
29
|
-
protected oidcInteractions = inject(OidcInteractions);
|
|
30
|
-
|
|
31
|
-
get $ctx() {
|
|
32
|
-
return context<PlatformContext>();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get raw(): OidcInteraction {
|
|
36
|
-
return this.$ctx.get(INTERACTION_DETAILS)!;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get session(): OidcSession | undefined {
|
|
40
|
-
return this.raw.session as any;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get prompt(): PromptDetail {
|
|
44
|
-
return this.raw.prompt;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
get params(): Record<string, any> {
|
|
48
|
-
return this.raw.params;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
get uid(): string {
|
|
52
|
-
return this.raw.uid;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
get grantId(): string {
|
|
56
|
-
return (this.raw as any).grantId;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async runInteraction(name?: string) {
|
|
60
|
-
name = name || this.prompt.name;
|
|
61
|
-
|
|
62
|
-
const handler = this.oidcInteractions.getInteractionHandler(name);
|
|
63
|
-
|
|
64
|
-
if (handler) {
|
|
65
|
-
this.raw.prompt = {
|
|
66
|
-
...this.raw.prompt,
|
|
67
|
-
name,
|
|
68
|
-
reasons: [name]
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
await handler(this.$ctx);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async interactionDetails(): Promise<OidcInteraction> {
|
|
76
|
-
const raw = await this.oidcProvider.get().interactionDetails(this.$ctx.getReq(), this.$ctx.getRes());
|
|
77
|
-
const {uid, prompt, params, session, grantId} = raw as any;
|
|
78
|
-
|
|
79
|
-
this.$ctx.set(INTERACTION_CONTEXT, this);
|
|
80
|
-
this.$ctx.set(INTERACTION_DETAILS, raw);
|
|
81
|
-
this.$ctx.set(INTERACTION_UID, uid);
|
|
82
|
-
this.$ctx.set(INTERACTION_PROMPT, prompt);
|
|
83
|
-
this.$ctx.set(INTERACTION_PARAMS, params);
|
|
84
|
-
this.$ctx.set(INTERACTION_GRANT_ID, grantId);
|
|
85
|
-
this.$ctx.set(INTERACTION_SESSION, session);
|
|
86
|
-
|
|
87
|
-
return raw;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
interactionFinished(
|
|
91
|
-
result: InteractionResults,
|
|
92
|
-
options: {
|
|
93
|
-
mergeWithLastSubmission?: boolean;
|
|
94
|
-
} = {mergeWithLastSubmission: false}
|
|
95
|
-
) {
|
|
96
|
-
return this.oidcProvider.get().interactionFinished(this.$ctx.getReq(), this.$ctx.getRes(), result, options);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
interactionResult(
|
|
100
|
-
result: InteractionResults,
|
|
101
|
-
options: {
|
|
102
|
-
mergeWithLastSubmission?: boolean;
|
|
103
|
-
} = {mergeWithLastSubmission: false}
|
|
104
|
-
) {
|
|
105
|
-
return this.oidcProvider.get().interactionResult(this.$ctx.getReq(), this.$ctx.getRes(), result, options);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async interactionPrompt({client, ...options}: Record<string, any>): Promise<OidcInteractionPromptProps> {
|
|
109
|
-
client = client || (await this.findClient());
|
|
110
|
-
|
|
111
|
-
const omitClientProps = constant("oidc.render.omitClientProps", []);
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
client: omit(client, ["clientSecret", ...omitClientProps]),
|
|
115
|
-
uid: this.uid,
|
|
116
|
-
grantId: this.grantId,
|
|
117
|
-
details: this.prompt.details,
|
|
118
|
-
params: {
|
|
119
|
-
...this.params,
|
|
120
|
-
...options.params
|
|
121
|
-
},
|
|
122
|
-
...options,
|
|
123
|
-
...this.debug()
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
render(view: string, result: any): Promise<string> {
|
|
128
|
-
return this.$ctx.response.render(view, result);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
save(ttl: number): Promise<string> {
|
|
132
|
-
return this.raw.save(ttl);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
findClient(clientId: string = this.params.client_id): Promise<OidcClient | undefined> {
|
|
136
|
-
const key = `$client:${clientId}`;
|
|
137
|
-
|
|
138
|
-
return this.$ctx.cacheAsync(key, () => this.oidcProvider.get().Client.find(clientId));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
findAccount(sub?: string, token?: any): Promise<Account | undefined> {
|
|
142
|
-
if (!sub && this.session) {
|
|
143
|
-
sub = this.session?.accountId as any;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (!sub) {
|
|
147
|
-
return Promise.resolve(undefined);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const key = `$account:${sub}`;
|
|
151
|
-
|
|
152
|
-
return this.$ctx.cacheAsync<Account | undefined>(key, (() => {
|
|
153
|
-
return this.oidcProvider.get().Account.findAccount(undefined as any, sub!, token);
|
|
154
|
-
}) as any);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
getGrant(): Promise<InstanceType<Provider["Grant"]>> {
|
|
158
|
-
const {Grant} = this.oidcProvider.get() as any;
|
|
159
|
-
|
|
160
|
-
if (this.grantId) {
|
|
161
|
-
// we'll be modifying existing grant in existing session
|
|
162
|
-
// @ts-ignore
|
|
163
|
-
return Grant.find(this.grantId);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return Promise.resolve(
|
|
167
|
-
new Grant({
|
|
168
|
-
accountId: this.session?.accountId,
|
|
169
|
-
clientId: this.params.client_id
|
|
170
|
-
})
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
checkInteractionName(name: string) {
|
|
175
|
-
if (this.prompt.name !== name) {
|
|
176
|
-
throw new OidcBadInteractionName("Bad interaction name");
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async checkClientId(clientId = this.params.client_id) {
|
|
181
|
-
const client = await this.findClient(clientId);
|
|
182
|
-
|
|
183
|
-
if (!client) {
|
|
184
|
-
throw new Unauthorized(`Unknown client_id ${clientId}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
debug(obj?: any): any {
|
|
189
|
-
/* istanbul ignore next */
|
|
190
|
-
if (this.env === Env.PROD) {
|
|
191
|
-
return {session: undefined, dbg: {params: undefined, prompt: undefined}};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (obj) {
|
|
195
|
-
return debug(obj);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
session: this.session ? this.debug(this.session) : undefined,
|
|
200
|
-
dbg: {
|
|
201
|
-
params: this.debug(this.params),
|
|
202
|
-
prompt: this.debug(this.prompt)
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import {Env} from "@tsed/core";
|
|
2
|
-
import {constant, Injectable, injector, Provider, TokenProvider} from "@tsed/di";
|
|
3
|
-
import {PlatformContext, PlatformHandler} from "@tsed/platform-http";
|
|
4
|
-
import {EndpointMetadata} from "@tsed/schema";
|
|
5
|
-
|
|
6
|
-
import {INTERACTION, INTERACTION_OPTIONS, INTERACTIONS} from "../constants/constants.js";
|
|
7
|
-
import {OidcInteractionOptions} from "../domain/OidcInteractionOptions.js";
|
|
8
|
-
|
|
9
|
-
@Injectable()
|
|
10
|
-
export class OidcInteractions {
|
|
11
|
-
protected injector = injector();
|
|
12
|
-
protected env = constant<Env>("env");
|
|
13
|
-
protected interactions: Map<string, Provider> = new Map();
|
|
14
|
-
|
|
15
|
-
$onInit(): void {
|
|
16
|
-
const platformHandler = this.injector.get<PlatformHandler>(PlatformHandler)!;
|
|
17
|
-
|
|
18
|
-
this.getInteractions().forEach((provider: Provider) => {
|
|
19
|
-
const {name} = provider.store.get<OidcInteractionOptions>(INTERACTION_OPTIONS);
|
|
20
|
-
this.interactions.set(name, provider);
|
|
21
|
-
|
|
22
|
-
if (this.injector.get(provider.token)?.$prompt) {
|
|
23
|
-
provider.store.set("$prompt", platformHandler.createCustomHandler(provider, "$prompt"));
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
getInteractions(): Provider[] {
|
|
29
|
-
const interactionsProvider = this.injector.getProviders().find((provider) => provider.subType === INTERACTIONS);
|
|
30
|
-
|
|
31
|
-
/* istanbul ignore next */
|
|
32
|
-
if (!interactionsProvider) {
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return interactionsProvider.children
|
|
37
|
-
.map((token: TokenProvider) => this.injector.getProvider(token)!)
|
|
38
|
-
.filter((provider: Provider) => provider?.subType === INTERACTION);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
getInteractionProvider(name: string): Provider | undefined {
|
|
42
|
-
return this.interactions.get(name);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
getInteractionHandler(name: string) {
|
|
46
|
-
const interaction = this.getInteractionProvider(name);
|
|
47
|
-
|
|
48
|
-
if (interaction) {
|
|
49
|
-
const endpoint = EndpointMetadata.get(interaction.useClass, "$prompt");
|
|
50
|
-
return (ctx: PlatformContext) => {
|
|
51
|
-
// Add current endpoint metadata to ctx
|
|
52
|
-
ctx.endpoint = endpoint;
|
|
53
|
-
return interaction.store.get("$prompt")(ctx);
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
package/src/services/OidcJwks.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import {join} from "node:path";
|
|
2
|
-
|
|
3
|
-
import {constant, Injectable} from "@tsed/di";
|
|
4
|
-
import {getJwks, JwksKeyParameters} from "@tsed/jwks";
|
|
5
|
-
|
|
6
|
-
@Injectable()
|
|
7
|
-
export class OidcJwks {
|
|
8
|
-
public jwksPath: string = constant("oidc.jwksPath", join(process.cwd(), "keys", "jwks.json"));
|
|
9
|
-
public certificates?: JwksKeyParameters[] = constant("oidc.certificates");
|
|
10
|
-
public keys: string;
|
|
11
|
-
|
|
12
|
-
$onInit() {
|
|
13
|
-
return this.getJwks();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
getJwks() {
|
|
17
|
-
return getJwks({
|
|
18
|
-
path: this.jwksPath,
|
|
19
|
-
certificates: this.certificates
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import {Env} from "@tsed/core";
|
|
2
|
-
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
3
|
-
|
|
4
|
-
import {ConsentInteraction} from "../../test/app/interactions/ConsentInteraction.js";
|
|
5
|
-
import {Interaction} from "../decorators/interaction.js";
|
|
6
|
-
import {OidcInteractions} from "./OidcInteractions.js";
|
|
7
|
-
import {OidcPolicy} from "./OidcPolicy.js";
|
|
8
|
-
|
|
9
|
-
describe("OidcPolicy", () => {
|
|
10
|
-
beforeEach(() =>
|
|
11
|
-
PlatformTest.create({
|
|
12
|
-
env: Env.PROD,
|
|
13
|
-
oidc: {
|
|
14
|
-
issuer: "http://localhost:8081",
|
|
15
|
-
secureKey: ["secureKey"]
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
);
|
|
19
|
-
afterEach(() => PlatformTest.reset());
|
|
20
|
-
describe("createPrompt()", () => {
|
|
21
|
-
it("should bind options to prompt instance", async () => {
|
|
22
|
-
const oidcProvider = PlatformTest.get<OidcPolicy>(OidcPolicy);
|
|
23
|
-
const instance = {};
|
|
24
|
-
const options = {
|
|
25
|
-
name: "name",
|
|
26
|
-
requestable: true,
|
|
27
|
-
details: vi.fn(),
|
|
28
|
-
checks: []
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const prompt = await oidcProvider.createPrompt(instance, options);
|
|
32
|
-
|
|
33
|
-
expect(prompt.details).toEqual(options.details);
|
|
34
|
-
expect(prompt.name).toEqual(options.name);
|
|
35
|
-
expect(prompt.requestable).toEqual(options.requestable);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("should bind methods from instance to prompt instance", async () => {
|
|
39
|
-
const oidcProvider = PlatformTest.get<OidcPolicy>(OidcPolicy);
|
|
40
|
-
const instance = {
|
|
41
|
-
details: vi.fn(),
|
|
42
|
-
checks: vi.fn().mockReturnValue([])
|
|
43
|
-
};
|
|
44
|
-
const options = {
|
|
45
|
-
name: "name",
|
|
46
|
-
requestable: true
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const prompt = await oidcProvider.createPrompt(instance, options);
|
|
50
|
-
|
|
51
|
-
expect(prompt.details).toBeDefined();
|
|
52
|
-
expect(prompt.name).toEqual(options.name);
|
|
53
|
-
expect(prompt.requestable).toEqual(options.requestable);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
describe("getPolicy()", () => {
|
|
57
|
-
describe('when there is interactions with "priority" property', () => {
|
|
58
|
-
@Interaction({
|
|
59
|
-
name: "test"
|
|
60
|
-
})
|
|
61
|
-
class TestInteraction {}
|
|
62
|
-
|
|
63
|
-
@Interaction({
|
|
64
|
-
name: "test2"
|
|
65
|
-
})
|
|
66
|
-
class Test2Interaction {}
|
|
67
|
-
|
|
68
|
-
@Interaction({
|
|
69
|
-
name: "login"
|
|
70
|
-
})
|
|
71
|
-
class LoginInteraction {}
|
|
72
|
-
|
|
73
|
-
@Interaction({
|
|
74
|
-
name: "consent"
|
|
75
|
-
})
|
|
76
|
-
class ConsentInteraction {}
|
|
77
|
-
|
|
78
|
-
@Interaction({
|
|
79
|
-
name: "test3",
|
|
80
|
-
priority: 0
|
|
81
|
-
})
|
|
82
|
-
class Test3Interaction {}
|
|
83
|
-
|
|
84
|
-
it("should load policy (without priority)", async () => {
|
|
85
|
-
const oidcInteractions = {
|
|
86
|
-
getInteractions: vi
|
|
87
|
-
.fn()
|
|
88
|
-
.mockReturnValue([
|
|
89
|
-
PlatformTest.injector.getProvider(Test2Interaction),
|
|
90
|
-
PlatformTest.injector.getProvider(LoginInteraction),
|
|
91
|
-
PlatformTest.injector.getProvider(ConsentInteraction),
|
|
92
|
-
PlatformTest.injector.getProvider(TestInteraction)
|
|
93
|
-
])
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const oidcProvider = await PlatformTest.invoke<OidcPolicy>(OidcPolicy, [
|
|
97
|
-
{
|
|
98
|
-
token: OidcInteractions,
|
|
99
|
-
use: oidcInteractions
|
|
100
|
-
}
|
|
101
|
-
]);
|
|
102
|
-
|
|
103
|
-
const policy = oidcProvider.getPolicy();
|
|
104
|
-
|
|
105
|
-
expect(policy.map(({name}: {name: string}) => name)).toEqual(["test2", "login", "consent", "test"]);
|
|
106
|
-
});
|
|
107
|
-
it("should load policy (with priority)", async () => {
|
|
108
|
-
const oidcInteractions = {
|
|
109
|
-
getInteractions: vi
|
|
110
|
-
.fn()
|
|
111
|
-
.mockReturnValue([
|
|
112
|
-
PlatformTest.injector.getProvider(Test2Interaction),
|
|
113
|
-
PlatformTest.injector.getProvider(LoginInteraction),
|
|
114
|
-
PlatformTest.injector.getProvider(ConsentInteraction),
|
|
115
|
-
PlatformTest.injector.getProvider(TestInteraction),
|
|
116
|
-
PlatformTest.injector.getProvider(Test3Interaction)
|
|
117
|
-
])
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const oidcProvider = await PlatformTest.invoke<OidcPolicy>(OidcPolicy, [
|
|
121
|
-
{
|
|
122
|
-
token: OidcInteractions,
|
|
123
|
-
use: oidcInteractions
|
|
124
|
-
}
|
|
125
|
-
]);
|
|
126
|
-
|
|
127
|
-
const policy = oidcProvider.getPolicy();
|
|
128
|
-
|
|
129
|
-
expect(policy.map(({name}: {name: string}) => name)).toEqual(["test3", "login", "consent", "test2", "test"]);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
describe("when there is no interactions without usePriority", () => {
|
|
133
|
-
it("should load policy", async () => {
|
|
134
|
-
const oidcInteractions = {
|
|
135
|
-
getInteractions: vi.fn().mockReturnValue([])
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const oidcPolicy = await PlatformTest.invoke<OidcPolicy>(OidcPolicy, [
|
|
139
|
-
{
|
|
140
|
-
token: OidcInteractions,
|
|
141
|
-
use: oidcInteractions
|
|
142
|
-
}
|
|
143
|
-
]);
|
|
144
|
-
|
|
145
|
-
vi.spyOn(oidcPolicy as any, "getInteractions").mockReturnValue({
|
|
146
|
-
usePriority: false,
|
|
147
|
-
interactions: new Map([["login", {name: "login", instance: {}} as any]])
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
const policy = oidcPolicy.getPolicy();
|
|
151
|
-
|
|
152
|
-
expect(policy.map(({name}: {name: string}) => name)).toEqual(["login", "consent"]);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import {inject, Injectable, injector, Provider} from "@tsed/di";
|
|
2
|
-
import {interactionPolicy} from "oidc-provider";
|
|
3
|
-
|
|
4
|
-
import {InteractionMethods} from "../domain/InteractionMethods.js";
|
|
5
|
-
import {OidcInteractionOptions} from "../domain/OidcInteractionOptions.js";
|
|
6
|
-
import {OidcInteractions} from "./OidcInteractions.js";
|
|
7
|
-
import Prompt = interactionPolicy.Prompt;
|
|
8
|
-
|
|
9
|
-
@Injectable()
|
|
10
|
-
export class OidcPolicy {
|
|
11
|
-
protected injector = injector();
|
|
12
|
-
protected oidcInteractions = inject(OidcInteractions);
|
|
13
|
-
|
|
14
|
-
public getPolicy() {
|
|
15
|
-
let policy = interactionPolicy.base();
|
|
16
|
-
const {usePriority, interactions} = this.getInteractions();
|
|
17
|
-
|
|
18
|
-
if (interactions.size) {
|
|
19
|
-
for (const {name, instance, options} of interactions.values()) {
|
|
20
|
-
if (!policy.get(name)) {
|
|
21
|
-
const prompt = this.createPrompt(instance, options);
|
|
22
|
-
|
|
23
|
-
policy.add(prompt, options.priority);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (instance.$onCreate) {
|
|
27
|
-
instance.$onCreate(policy.get(name)!);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// reordering interactions by interactions index
|
|
32
|
-
if (!usePriority) {
|
|
33
|
-
policy = policy.sort((a, b) => {
|
|
34
|
-
const o1 = interactions.get(a.name)?.order || 0;
|
|
35
|
-
const o2 = interactions.get(b.name)?.order || 0;
|
|
36
|
-
|
|
37
|
-
return o1 < o2 ? -1 : 1;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return this.injector.alter("$alterOidcPolicy", policy);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public createPrompt(instance: InteractionMethods, options: OidcInteractionOptions): Prompt {
|
|
46
|
-
const {checks: originalChecks = [], details, ...promptOptions} = options;
|
|
47
|
-
const checks = [...(instance.checks ? instance.checks() : originalChecks)].filter(Boolean);
|
|
48
|
-
|
|
49
|
-
return new interactionPolicy.Prompt(promptOptions, instance.details ? instance.details.bind(instance) : details, ...checks);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private getInteractions() {
|
|
53
|
-
let usePriority = false;
|
|
54
|
-
|
|
55
|
-
const interactions = this.oidcInteractions.getInteractions();
|
|
56
|
-
|
|
57
|
-
const map = interactions.reduce(
|
|
58
|
-
(map, provider, index) => {
|
|
59
|
-
const instance = this.injector.get<InteractionMethods>(provider.token)!;
|
|
60
|
-
|
|
61
|
-
const options = provider.store.get("interactionOptions");
|
|
62
|
-
|
|
63
|
-
if (options.priority !== undefined) {
|
|
64
|
-
usePriority = true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return map.set(options.name, {
|
|
68
|
-
order: index,
|
|
69
|
-
name: options.name,
|
|
70
|
-
provider,
|
|
71
|
-
instance,
|
|
72
|
-
options
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
new Map<
|
|
76
|
-
string,
|
|
77
|
-
{
|
|
78
|
-
order: number;
|
|
79
|
-
provider: Provider;
|
|
80
|
-
instance: any;
|
|
81
|
-
options: OidcInteractionOptions;
|
|
82
|
-
name: string;
|
|
83
|
-
}
|
|
84
|
-
>()
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
interactions: map,
|
|
89
|
-
usePriority
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import "../../test/app/controllers/oidc/InteractionsCtrl.js";
|
|
2
|
-
|
|
3
|
-
import {Env} from "@tsed/core";
|
|
4
|
-
import {runInContext} from "@tsed/di";
|
|
5
|
-
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
6
|
-
|
|
7
|
-
import {OidcProvider} from "./OidcProvider.js";
|
|
8
|
-
|
|
9
|
-
describe("OidcProvider", () => {
|
|
10
|
-
describe("Production", () => {
|
|
11
|
-
beforeEach(() =>
|
|
12
|
-
PlatformTest.create({
|
|
13
|
-
env: Env.PROD,
|
|
14
|
-
oidc: {
|
|
15
|
-
issuer: "http://localhost:8081",
|
|
16
|
-
secureKey: ["secureKey"]
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
);
|
|
20
|
-
afterEach(() => PlatformTest.reset());
|
|
21
|
-
|
|
22
|
-
it("should create oidc instance", () => {
|
|
23
|
-
const oidcProvider = PlatformTest.get<OidcProvider>(OidcProvider);
|
|
24
|
-
|
|
25
|
-
// @ts-ignore
|
|
26
|
-
expect(oidcProvider.getInteractionsUrl()({}, {uid: "uid"})).toEqual("/interaction/uid");
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
describe("createErrorHandler()", () => {
|
|
30
|
-
beforeEach(() =>
|
|
31
|
-
PlatformTest.create({
|
|
32
|
-
env: Env.PROD,
|
|
33
|
-
oidc: {
|
|
34
|
-
issuer: "http://localhost:8081",
|
|
35
|
-
secureKey: ["secureKey"]
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
);
|
|
39
|
-
afterEach(() => PlatformTest.reset());
|
|
40
|
-
|
|
41
|
-
it("should intercept all oidc errors", () => {
|
|
42
|
-
const oidcProvider = PlatformTest.get<OidcProvider>(OidcProvider);
|
|
43
|
-
vi.spyOn((oidcProvider as any).injector.logger, "error");
|
|
44
|
-
|
|
45
|
-
const fn = (oidcProvider as any).createErrorHandler("event");
|
|
46
|
-
fn(
|
|
47
|
-
{
|
|
48
|
-
headers: {
|
|
49
|
-
origin: "origin"
|
|
50
|
-
},
|
|
51
|
-
oidc: {
|
|
52
|
-
params: {
|
|
53
|
-
client_id: "client_id"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
{error: "error", error_description: "error_description", error_detail: "error_detail"},
|
|
58
|
-
"account_id",
|
|
59
|
-
"sid"
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
expect((oidcProvider as any).injector.logger.error).toHaveBeenCalledWith({
|
|
63
|
-
duration: expect.any(Number),
|
|
64
|
-
reqId: expect.any(String),
|
|
65
|
-
account_id: "account_id",
|
|
66
|
-
error: {error_description: "error_description", error_detail: "error_detail", error: "error"},
|
|
67
|
-
event: "OIDC_ERROR",
|
|
68
|
-
headers: {
|
|
69
|
-
origin: "origin"
|
|
70
|
-
},
|
|
71
|
-
params: {client_id: "client_id"},
|
|
72
|
-
sid: "sid",
|
|
73
|
-
type: "event",
|
|
74
|
-
time: expect.any(Date)
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
it("should intercept all oidc errors (in request context)", async () => {
|
|
78
|
-
const oidcProvider = PlatformTest.get<OidcProvider>(OidcProvider);
|
|
79
|
-
const ctx = PlatformTest.createRequestContext();
|
|
80
|
-
|
|
81
|
-
vi.spyOn(ctx.logger, "error");
|
|
82
|
-
|
|
83
|
-
const fn = (oidcProvider as any).createErrorHandler("event");
|
|
84
|
-
|
|
85
|
-
await runInContext(ctx, () => {
|
|
86
|
-
fn(
|
|
87
|
-
{
|
|
88
|
-
headers: {
|
|
89
|
-
origin: "origin"
|
|
90
|
-
},
|
|
91
|
-
oidc: {
|
|
92
|
-
params: {
|
|
93
|
-
client_id: "client_id"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
{error: "error", error_description: "error_description", error_detail: "error_detail"},
|
|
98
|
-
"account_id",
|
|
99
|
-
"sid"
|
|
100
|
-
);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
expect(ctx.logger.error).toHaveBeenCalledWith({
|
|
104
|
-
account_id: "account_id",
|
|
105
|
-
error: {error_description: "error_description", error_detail: "error_detail", error: "error"},
|
|
106
|
-
event: "OIDC_ERROR",
|
|
107
|
-
headers: {
|
|
108
|
-
origin: "origin"
|
|
109
|
-
},
|
|
110
|
-
params: {client_id: "client_id"},
|
|
111
|
-
sid: "sid",
|
|
112
|
-
type: "event"
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
});
|