@tsed/oidc-provider 8.0.1 → 8.0.3
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/package.json +16 -15
- package/src/OidcModule.spec.ts +116 -0
- package/src/OidcModule.ts +70 -0
- package/src/constants/constants.ts +10 -0
- package/src/decorators/grantId.spec.ts +17 -0
- package/src/decorators/grantId.ts +10 -0
- package/src/decorators/interaction.spec.ts +27 -0
- package/src/decorators/interaction.ts +18 -0
- package/src/decorators/interactions.spec.ts +23 -0
- package/src/decorators/interactions.ts +21 -0
- package/src/decorators/noCache.ts +7 -0
- package/src/decorators/oidcCtx.spec.ts +17 -0
- package/src/decorators/oidcCtx.ts +11 -0
- package/src/decorators/oidcSession.spec.ts +17 -0
- package/src/decorators/oidcSession.ts +14 -0
- package/src/decorators/params.spec.ts +17 -0
- package/src/decorators/params.ts +10 -0
- package/src/decorators/prompt.spec.ts +17 -0
- package/src/decorators/prompt.ts +11 -0
- package/src/decorators/uid.spec.ts +17 -0
- package/src/decorators/uid.ts +10 -0
- package/src/domain/InteractionMethods.ts +11 -0
- package/src/domain/OidcAccountsMethods.ts +10 -0
- package/src/domain/OidcBadInteractionName.ts +3 -0
- package/src/domain/OidcInteractionMethods.ts +3 -0
- package/src/domain/OidcInteractionOptions.ts +8 -0
- package/src/domain/OidcInteractionPromptProps.ts +11 -0
- package/src/domain/OidcSettings.ts +72 -0
- package/src/domain/interfaces.ts +13 -0
- package/src/index.ts +33 -0
- package/src/middlewares/OidcInteractionMiddleware.spec.ts +40 -0
- package/src/middlewares/OidcInteractionMiddleware.ts +14 -0
- package/src/middlewares/OidcNoCacheMiddleware.spec.ts +18 -0
- package/src/middlewares/OidcNoCacheMiddleware.ts +10 -0
- package/src/middlewares/OidcSecureMiddleware.spec.ts +106 -0
- package/src/middlewares/OidcSecureMiddleware.ts +29 -0
- package/src/services/OidcAdapters.spec.ts +100 -0
- package/src/services/OidcAdapters.ts +92 -0
- package/src/services/OidcInteractionContext.spec.ts +304 -0
- package/src/services/OidcInteractionContext.ts +206 -0
- package/src/services/OidcInteractions.ts +57 -0
- package/src/services/OidcJwks.ts +21 -0
- package/src/services/OidcPolicy.spec.ts +156 -0
- package/src/services/OidcPolicy.ts +92 -0
- package/src/services/OidcProvider.spec.ts +116 -0
- package/src/services/OidcProvider.ts +198 -0
- package/src/utils/debug.spec.ts +12 -0
- package/src/utils/debug.ts +25 -0
- package/src/utils/events.ts +61 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type {Adapter} from "@tsed/adapters";
|
|
2
|
+
import type {Type} from "@tsed/core";
|
|
3
|
+
import type {JwksKeyParameters} from "@tsed/jwks";
|
|
4
|
+
import type {Configuration} from "oidc-provider";
|
|
5
|
+
|
|
6
|
+
import type {OidcAccountsMethods} from "./OidcAccountsMethods.js";
|
|
7
|
+
|
|
8
|
+
export interface OidcSettings extends Configuration {
|
|
9
|
+
/**
|
|
10
|
+
* force the secure cookie. By default, in dev mode it's disabled and in production it's enabled.
|
|
11
|
+
*/
|
|
12
|
+
secureCookies?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Path on which the oidc-provider instance is mounted.
|
|
15
|
+
*/
|
|
16
|
+
path?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Issuer URI. By default, Ts.ED create issuer with http://localhost:${httpPort}
|
|
19
|
+
*/
|
|
20
|
+
issuer?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Path to store jwks keys.
|
|
23
|
+
*/
|
|
24
|
+
jwksPath?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Generate jwks from given certificates
|
|
27
|
+
*/
|
|
28
|
+
certificates?: JwksKeyParameters[];
|
|
29
|
+
/**
|
|
30
|
+
* Secure keys.
|
|
31
|
+
*/
|
|
32
|
+
secureKey?: string[];
|
|
33
|
+
/**
|
|
34
|
+
* Enable proxy.
|
|
35
|
+
*/
|
|
36
|
+
proxy?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Allow redirect_uri on HTTP protocol and localhost domain.
|
|
39
|
+
*/
|
|
40
|
+
allowHttpLocalhost?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Injectable service to manage accounts.
|
|
43
|
+
*/
|
|
44
|
+
Accounts?: Type<OidcAccountsMethods>;
|
|
45
|
+
/**
|
|
46
|
+
* Injectable adapter to manage database connexion.
|
|
47
|
+
*/
|
|
48
|
+
Adapter?: Type<Adapter>;
|
|
49
|
+
/**
|
|
50
|
+
* Use the connection name for the OIDCRedisAdapter.
|
|
51
|
+
*/
|
|
52
|
+
connectionName?: string;
|
|
53
|
+
|
|
54
|
+
plugins?: TsED.OIDCPluginSettings;
|
|
55
|
+
|
|
56
|
+
render?: {
|
|
57
|
+
/**
|
|
58
|
+
* By default ["clientSecret"] is omitted
|
|
59
|
+
*/
|
|
60
|
+
omitClientProps?: string[];
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
declare global {
|
|
65
|
+
namespace TsED {
|
|
66
|
+
interface OIDCPluginSettings {}
|
|
67
|
+
|
|
68
|
+
interface Configuration {
|
|
69
|
+
oidc: OidcSettings;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type {default as Provider, interactionPolicy} from "oidc-provider";
|
|
2
|
+
|
|
3
|
+
export type OIDCContext = InstanceType<Provider["OIDCContext"]>;
|
|
4
|
+
export type OidcClient = InstanceType<Provider["Client"]>;
|
|
5
|
+
export type DefaultPolicy = interactionPolicy.DefaultPolicy;
|
|
6
|
+
export type AuthorizationCode = InstanceType<Provider["AuthorizationCode"]>;
|
|
7
|
+
export type AccessToken = InstanceType<Provider["AccessToken"]>;
|
|
8
|
+
export type ClientCredentials = InstanceType<Provider["ClientCredentials"]>;
|
|
9
|
+
export type DeviceCode = InstanceType<Provider["DeviceCode"]>;
|
|
10
|
+
export type RefreshToken = InstanceType<Provider["RefreshToken"]>;
|
|
11
|
+
export type BackchannelAuthenticationRequest = InstanceType<Provider["BackchannelAuthenticationRequest"]>;
|
|
12
|
+
export type Grant = InstanceType<Provider["Grant"]>;
|
|
13
|
+
export type OidcInteraction = InstanceType<Provider["Interaction"]>;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Automatically generated by @tsed/barrels.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./constants/constants.js";
|
|
5
|
+
export * from "./decorators/grantId.js";
|
|
6
|
+
export * from "./decorators/interaction.js";
|
|
7
|
+
export * from "./decorators/interactions.js";
|
|
8
|
+
export * from "./decorators/noCache.js";
|
|
9
|
+
export * from "./decorators/oidcCtx.js";
|
|
10
|
+
export * from "./decorators/oidcSession.js";
|
|
11
|
+
export * from "./decorators/params.js";
|
|
12
|
+
export * from "./decorators/prompt.js";
|
|
13
|
+
export * from "./decorators/uid.js";
|
|
14
|
+
export * from "./domain/InteractionMethods.js";
|
|
15
|
+
export * from "./domain/interfaces.js";
|
|
16
|
+
export * from "./domain/OidcAccountsMethods.js";
|
|
17
|
+
export * from "./domain/OidcBadInteractionName.js";
|
|
18
|
+
export * from "./domain/OidcInteractionMethods.js";
|
|
19
|
+
export * from "./domain/OidcInteractionOptions.js";
|
|
20
|
+
export * from "./domain/OidcInteractionPromptProps.js";
|
|
21
|
+
export * from "./domain/OidcSettings.js";
|
|
22
|
+
export * from "./middlewares/OidcInteractionMiddleware.js";
|
|
23
|
+
export * from "./middlewares/OidcNoCacheMiddleware.js";
|
|
24
|
+
export * from "./middlewares/OidcSecureMiddleware.js";
|
|
25
|
+
export * from "./OidcModule.js";
|
|
26
|
+
export * from "./services/OidcAdapters.js";
|
|
27
|
+
export * from "./services/OidcInteractionContext.js";
|
|
28
|
+
export * from "./services/OidcInteractions.js";
|
|
29
|
+
export * from "./services/OidcJwks.js";
|
|
30
|
+
export * from "./services/OidcPolicy.js";
|
|
31
|
+
export * from "./services/OidcProvider.js";
|
|
32
|
+
export * from "./utils/debug.js";
|
|
33
|
+
export * from "./utils/events.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {faker} from "@faker-js/faker";
|
|
2
|
+
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
INTERACTION_CONTEXT,
|
|
6
|
+
INTERACTION_DETAILS,
|
|
7
|
+
INTERACTION_PARAMS,
|
|
8
|
+
INTERACTION_PROMPT,
|
|
9
|
+
INTERACTION_SESSION,
|
|
10
|
+
INTERACTION_UID
|
|
11
|
+
} from "../constants/constants.js";
|
|
12
|
+
import {OidcInteractionContext} from "../services/OidcInteractionContext.js";
|
|
13
|
+
import {OidcInteractionMiddleware} from "./OidcInteractionMiddleware.js";
|
|
14
|
+
|
|
15
|
+
describe("OidcInteractionMiddleware", () => {
|
|
16
|
+
beforeEach(() => PlatformTest.create());
|
|
17
|
+
afterEach(() => PlatformTest.reset());
|
|
18
|
+
it("should create interaction details and store it to the context", async () => {
|
|
19
|
+
const interactionDetails = {
|
|
20
|
+
uid: faker.string.uuid(),
|
|
21
|
+
prompt: {},
|
|
22
|
+
params: {},
|
|
23
|
+
session: {}
|
|
24
|
+
};
|
|
25
|
+
const oidcInteractionContext = {
|
|
26
|
+
interactionDetails: vi.fn().mockReturnValue(interactionDetails)
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const middleware = await PlatformTest.invoke<OidcInteractionMiddleware>(OidcInteractionMiddleware, [
|
|
30
|
+
{
|
|
31
|
+
token: OidcInteractionContext,
|
|
32
|
+
use: oidcInteractionContext
|
|
33
|
+
}
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
await middleware.use();
|
|
37
|
+
|
|
38
|
+
expect(oidcInteractionContext.interactionDetails).toHaveBeenCalledWith();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {Inject} from "@tsed/di";
|
|
2
|
+
import {Middleware} from "@tsed/platform-middlewares";
|
|
3
|
+
|
|
4
|
+
import {OidcInteractionContext} from "../services/OidcInteractionContext.js";
|
|
5
|
+
|
|
6
|
+
@Middleware()
|
|
7
|
+
export class OidcInteractionMiddleware {
|
|
8
|
+
@Inject()
|
|
9
|
+
protected oidcInteractionContext: OidcInteractionContext;
|
|
10
|
+
|
|
11
|
+
async use() {
|
|
12
|
+
await this.oidcInteractionContext.interactionDetails();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
2
|
+
|
|
3
|
+
import {OidcNoCacheMiddleware} from "./OidcNoCacheMiddleware.js";
|
|
4
|
+
|
|
5
|
+
describe("OidcNoCacheMiddleware", () => {
|
|
6
|
+
beforeEach(() => PlatformTest.create());
|
|
7
|
+
afterEach(() => PlatformTest.reset());
|
|
8
|
+
it("should add headers", () => {
|
|
9
|
+
const middleware = PlatformTest.get<OidcNoCacheMiddleware>(OidcNoCacheMiddleware);
|
|
10
|
+
const ctx = PlatformTest.createRequestContext();
|
|
11
|
+
vi.spyOn(ctx.response, "setHeader").mockReturnThis();
|
|
12
|
+
|
|
13
|
+
middleware.use(ctx);
|
|
14
|
+
|
|
15
|
+
expect(ctx.response.setHeader).toHaveBeenCalledWith("Pragma", "no-cache");
|
|
16
|
+
expect(ctx.response.setHeader).toHaveBeenCalledWith("Cache-Control", "no-cache, no-store");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {Middleware, MiddlewareMethods} from "@tsed/platform-middlewares";
|
|
2
|
+
import {Context} from "@tsed/platform-params";
|
|
3
|
+
|
|
4
|
+
@Middleware()
|
|
5
|
+
export class OidcNoCacheMiddleware implements MiddlewareMethods {
|
|
6
|
+
use(@Context() ctx: Context) {
|
|
7
|
+
ctx.response.setHeader("Pragma", "no-cache");
|
|
8
|
+
ctx.response.setHeader("Cache-Control", "no-cache, no-store");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
2
|
+
|
|
3
|
+
import {OidcSecureMiddleware} from "./OidcSecureMiddleware.js";
|
|
4
|
+
|
|
5
|
+
describe("OidcSecureMiddleware", () => {
|
|
6
|
+
beforeEach(() => PlatformTest.create());
|
|
7
|
+
afterEach(() => PlatformTest.reset());
|
|
8
|
+
|
|
9
|
+
it("should check if the request is not secure on GET verb", async () => {
|
|
10
|
+
const middleware = await PlatformTest.invoke<OidcSecureMiddleware>(OidcSecureMiddleware);
|
|
11
|
+
const request = PlatformTest.createRequest({
|
|
12
|
+
secure: false,
|
|
13
|
+
method: "GET",
|
|
14
|
+
url: "/path",
|
|
15
|
+
headers: {
|
|
16
|
+
host: "host"
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const ctx = PlatformTest.createRequestContext({
|
|
21
|
+
event: {
|
|
22
|
+
request
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
vi.spyOn(ctx.response, "redirect").mockReturnValue(undefined as any);
|
|
26
|
+
|
|
27
|
+
middleware.use(ctx);
|
|
28
|
+
|
|
29
|
+
expect(ctx.response.redirect).toHaveBeenCalledWith(302, "https://host/path");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should check if the request is not secure on HEAD verb", async () => {
|
|
33
|
+
const middleware = await PlatformTest.invoke<OidcSecureMiddleware>(OidcSecureMiddleware);
|
|
34
|
+
const ctx = PlatformTest.createRequestContext({
|
|
35
|
+
event: {
|
|
36
|
+
request: PlatformTest.createRequest({
|
|
37
|
+
secure: false,
|
|
38
|
+
method: "GET",
|
|
39
|
+
url: "/path",
|
|
40
|
+
headers: {
|
|
41
|
+
host: "host"
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
vi.spyOn(ctx.response, "redirect").mockReturnValue(undefined as any);
|
|
48
|
+
|
|
49
|
+
middleware.use(ctx);
|
|
50
|
+
|
|
51
|
+
expect(ctx.response.redirect).toHaveBeenCalledWith(302, "https://host/path");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should check if the request is not secure on POST verb", async () => {
|
|
55
|
+
const middleware = await PlatformTest.invoke<OidcSecureMiddleware>(OidcSecureMiddleware);
|
|
56
|
+
const ctx = PlatformTest.createRequestContext({
|
|
57
|
+
event: {
|
|
58
|
+
request: PlatformTest.createRequest({
|
|
59
|
+
secure: false,
|
|
60
|
+
method: "POST",
|
|
61
|
+
url: "/path",
|
|
62
|
+
headers: {
|
|
63
|
+
host: "host"
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
let actualError: any;
|
|
70
|
+
try {
|
|
71
|
+
middleware.use(ctx);
|
|
72
|
+
} catch (er) {
|
|
73
|
+
actualError = er;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
expect(actualError.status).toEqual(400);
|
|
77
|
+
expect(actualError.message).toEqual("InvalidRequest");
|
|
78
|
+
expect(actualError.body).toEqual({
|
|
79
|
+
error: "invalid_request",
|
|
80
|
+
error_description: "Do yourself a favor and only use https"
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should check if the request is secure on GET verb", async () => {
|
|
85
|
+
const middleware = await PlatformTest.invoke<OidcSecureMiddleware>(OidcSecureMiddleware);
|
|
86
|
+
|
|
87
|
+
const ctx = PlatformTest.createRequestContext({
|
|
88
|
+
event: {
|
|
89
|
+
request: PlatformTest.createRequest({
|
|
90
|
+
secure: true,
|
|
91
|
+
method: "GET",
|
|
92
|
+
url: "/path",
|
|
93
|
+
headers: {
|
|
94
|
+
host: "host"
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
vi.spyOn(ctx.response, "redirect").mockReturnValue(undefined as any);
|
|
101
|
+
|
|
102
|
+
middleware.use(ctx);
|
|
103
|
+
|
|
104
|
+
expect(ctx.response.redirect).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {BadRequest} from "@tsed/exceptions";
|
|
2
|
+
import {Middleware, MiddlewareMethods} from "@tsed/platform-middlewares";
|
|
3
|
+
import {Context} from "@tsed/platform-params";
|
|
4
|
+
import url from "url";
|
|
5
|
+
|
|
6
|
+
@Middleware()
|
|
7
|
+
export class OidcSecureMiddleware implements MiddlewareMethods {
|
|
8
|
+
use(@Context() ctx: Context) {
|
|
9
|
+
const req = ctx.request;
|
|
10
|
+
|
|
11
|
+
if (!req.secure) {
|
|
12
|
+
if (req.method === "GET" || req.method === "HEAD") {
|
|
13
|
+
ctx.response.redirect(
|
|
14
|
+
302,
|
|
15
|
+
url.format({
|
|
16
|
+
protocol: "https",
|
|
17
|
+
host: req.get("host"),
|
|
18
|
+
pathname: req.url
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
} else {
|
|
22
|
+
throw new BadRequest("InvalidRequest", {
|
|
23
|
+
error: "invalid_request",
|
|
24
|
+
error_description: "Do yourself a favor and only use https"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {faker} from "@faker-js/faker";
|
|
2
|
+
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
3
|
+
import type {Adapter} from "oidc-provider";
|
|
4
|
+
|
|
5
|
+
import {OidcAdapters} from "./OidcAdapters.js";
|
|
6
|
+
|
|
7
|
+
describe("OidcAdapters", () => {
|
|
8
|
+
beforeEach(() => PlatformTest.create());
|
|
9
|
+
afterEach(() => PlatformTest.reset());
|
|
10
|
+
|
|
11
|
+
describe("createAdapterClass()", () => {
|
|
12
|
+
let adapter: Adapter;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
const oidcAdapters = await PlatformTest.invoke<OidcAdapters>(OidcAdapters);
|
|
16
|
+
adapter = new (oidcAdapters.createAdapterClass())("clients");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("adapter.upsert()", () => {
|
|
20
|
+
it("should call upsert", async () => {
|
|
21
|
+
const id = faker.string.uuid();
|
|
22
|
+
|
|
23
|
+
await adapter.upsert(
|
|
24
|
+
id,
|
|
25
|
+
{
|
|
26
|
+
client_id: id
|
|
27
|
+
},
|
|
28
|
+
20000
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const obj: any = await adapter.find(id);
|
|
32
|
+
|
|
33
|
+
expect(obj._id).toEqual(id);
|
|
34
|
+
expect(obj.client_id).toEqual(id);
|
|
35
|
+
expect(obj.expires_at).toBeInstanceOf(Date);
|
|
36
|
+
|
|
37
|
+
await adapter.destroy(id);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("adapter.findByUserCode()", () => {
|
|
42
|
+
it("should find data by userCode", async () => {
|
|
43
|
+
const id = faker.string.uuid();
|
|
44
|
+
|
|
45
|
+
await adapter.upsert(
|
|
46
|
+
id,
|
|
47
|
+
{
|
|
48
|
+
userCode: id
|
|
49
|
+
},
|
|
50
|
+
20000
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const obj: any = await adapter.findByUserCode(id);
|
|
54
|
+
|
|
55
|
+
expect(obj._id).toEqual(id);
|
|
56
|
+
expect(obj.userCode).toEqual(id);
|
|
57
|
+
expect(obj.expires_at).toBeInstanceOf(Date);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("adapter.findByUid()", () => {
|
|
61
|
+
it("should find data by uid", async () => {
|
|
62
|
+
const id = faker.string.uuid();
|
|
63
|
+
|
|
64
|
+
await adapter.upsert(
|
|
65
|
+
id,
|
|
66
|
+
{
|
|
67
|
+
uid: id
|
|
68
|
+
},
|
|
69
|
+
20000
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const obj: any = await adapter.findByUid(id);
|
|
73
|
+
|
|
74
|
+
expect(obj._id).toEqual(id);
|
|
75
|
+
expect(obj.uid).toEqual(id);
|
|
76
|
+
expect(obj.expires_at).toBeInstanceOf(Date);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("adapter.deleteMany()", () => {
|
|
80
|
+
it("should delete items", async () => {
|
|
81
|
+
const id = faker.string.uuid();
|
|
82
|
+
|
|
83
|
+
await adapter.upsert(
|
|
84
|
+
id,
|
|
85
|
+
{
|
|
86
|
+
grantId: id
|
|
87
|
+
},
|
|
88
|
+
20000
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
await adapter.consume(id);
|
|
92
|
+
const obj: any = await adapter.find(id);
|
|
93
|
+
await adapter.revokeByGrantId(id);
|
|
94
|
+
|
|
95
|
+
expect(obj._id).toEqual(id);
|
|
96
|
+
expect(obj.grantId).toEqual(id);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {Adapter, Adapters} from "@tsed/adapters";
|
|
2
|
+
import {constant, inject, Injectable} from "@tsed/di";
|
|
3
|
+
import type {Adapter as OidcAdapter, AdapterConstructor} from "oidc-provider";
|
|
4
|
+
|
|
5
|
+
export type OidcAdapterMethods<Model = any> = Adapter<Model> & Partial<Omit<OidcAdapter, "upsert">>;
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class OidcAdapters {
|
|
9
|
+
protected adapters = inject(Adapters);
|
|
10
|
+
|
|
11
|
+
createAdapterClass(): AdapterConstructor {
|
|
12
|
+
const self = this;
|
|
13
|
+
const adapterBase = constant("oidc.Adapter", constant("adapters.Adapter"));
|
|
14
|
+
const connectionName = constant("oidc.connectionName", "default");
|
|
15
|
+
|
|
16
|
+
return class CustomAdapter implements OidcAdapter {
|
|
17
|
+
adapter: OidcAdapterMethods;
|
|
18
|
+
|
|
19
|
+
constructor(name: string) {
|
|
20
|
+
this.adapter = self.adapters.invokeAdapter<any>({
|
|
21
|
+
adapter: adapterBase,
|
|
22
|
+
collectionName: name,
|
|
23
|
+
connectionName,
|
|
24
|
+
model: Object
|
|
25
|
+
}) as OidcAdapterMethods;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async upsert(id: string, payload: any, expiresIn: number): Promise<void> {
|
|
29
|
+
let expiresAt;
|
|
30
|
+
|
|
31
|
+
if (expiresIn) {
|
|
32
|
+
expiresAt = new Date(Date.now() + expiresIn * 1000);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await this.adapter.upsert(id, payload, expiresAt);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
find(id: string) {
|
|
39
|
+
return this.adapter.findById(id);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
findByUserCode(userCode: string) {
|
|
43
|
+
// istanbul ignore next
|
|
44
|
+
if (this.adapter.findByUserCode) {
|
|
45
|
+
return this.adapter.findByUserCode(userCode);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return this.adapter.findOne({
|
|
49
|
+
userCode
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
findByUid(uid: string) {
|
|
54
|
+
// istanbul ignore next
|
|
55
|
+
if (this.adapter.findByUid) {
|
|
56
|
+
return this.adapter.findByUid(uid);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return this.adapter.findOne({
|
|
60
|
+
uid
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async destroy(id: string) {
|
|
65
|
+
// istanbul ignore next
|
|
66
|
+
if (this.adapter.destroy) {
|
|
67
|
+
return this.adapter.destroy(id);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await this.adapter.deleteById(id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async revokeByGrantId(grantId: string) {
|
|
74
|
+
// istanbul ignore next
|
|
75
|
+
if (this.adapter.revokeByGrantId) {
|
|
76
|
+
return this.adapter.revokeByGrantId(grantId);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await this.adapter.deleteMany({grantId});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async consume(grantId: string) {
|
|
83
|
+
// istanbul ignore next
|
|
84
|
+
if (this.adapter.consume) {
|
|
85
|
+
return this.adapter.consume(grantId);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await this.adapter.update(grantId, {consumed: Math.floor(Date.now() / 1000)});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|