@owlmeans/oidc 0.1.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.
- package/LICENSE +21 -0
- package/README.md +525 -0
- package/build/.gitkeep +0 -0
- package/build/consts.d.ts +17 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +17 -0
- package/build/consts.js.map +1 -0
- package/build/guard.d.ts +6 -0
- package/build/guard.d.ts.map +1 -0
- package/build/guard.js +102 -0
- package/build/guard.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/models.d.ts +7 -0
- package/build/models.d.ts.map +1 -0
- package/build/models.js +58 -0
- package/build/models.js.map +1 -0
- package/build/modules.d.ts +2 -0
- package/build/modules.d.ts.map +1 -0
- package/build/modules.js +9 -0
- package/build/modules.js.map +1 -0
- package/build/types.d.ts +88 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +44 -0
- package/src/consts.ts +32 -0
- package/src/guard.ts +130 -0
- package/src/index.ts +5 -0
- package/src/models.ts +63 -0
- package/src/modules.ts +16 -0
- package/src/types.ts +116 -0
- package/tsconfig.json +15 -0
package/build/guard.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createService } from '@owlmeans/context';
|
|
2
|
+
import { OIDC_GUARD, OIDC_WRAPPED_TOKEN, WRAPPED_OIDC } from './consts.js';
|
|
3
|
+
import { DEFAULT_GUARD, TOKEN_UPDATE } from '@owlmeans/auth-common';
|
|
4
|
+
import { AUTH_HEADER, AuthorizationError } from '@owlmeans/auth';
|
|
5
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
|
|
6
|
+
import { trust } from '@owlmeans/auth-common/utils';
|
|
7
|
+
import { TRUSTED } from '@owlmeans/config';
|
|
8
|
+
import { extractAuthToken } from '@owlmeans/auth-common/utils';
|
|
9
|
+
import { modules as oidcModules } from './modules.js';
|
|
10
|
+
export const makeOidcGuard = (opts) => {
|
|
11
|
+
// const cache = (context: Context) => context.hasResource(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
12
|
+
// ? context.resource<Resource<ResourceRecord>>(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
13
|
+
// : null
|
|
14
|
+
const [cogurad] = Array.isArray(opts?.coguards) ? opts.coguards : [opts?.coguards ?? DEFAULT_GUARD];
|
|
15
|
+
const guard = createService(OIDC_GUARD, {
|
|
16
|
+
// Client side
|
|
17
|
+
// get token() {
|
|
18
|
+
// const ctx = guard.assertCtx<Config, Context>()
|
|
19
|
+
// if (!ctx.hasService(cogurad)) {
|
|
20
|
+
// return undefined
|
|
21
|
+
// }
|
|
22
|
+
// // @TODO Make some custom implementation if required.
|
|
23
|
+
// // Cause it won't work on the back. And it's likely that
|
|
24
|
+
// // we will need it soon.
|
|
25
|
+
// const auth = ctx.service<GuardService>(cogurad)
|
|
26
|
+
// return auth.token
|
|
27
|
+
// },
|
|
28
|
+
authenticated: async (req) => {
|
|
29
|
+
const ctx = guard.assertCtx();
|
|
30
|
+
// @TODO Make some custom implementation if required.
|
|
31
|
+
// We try to rely on some centeral auth service that operates all tokens.
|
|
32
|
+
const auth = ctx.service(opts?.tokenService ?? cogurad);
|
|
33
|
+
const token = await auth.authenticated(req);
|
|
34
|
+
if (token != null) {
|
|
35
|
+
const [type] = token.split(' ');
|
|
36
|
+
if (type === OIDC_WRAPPED_TOKEN.toUpperCase()) {
|
|
37
|
+
return token;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
},
|
|
42
|
+
// Server side
|
|
43
|
+
match: async (req) => extractAuthToken(req, OIDC_WRAPPED_TOKEN) != null,
|
|
44
|
+
handle: async (req, res) => {
|
|
45
|
+
const authorization = extractAuthToken(req, OIDC_WRAPPED_TOKEN);
|
|
46
|
+
if (authorization == null) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const ctx = guard.assertCtx();
|
|
50
|
+
const envelope = makeEnvelopeModel(authorization, EnvelopeKind.Token);
|
|
51
|
+
const trusted = await trust(ctx, TRUSTED, ctx.cfg.alias ?? ctx.cfg.service);
|
|
52
|
+
if (!await envelope.verify(trusted.key)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const token = extractAuthToken(req, OIDC_WRAPPED_TOKEN, false);
|
|
56
|
+
let updated = null;
|
|
57
|
+
try {
|
|
58
|
+
updated = await wrapper(ctx).update({ token }, true);
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
if (e instanceof AuthorizationError) {
|
|
62
|
+
res.responseProvider.header(TOKEN_UPDATE, '');
|
|
63
|
+
req.headers = { ...req.headers, [AUTH_HEADER]: '' };
|
|
64
|
+
}
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
if (updated == null) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (updated.token !== token) {
|
|
71
|
+
const [, newAuth] = updated.token.split(' ');
|
|
72
|
+
const envelope = makeEnvelopeModel(newAuth, EnvelopeKind.Token);
|
|
73
|
+
res.responseProvider.header(TOKEN_UPDATE, updated.token);
|
|
74
|
+
req.headers = { ...req.headers, [AUTH_HEADER]: updated.token };
|
|
75
|
+
res.resolve(envelope.message());
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
res.resolve(envelope.message());
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
return guard;
|
|
84
|
+
};
|
|
85
|
+
export const appendOidcGuard = (context, opts) => {
|
|
86
|
+
context.registerService(makeOidcGuard(opts));
|
|
87
|
+
return context;
|
|
88
|
+
};
|
|
89
|
+
export const setupOidcGuard = (modules, coguards) => {
|
|
90
|
+
modules.push(...oidcModules);
|
|
91
|
+
coguards = Array.isArray(coguards) ? coguards : [coguards ?? DEFAULT_GUARD];
|
|
92
|
+
modules.forEach(module => {
|
|
93
|
+
if (module.guards != null && !module.guards.includes(OIDC_GUARD)
|
|
94
|
+
&& module.guards.some(guard => coguards.includes(guard))) {
|
|
95
|
+
module.guards.unshift(OIDC_GUARD);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
const wrapper = (context) => context.hasService(WRAPPED_OIDC)
|
|
100
|
+
? context.service(WRAPPED_OIDC)
|
|
101
|
+
: { update: async (token) => token };
|
|
102
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { JSONSchemaType } from 'ajv';
|
|
2
|
+
import type { OIDCAuthInitParams, OIDCClientAuthPayload, OIDCTokenUpdate, ProviderProfileDetails } from './types.js';
|
|
3
|
+
export declare const OIDCAuthInitParamsSchema: JSONSchemaType<OIDCAuthInitParams>;
|
|
4
|
+
export declare const OIDCClientAuthPayloadSchema: JSONSchemaType<OIDCClientAuthPayload>;
|
|
5
|
+
export declare const OIDCTokenUpdateSchema: JSONSchemaType<OIDCTokenUpdate>;
|
|
6
|
+
export declare const ProviderProfileDetailsSchema: JSONSchemaType<ProviderProfileDetails>;
|
|
7
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAGpH,eAAO,MAAM,wBAAwB,EAAE,cAAc,CAAC,kBAAkB,CAQvE,CAAA;AAED,eAAO,MAAM,2BAA2B,EAAE,cAAc,CAAC,qBAAqB,CAQ7E,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,eAAe,CAqBjE,CAAA;AAED,eAAO,MAAM,4BAA4B,EAAE,cAAc,CAAC,sBAAsB,CAe/E,CAAA"}
|
package/build/models.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { AuthTokenSchema, EntityValueSchema, IdValueSchema, ScopeValueSchema, TypeNameSchema } from '@owlmeans/auth';
|
|
2
|
+
export const OIDCAuthInitParamsSchema = {
|
|
3
|
+
type: 'object',
|
|
4
|
+
properties: {
|
|
5
|
+
entity: { ...EntityValueSchema, nullable: true },
|
|
6
|
+
profile: { ...IdValueSchema, nullable: true },
|
|
7
|
+
},
|
|
8
|
+
required: [],
|
|
9
|
+
additionalProperties: false,
|
|
10
|
+
};
|
|
11
|
+
export const OIDCClientAuthPayloadSchema = {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
code: { type: 'string', minLength: 16, maxLength: 512 },
|
|
15
|
+
authUrl: { type: 'string', minLength: 0, maxLength: 1024, format: 'uri' },
|
|
16
|
+
},
|
|
17
|
+
additionalProperties: { type: 'string', minLength: 0, maxLength: 512 },
|
|
18
|
+
required: ['code', 'authUrl'],
|
|
19
|
+
};
|
|
20
|
+
export const OIDCTokenUpdateSchema = {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
...AuthTokenSchema.properties,
|
|
24
|
+
tokenSet: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
access_token: { type: 'string', nullable: true },
|
|
28
|
+
token_type: { type: 'string', nullable: true },
|
|
29
|
+
id_token: { type: 'string', nullable: true },
|
|
30
|
+
refresh_token: { type: 'string', nullable: true },
|
|
31
|
+
scope: { type: 'string', nullable: true },
|
|
32
|
+
expires_at: { type: 'number', nullable: true },
|
|
33
|
+
session_state: { type: 'string', nullable: true }
|
|
34
|
+
},
|
|
35
|
+
required: [],
|
|
36
|
+
additionalProperties: true,
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
required: ['token', 'tokenSet'],
|
|
40
|
+
additionalProperties: false
|
|
41
|
+
};
|
|
42
|
+
export const ProviderProfileDetailsSchema = {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
type: { ...TypeNameSchema },
|
|
46
|
+
service: { ...ScopeValueSchema },
|
|
47
|
+
clientId: { ...ScopeValueSchema },
|
|
48
|
+
userId: { ...IdValueSchema },
|
|
49
|
+
profileId: { ...IdValueSchema, nullable: true },
|
|
50
|
+
username: { type: 'string', minLength: 1, maxLength: 255, nullable: true },
|
|
51
|
+
entityId: { ...EntityValueSchema, nullable: true },
|
|
52
|
+
did: { ...IdValueSchema, nullable: true },
|
|
53
|
+
isOwlMeansId: { type: 'boolean', nullable: true }
|
|
54
|
+
},
|
|
55
|
+
required: ['type', 'service', 'clientId', 'userId'],
|
|
56
|
+
additionalProperties: false
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,OAAO,2CAUnB,CAAA"}
|
package/build/modules.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { body, filter, module } from '@owlmeans/module';
|
|
2
|
+
import { route, RouteMethod, backend } from '@owlmeans/route';
|
|
3
|
+
import { DISPATCHER_OIDC, DISPATCHER_OIDC_INIT } from './consts.js';
|
|
4
|
+
import { OIDCAuthInitParamsSchema, OIDCClientAuthPayloadSchema } from './models.js';
|
|
5
|
+
export const modules = [
|
|
6
|
+
module(route(DISPATCHER_OIDC_INIT, '/authenticate/oidc/init', backend(null, RouteMethod.POST)), filter(body(OIDCAuthInitParamsSchema))),
|
|
7
|
+
module(route(DISPATCHER_OIDC, '/authenticate/oidc/process', backend(null, RouteMethod.POST)), filter(body(OIDCClientAuthPayloadSchema)))
|
|
8
|
+
];
|
|
9
|
+
//# sourceMappingURL=modules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAEnF,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,MAAM,CACJ,KAAK,CAAC,oBAAoB,EAAE,yBAAyB,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,EACvF,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAEvC;IACD,MAAM,CACJ,KAAK,CAAC,eAAe,EAAE,4BAA4B,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,EACrF,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAC1C;CACF,CAAA"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { AuthToken } from '@owlmeans/auth';
|
|
2
|
+
import type { AuthorizationService } from '@owlmeans/auth-common';
|
|
3
|
+
import type { BasicConfig, BasicContext } from '@owlmeans/context';
|
|
4
|
+
import type { GuardService } from '@owlmeans/module';
|
|
5
|
+
export interface Config extends BasicConfig {
|
|
6
|
+
}
|
|
7
|
+
export interface Context<C extends Config = Config> extends BasicContext<C> {
|
|
8
|
+
}
|
|
9
|
+
export interface OidcSharedConfig {
|
|
10
|
+
clientCookie?: {
|
|
11
|
+
interaction?: {
|
|
12
|
+
name?: string;
|
|
13
|
+
ttl?: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
providers?: OidcProviderConfig[];
|
|
17
|
+
/**
|
|
18
|
+
* false - in case the service user can't use identity provider for authentication (restricted for internal use only)
|
|
19
|
+
* true - in case only default identity provider can be used
|
|
20
|
+
* string[] - list of allowed identity providers
|
|
21
|
+
*/
|
|
22
|
+
restrictedProviders?: boolean | string[];
|
|
23
|
+
}
|
|
24
|
+
export interface OidcProviderConfig extends OidcProviderDescriptor {
|
|
25
|
+
internal?: boolean;
|
|
26
|
+
apiClientId?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface OidcProviderDescriptor {
|
|
29
|
+
entityId?: string;
|
|
30
|
+
service?: string;
|
|
31
|
+
discoveryUrl?: string;
|
|
32
|
+
basePath?: string;
|
|
33
|
+
clientId: string;
|
|
34
|
+
secret?: string;
|
|
35
|
+
extraScopes?: string;
|
|
36
|
+
idOverride?: string;
|
|
37
|
+
def?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface WithSharedConfig {
|
|
40
|
+
oidc: OidcSharedConfig;
|
|
41
|
+
}
|
|
42
|
+
export interface OidcGuard extends GuardService {
|
|
43
|
+
}
|
|
44
|
+
export interface OidcGuardOptions {
|
|
45
|
+
cache?: string;
|
|
46
|
+
coguards: string | string[];
|
|
47
|
+
tokenService?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface OIDCAuthInitParams {
|
|
50
|
+
entity?: string;
|
|
51
|
+
profile?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface OIDCClientAuthPayload extends Record<string, string> {
|
|
54
|
+
code: string;
|
|
55
|
+
authUrl: string;
|
|
56
|
+
}
|
|
57
|
+
export interface WrappedOIDCService extends AuthorizationService {
|
|
58
|
+
}
|
|
59
|
+
export interface OIDCTokenUpdate extends AuthToken {
|
|
60
|
+
tokenSet: CommonTokenSetParams;
|
|
61
|
+
}
|
|
62
|
+
export interface CommonTokenSetParams extends Record<string, string | number | undefined> {
|
|
63
|
+
access_token?: string;
|
|
64
|
+
token_type?: string;
|
|
65
|
+
id_token?: string;
|
|
66
|
+
refresh_token?: string;
|
|
67
|
+
scope?: string;
|
|
68
|
+
expires_at?: number;
|
|
69
|
+
session_state?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface ProviderProfileDetails extends Partial<OidcUserDetails> {
|
|
72
|
+
type: string;
|
|
73
|
+
service: string;
|
|
74
|
+
clientId: string;
|
|
75
|
+
userId: string;
|
|
76
|
+
profileId?: string;
|
|
77
|
+
}
|
|
78
|
+
export interface OidcUserDetails {
|
|
79
|
+
userId: string;
|
|
80
|
+
username: string;
|
|
81
|
+
entityId?: string;
|
|
82
|
+
did?: string;
|
|
83
|
+
isOwlMeansId?: boolean;
|
|
84
|
+
}
|
|
85
|
+
export interface OidcProviderSettings {
|
|
86
|
+
registrationEnabled: boolean;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@owlmeans/oidc",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -b",
|
|
7
|
+
"dev": "sleep 222 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
|
|
8
|
+
"watch": "tsc -b -w --preserveWatchOutput --pretty"
|
|
9
|
+
},
|
|
10
|
+
"main": "build/index.js",
|
|
11
|
+
"module": "build/index.js",
|
|
12
|
+
"types": "build/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./build/index.js",
|
|
16
|
+
"require": "./build/index.js",
|
|
17
|
+
"default": "./build/index.js",
|
|
18
|
+
"module": "./build/index.js",
|
|
19
|
+
"types": "./build/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@owlmeans/auth": "^0.1.0",
|
|
24
|
+
"@owlmeans/auth-common": "^0.1.0",
|
|
25
|
+
"@owlmeans/basic-envelope": "^0.1.0",
|
|
26
|
+
"@owlmeans/config": "^0.1.0",
|
|
27
|
+
"@owlmeans/context": "^0.1.0",
|
|
28
|
+
"@owlmeans/module": "^0.1.0",
|
|
29
|
+
"@owlmeans/resource": "^0.1.0",
|
|
30
|
+
"@owlmeans/route": "^0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"ajv": "*"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"nodemon": "^3.1.7",
|
|
37
|
+
"npm-check": "^6.0.1",
|
|
38
|
+
"typescript": "^5.6.3"
|
|
39
|
+
},
|
|
40
|
+
"private": false,
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/consts.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
export const DEFAULT_PATH = 'oidc'
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_FRONT = 'oidc-client'
|
|
5
|
+
|
|
6
|
+
export const INTERACTION_PATH = '/interaction/:uid'
|
|
7
|
+
|
|
8
|
+
export const INTERACTION = 'oidc:interaction'
|
|
9
|
+
|
|
10
|
+
export const OIDC_FLOW = 'oidc'
|
|
11
|
+
|
|
12
|
+
export const OIDC_AUTHEN_MODULE = 'iam-oidc-authen'
|
|
13
|
+
|
|
14
|
+
export const PROVIDER_INTERACTION = 'oidc-server:interaction'
|
|
15
|
+
|
|
16
|
+
export const OIDC_CLIENT_AUTH = 'oidc-client'
|
|
17
|
+
|
|
18
|
+
export const OIDC_GUARD = 'guard:oidc'
|
|
19
|
+
|
|
20
|
+
export const OIDC_GUARD_CACHE = 'resource:oidc-guard:cache'
|
|
21
|
+
|
|
22
|
+
export const DISPATCHER_OIDC_INIT = 'dispatcher:oidc:init'
|
|
23
|
+
|
|
24
|
+
export const DISPATCHER_OIDC = 'dispatcher:oidc:authenticate'
|
|
25
|
+
|
|
26
|
+
export const OIDC_CODE_QUERY = 'code'
|
|
27
|
+
|
|
28
|
+
export const OIDC_WRAPPED_TOKEN = 'oidc-wrapped-token'
|
|
29
|
+
|
|
30
|
+
export const WRAPPED_OIDC = 'wrapped-oidc-authz'
|
|
31
|
+
|
|
32
|
+
export const OIDC_GATE = 'oidc-gate'
|
package/src/guard.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createService } from '@owlmeans/context'
|
|
2
|
+
import type { Config, Context, OidcGuard, OidcGuardOptions, WrappedOIDCService } from './types.js'
|
|
3
|
+
import { OIDC_GUARD, OIDC_WRAPPED_TOKEN, WRAPPED_OIDC } from './consts.js'
|
|
4
|
+
import type { AbstractRequest, AbstractResponse, CommonModule, GuardService } from '@owlmeans/module'
|
|
5
|
+
import { DEFAULT_GUARD, TOKEN_UPDATE } from '@owlmeans/auth-common'
|
|
6
|
+
import { AUTH_HEADER, type Auth, AuthToken, AuthorizationError } from '@owlmeans/auth'
|
|
7
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
8
|
+
import { trust } from '@owlmeans/auth-common/utils'
|
|
9
|
+
import { TRUSTED } from '@owlmeans/config'
|
|
10
|
+
import { extractAuthToken } from '@owlmeans/auth-common/utils'
|
|
11
|
+
import { modules as oidcModules } from './modules.js'
|
|
12
|
+
|
|
13
|
+
export const makeOidcGuard = (opts?: OidcGuardOptions): OidcGuard => {
|
|
14
|
+
// const cache = (context: Context) => context.hasResource(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
15
|
+
// ? context.resource<Resource<ResourceRecord>>(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
16
|
+
// : null
|
|
17
|
+
|
|
18
|
+
const [cogurad] = Array.isArray(opts?.coguards) ? opts.coguards : [opts?.coguards ?? DEFAULT_GUARD]
|
|
19
|
+
|
|
20
|
+
const guard: OidcGuard = createService<OidcGuard>(OIDC_GUARD, {
|
|
21
|
+
// Client side
|
|
22
|
+
|
|
23
|
+
// get token() {
|
|
24
|
+
// const ctx = guard.assertCtx<Config, Context>()
|
|
25
|
+
// if (!ctx.hasService(cogurad)) {
|
|
26
|
+
// return undefined
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
// // @TODO Make some custom implementation if required.
|
|
30
|
+
// // Cause it won't work on the back. And it's likely that
|
|
31
|
+
// // we will need it soon.
|
|
32
|
+
// const auth = ctx.service<GuardService>(cogurad)
|
|
33
|
+
// return auth.token
|
|
34
|
+
// },
|
|
35
|
+
|
|
36
|
+
authenticated: async req => {
|
|
37
|
+
const ctx = guard.assertCtx()
|
|
38
|
+
// @TODO Make some custom implementation if required.
|
|
39
|
+
// We try to rely on some centeral auth service that operates all tokens.
|
|
40
|
+
const auth = ctx.service<GuardService>(opts?.tokenService ?? cogurad)
|
|
41
|
+
const token = await auth.authenticated(req)
|
|
42
|
+
if (token != null) {
|
|
43
|
+
const [type] = token.split(' ')
|
|
44
|
+
if (type === OIDC_WRAPPED_TOKEN.toUpperCase()) {
|
|
45
|
+
return token
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Server side
|
|
53
|
+
match: async req => extractAuthToken(req, OIDC_WRAPPED_TOKEN) != null,
|
|
54
|
+
|
|
55
|
+
handle: async <T>(req: AbstractRequest, res: AbstractResponse<Auth>) => {
|
|
56
|
+
const authorization = extractAuthToken(req, OIDC_WRAPPED_TOKEN)
|
|
57
|
+
if (authorization == null) {
|
|
58
|
+
return false as T
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const ctx = guard.assertCtx()
|
|
62
|
+
const envelope = makeEnvelopeModel<Auth>(authorization, EnvelopeKind.Token)
|
|
63
|
+
const trusted = await trust<Config, Context>(ctx, TRUSTED, ctx.cfg.alias ?? ctx.cfg.service)
|
|
64
|
+
|
|
65
|
+
if (!await envelope.verify(trusted.key)) {
|
|
66
|
+
return false as T
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const token = extractAuthToken(req, OIDC_WRAPPED_TOKEN, false)!
|
|
70
|
+
|
|
71
|
+
let updated: AuthToken | null = null
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
updated = await wrapper(ctx).update({ token }, true)
|
|
75
|
+
} catch (e) {
|
|
76
|
+
if (e instanceof AuthorizationError) {
|
|
77
|
+
res.responseProvider.header(TOKEN_UPDATE, '')
|
|
78
|
+
req.headers = { ...req.headers, [AUTH_HEADER]: '' }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw e
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (updated == null) {
|
|
85
|
+
return false as T
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (updated.token !== token) {
|
|
89
|
+
const [, newAuth] = updated.token.split(' ')
|
|
90
|
+
const envelope = makeEnvelopeModel<Auth>(newAuth, EnvelopeKind.Token)
|
|
91
|
+
|
|
92
|
+
res.responseProvider.header(TOKEN_UPDATE, updated.token)
|
|
93
|
+
req.headers = { ...req.headers, [AUTH_HEADER]: updated.token }
|
|
94
|
+
|
|
95
|
+
res.resolve(envelope.message())
|
|
96
|
+
} else {
|
|
97
|
+
res.resolve(envelope.message())
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return true as T
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return guard
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const appendOidcGuard = <C extends Config, T extends Context<C>>(
|
|
108
|
+
context: T, opts?: OidcGuardOptions
|
|
109
|
+
) => {
|
|
110
|
+
context.registerService(makeOidcGuard(opts))
|
|
111
|
+
|
|
112
|
+
return context
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const setupOidcGuard = (modules: CommonModule[], coguards?: string | string[]) => {
|
|
116
|
+
modules.push(...oidcModules)
|
|
117
|
+
coguards = Array.isArray(coguards) ? coguards : [coguards ?? DEFAULT_GUARD]
|
|
118
|
+
|
|
119
|
+
modules.forEach(module => {
|
|
120
|
+
if (module.guards != null && !module.guards.includes(OIDC_GUARD)
|
|
121
|
+
&& module.guards.some(guard => coguards.includes(guard))) {
|
|
122
|
+
module.guards.unshift(OIDC_GUARD)
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const wrapper = (context: Context): WrappedOIDCService =>
|
|
128
|
+
context.hasService(WRAPPED_OIDC)
|
|
129
|
+
? context.service(WRAPPED_OIDC)
|
|
130
|
+
: { update: async token => token } as WrappedOIDCService
|
package/src/index.ts
ADDED
package/src/models.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { JSONSchemaType } from 'ajv'
|
|
2
|
+
import type { OIDCAuthInitParams, OIDCClientAuthPayload, OIDCTokenUpdate, ProviderProfileDetails } from './types.js'
|
|
3
|
+
import { AuthTokenSchema, EntityValueSchema, IdValueSchema, ScopeValueSchema, TypeNameSchema } from '@owlmeans/auth'
|
|
4
|
+
|
|
5
|
+
export const OIDCAuthInitParamsSchema: JSONSchemaType<OIDCAuthInitParams> = {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
entity: { ...EntityValueSchema, nullable: true },
|
|
9
|
+
profile: { ...IdValueSchema, nullable: true },
|
|
10
|
+
},
|
|
11
|
+
required: [],
|
|
12
|
+
additionalProperties: false,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const OIDCClientAuthPayloadSchema: JSONSchemaType<OIDCClientAuthPayload> = {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
code: { type: 'string', minLength: 16, maxLength: 512 },
|
|
19
|
+
authUrl: { type: 'string', minLength: 0, maxLength: 1024, format: 'uri' },
|
|
20
|
+
},
|
|
21
|
+
additionalProperties: {type: 'string', minLength: 0, maxLength: 512},
|
|
22
|
+
required: ['code', 'authUrl'],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const OIDCTokenUpdateSchema: JSONSchemaType<OIDCTokenUpdate> = {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
...AuthTokenSchema.properties,
|
|
29
|
+
tokenSet: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
access_token: { type: 'string', nullable: true },
|
|
33
|
+
token_type: { type: 'string', nullable: true },
|
|
34
|
+
id_token: { type: 'string', nullable: true },
|
|
35
|
+
refresh_token: { type: 'string', nullable: true },
|
|
36
|
+
scope: { type: 'string', nullable: true },
|
|
37
|
+
expires_at: { type: 'number', nullable: true },
|
|
38
|
+
session_state: { type: 'string', nullable: true }
|
|
39
|
+
},
|
|
40
|
+
required: [],
|
|
41
|
+
additionalProperties: true,
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
required: ['token', 'tokenSet'],
|
|
45
|
+
additionalProperties: false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const ProviderProfileDetailsSchema: JSONSchemaType<ProviderProfileDetails> = {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
type: { ...TypeNameSchema },
|
|
52
|
+
service: { ...ScopeValueSchema },
|
|
53
|
+
clientId: { ...ScopeValueSchema },
|
|
54
|
+
userId: { ...IdValueSchema },
|
|
55
|
+
profileId: {...IdValueSchema, nullable: true },
|
|
56
|
+
username: { type: 'string', minLength: 1, maxLength: 255, nullable: true },
|
|
57
|
+
entityId: { ...EntityValueSchema, nullable: true },
|
|
58
|
+
did: { ...IdValueSchema, nullable: true },
|
|
59
|
+
isOwlMeansId: { type: 'boolean', nullable: true }
|
|
60
|
+
},
|
|
61
|
+
required: ['type', 'service', 'clientId', 'userId'],
|
|
62
|
+
additionalProperties: false
|
|
63
|
+
}
|
package/src/modules.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { body, filter, module } from '@owlmeans/module'
|
|
2
|
+
import { route, RouteMethod, backend } from '@owlmeans/route'
|
|
3
|
+
import { DISPATCHER_OIDC, DISPATCHER_OIDC_INIT } from './consts.js'
|
|
4
|
+
import { OIDCAuthInitParamsSchema, OIDCClientAuthPayloadSchema } from './models.js'
|
|
5
|
+
|
|
6
|
+
export const modules = [
|
|
7
|
+
module(
|
|
8
|
+
route(DISPATCHER_OIDC_INIT, '/authenticate/oidc/init', backend(null, RouteMethod.POST)),
|
|
9
|
+
filter(body(OIDCAuthInitParamsSchema))
|
|
10
|
+
|
|
11
|
+
),
|
|
12
|
+
module(
|
|
13
|
+
route(DISPATCHER_OIDC, '/authenticate/oidc/process', backend(null, RouteMethod.POST)),
|
|
14
|
+
filter(body(OIDCClientAuthPayloadSchema))
|
|
15
|
+
)
|
|
16
|
+
]
|