@owlmeans/web-oidc-rp 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 +515 -0
- package/build/.gitkeep +0 -0
- package/build/auth/plugins/index.d.ts +4 -0
- package/build/auth/plugins/index.d.ts.map +1 -0
- package/build/auth/plugins/index.js +6 -0
- package/build/auth/plugins/index.js.map +1 -0
- package/build/auth/plugins/oidc-client.d.ts +3 -0
- package/build/auth/plugins/oidc-client.d.ts.map +1 -0
- package/build/auth/plugins/oidc-client.js +97 -0
- package/build/auth/plugins/oidc-client.js.map +1 -0
- package/build/components/dispatcher.d.ts +2 -0
- package/build/components/dispatcher.d.ts.map +1 -0
- package/build/components/dispatcher.js +58 -0
- package/build/components/dispatcher.js.map +1 -0
- package/build/components/index.d.ts +2 -0
- package/build/components/index.d.ts.map +1 -0
- package/build/components/index.js +2 -0
- package/build/components/index.js.map +1 -0
- package/build/consts.d.ts +7 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +8 -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 +18 -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/service.d.ts +3 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +112 -0
- package/build/service.js.map +1 -0
- package/build/types.d.ts +25 -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 +60 -0
- package/src/auth/plugins/index.ts +8 -0
- package/src/auth/plugins/oidc-client.tsx +114 -0
- package/src/components/dispatcher.tsx +61 -0
- package/src/components/index.ts +2 -0
- package/src/consts.ts +8 -0
- package/src/guard.ts +31 -0
- package/src/index.ts +6 -0
- package/src/service.ts +147 -0
- package/src/types.ts +32 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { DispatcherHOC } from '@owlmeans/client-auth';
|
|
3
|
+
import { useSearchParams } from 'react-router-dom';
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { useContext } from '@owlmeans/web-client';
|
|
6
|
+
import { useI18nLib } from '@owlmeans/client-i18n';
|
|
7
|
+
import { AUTH_QUERY } from '@owlmeans/auth';
|
|
8
|
+
import { useFlow } from '@owlmeans/web-flow';
|
|
9
|
+
import { DEFAULT_ALIAS } from '../consts.js';
|
|
10
|
+
export const Dispatcher = DispatcherHOC(({ provideToken, navigate }) => {
|
|
11
|
+
const [query] = useSearchParams();
|
|
12
|
+
const context = useContext();
|
|
13
|
+
const client = useFlow();
|
|
14
|
+
const t = useI18nLib('auth', 'dispatcher');
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (client == null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const token = query.get(AUTH_QUERY);
|
|
20
|
+
const params = {};
|
|
21
|
+
query.forEach((value, key) => {
|
|
22
|
+
if (key !== AUTH_QUERY) {
|
|
23
|
+
params[key] = value;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (token != null) {
|
|
27
|
+
// This is required for compatibility with a standard OwlMeans Auth flow.
|
|
28
|
+
provideToken({ token }, params);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const oidc = context.service(DEFAULT_ALIAS);
|
|
32
|
+
oidc.dispatch(params).then(async (dispatched) => {
|
|
33
|
+
if (dispatched) {
|
|
34
|
+
return await navigate();
|
|
35
|
+
}
|
|
36
|
+
if (client == null) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const redirect = await oidc.authenticate(client.flow(), params);
|
|
40
|
+
if (redirect != null && redirect !== '') {
|
|
41
|
+
document.location.href = redirect;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const authzToken = await context.auth().authenticated();
|
|
45
|
+
if (authzToken == null) {
|
|
46
|
+
provideToken({ token: '' }, undefined);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
await navigate();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}, [client]);
|
|
54
|
+
return query.has(AUTH_QUERY)
|
|
55
|
+
? _jsx("div", { children: t('loading') })
|
|
56
|
+
: undefined;
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/components/dispatcher.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;IACrE,MAAM,CAAC,KAAK,CAAC,GAAG,eAAe,EAAE,CAAA;IACjC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAG,OAAO,EAAE,CAAA;IAExB,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IAE1C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACnC,MAAM,MAAM,GAA2B,EAAE,CAAA;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC3B,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;gBACvB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;YACrB,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,yEAAyE;YACzE,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,CAAC,CAAA;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAkB,aAAa,CAAC,CAAA;YAC5D,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAC,UAAU,EAAC,EAAE;gBAC5C,IAAI,UAAU,EAAE,CAAC;oBACf,OAAO,MAAM,QAAQ,EAAE,CAAA;gBACzB,CAAC;gBACD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;oBACnB,OAAM;gBACR,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAA;gBAC/D,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;oBACxC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAA;oBACjC,OAAM;gBACR,CAAC;gBACD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,CAAA;gBACvD,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;oBACvB,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,CAAA;gBACxC,CAAC;qBAAM,CAAC;oBACN,MAAM,QAAQ,EAAE,CAAA;gBAClB,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,OAAO,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1B,CAAC,CAAC,wBAAM,CAAC,CAAC,SAAS,CAAC,GAAO;QAC3B,CAAC,CAAC,SAAS,CAAA;AACf,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,YAAY,CAAA;AAEtC,oBAAY,gBAAgB;IAC1B,OAAO,YAAY;IACnB,SAAS,cAAc;IACvB,KAAK,UAAU;CAChB"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const DEFAULT_ALIAS = 'oidc-rp';
|
|
2
|
+
export var OidcAuthPurposes;
|
|
3
|
+
(function (OidcAuthPurposes) {
|
|
4
|
+
OidcAuthPurposes["Unknown"] = "unknown";
|
|
5
|
+
OidcAuthPurposes["Subscribe"] = "subscribe";
|
|
6
|
+
OidcAuthPurposes["Login"] = "login";
|
|
7
|
+
})(OidcAuthPurposes || (OidcAuthPurposes = {}));
|
|
8
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAA;AAEtC,MAAM,CAAN,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,uCAAmB,CAAA;IACnB,2CAAuB,CAAA;IACvB,mCAAe,CAAA;AACjB,CAAC,EAJW,gBAAgB,KAAhB,gBAAgB,QAI3B"}
|
package/build/guard.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OidcGuardOptions } from '@owlmeans/oidc';
|
|
2
|
+
import type { Config, Context } from './types.js';
|
|
3
|
+
import type { CommonModule } from '@owlmeans/module';
|
|
4
|
+
export declare const appendOidcGuard: <C extends Config, T extends Context<C>>(context: T, opts?: OidcGuardOptions) => T;
|
|
5
|
+
export declare const setupOidcGuard: (modules: CommonModule[], coguards?: string | string[]) => void;
|
|
6
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAYpD,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,WAC3D,CAAC,SAAS,gBAAgB,MAOpC,CAAA;AAED,eAAO,MAAM,cAAc,YAAa,YAAY,EAAE,aAAa,MAAM,GAAG,MAAM,EAAE,SAMnF,CAAA"}
|
package/build/guard.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { appendOidcGuard as appendBasicOidcGuard, setupOidcGuard as setupBasicOidcGuard, DISPATCHER_OIDC, DISPATCHER_OIDC_INIT } from '@owlmeans/oidc';
|
|
2
|
+
import { elevate } from '@owlmeans/web-client';
|
|
3
|
+
import { DISPATCHER } from '@owlmeans/auth';
|
|
4
|
+
import { handler } from '@owlmeans/client';
|
|
5
|
+
import { Dispatcher } from './components/dispatcher.js';
|
|
6
|
+
import { makeOidcAuthService } from './service.js';
|
|
7
|
+
export const appendOidcGuard = (context, opts) => {
|
|
8
|
+
context.registerService(makeOidcAuthService());
|
|
9
|
+
const ctx = appendBasicOidcGuard(context, opts);
|
|
10
|
+
return ctx;
|
|
11
|
+
};
|
|
12
|
+
export const setupOidcGuard = (modules, coguards) => {
|
|
13
|
+
setupBasicOidcGuard(modules, coguards);
|
|
14
|
+
elevate(modules, DISPATCHER_OIDC_INIT);
|
|
15
|
+
elevate(modules, DISPATCHER_OIDC);
|
|
16
|
+
elevate(modules, DISPATCHER, handler(Dispatcher), { force: true });
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,eAAe,IAAI,oBAAoB,EACvC,cAAc,IAAI,mBAAmB,EACrC,eAAe,EAAE,oBAAoB,EACtC,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAElD,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,OAAU,EAAE,IAAuB,EACnC,EAAE;IACF,OAAO,CAAC,eAAe,CAAC,mBAAmB,EAAE,CAAC,CAAA;IAE9C,MAAM,GAAG,GAAG,oBAAoB,CAAO,OAAO,EAAE,IAAI,CAAC,CAAA;IAErD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAuB,EAAE,QAA4B,EAAE,EAAE;IACtF,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAEtC,OAAO,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAA;IACtC,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;IACjC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACpE,CAAC,CAAA"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,uBAAuB,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,uBAAuB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,eAAe,EAAmB,MAAM,YAAY,CAAA;AAenF,eAAO,MAAM,mBAAmB,WAAW,MAAM,KAAmB,eAmInE,CAAA"}
|
package/build/service.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { assertContext, createService, HOME } from '@owlmeans/context';
|
|
2
|
+
import { DEFAULT_ALIAS } from './consts.js';
|
|
3
|
+
import { UserManager } from 'oidc-client-ts';
|
|
4
|
+
import { DEFAULT_ALIAS as FLOW_SERVICE } from '@owlmeans/client-flow';
|
|
5
|
+
import { FlowStepMissconfigured, OidcAuthStep, STD_OIDC_FLOW, UnknownFlow } from '@owlmeans/flow';
|
|
6
|
+
import { DISPATCHER_OIDC, DISPATCHER_OIDC_INIT, OIDC_CODE_QUERY } from '@owlmeans/oidc';
|
|
7
|
+
import { AUTH_RESOURCE, USER_ID } from '@owlmeans/client-auth';
|
|
8
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
|
|
9
|
+
export const makeOidcAuthService = (alias = DEFAULT_ALIAS) => {
|
|
10
|
+
const store = (context) => context.auth().store();
|
|
11
|
+
const storeKey = '_oidc-client-interaction';
|
|
12
|
+
const service = createService(alias, {
|
|
13
|
+
/**
|
|
14
|
+
* This method performs when the IdP returns authentication params.
|
|
15
|
+
*/
|
|
16
|
+
dispatch: async (params) => {
|
|
17
|
+
/**
|
|
18
|
+
* 1. Check if there are parameters in the URL for the server side OIDC authentication (e.g. code)
|
|
19
|
+
* 2. Send paramters to finalize authentication (proxy request to the auth server?)
|
|
20
|
+
* 3. If the authentication successful set user state using authentication service
|
|
21
|
+
*/
|
|
22
|
+
if (params[OIDC_CODE_QUERY] == null) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const ctx = service.assertCtx();
|
|
26
|
+
params.authUrl = (await store(ctx).get(storeKey)).authUrl;
|
|
27
|
+
const [authToken] = await ctx.module(DISPATCHER_OIDC)
|
|
28
|
+
.call({ body: params });
|
|
29
|
+
if (authToken.token != null && authToken.token !== '') {
|
|
30
|
+
const authResource = ctx.resource(AUTH_RESOURCE);
|
|
31
|
+
await authResource.save({ id: USER_ID, token: authToken.token });
|
|
32
|
+
const [, authorization] = authToken.token.split(' ');
|
|
33
|
+
const envelope = makeEnvelopeModel(authorization, EnvelopeKind.Token);
|
|
34
|
+
ctx.auth().auth = envelope.message();
|
|
35
|
+
ctx.auth().token = authToken.token;
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
},
|
|
40
|
+
authenticate: async (flow, params) => {
|
|
41
|
+
/**
|
|
42
|
+
* 1. Kick of OIDC authentication if we receive some hints about who or for what organization we'd like to authenticate
|
|
43
|
+
* 2. Request OIDC authentication params from the server using these entity and profile id
|
|
44
|
+
* 3. The server should return an URL to redirect user to
|
|
45
|
+
* 4. Return this user to the component for the further processing (redirection)
|
|
46
|
+
*/
|
|
47
|
+
if (flow.state().flow !== STD_OIDC_FLOW || flow.state().step !== OidcAuthStep.Ephemeral) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (params.entity == null && params.entity == null) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const ctx = service.assertCtx();
|
|
54
|
+
const [redirectTo] = await ctx.module(DISPATCHER_OIDC_INIT)
|
|
55
|
+
.call({ body: params });
|
|
56
|
+
const context = service.assertCtx();
|
|
57
|
+
await store(context).save({ id: storeKey, authUrl: redirectTo });
|
|
58
|
+
return redirectTo;
|
|
59
|
+
},
|
|
60
|
+
proceedToRedirectUrl: async (extras) => {
|
|
61
|
+
const context = assertContext(service.ctx);
|
|
62
|
+
const flow = context.service(FLOW_SERVICE);
|
|
63
|
+
const flowModel = await flow.state();
|
|
64
|
+
if (flowModel == null) {
|
|
65
|
+
throw new UnknownFlow('oidc.dispatch');
|
|
66
|
+
}
|
|
67
|
+
const authorityTransition = flowModel.next();
|
|
68
|
+
flowModel.transit(authorityTransition.transition, true, { purpose: extras.purpose });
|
|
69
|
+
// @TODO I'm not sure that this dirty hack is a correct approach
|
|
70
|
+
if (extras.alias === HOME) {
|
|
71
|
+
const redirectTransition = flowModel.next();
|
|
72
|
+
flowModel.transit(redirectTransition.transition, true, { purpose: extras.purpose });
|
|
73
|
+
}
|
|
74
|
+
const redirectUrl = await flow.proceed({ params: { uid: extras.uid } }, true);
|
|
75
|
+
return redirectUrl;
|
|
76
|
+
},
|
|
77
|
+
/**
|
|
78
|
+
* This is client-side only OIDC implementation. It's under constructuion.
|
|
79
|
+
* We stoped on the try to redirect to OIDC provider, but it requires browser integrated
|
|
80
|
+
* cryptography under ssl/tls.
|
|
81
|
+
* @TODO Finish client-side only implementation one day
|
|
82
|
+
*/
|
|
83
|
+
dispatchClientOnly: async () => {
|
|
84
|
+
const context = assertContext(service.ctx);
|
|
85
|
+
const flow = context.service(FLOW_SERVICE);
|
|
86
|
+
const flowModel = await flow.state();
|
|
87
|
+
if (flowModel == null) {
|
|
88
|
+
throw new UnknownFlow('oidc.dispatch');
|
|
89
|
+
}
|
|
90
|
+
const authorityTransition = flowModel.next();
|
|
91
|
+
flowModel.transit(authorityTransition.transition, true);
|
|
92
|
+
const authorityStep = flowModel.step();
|
|
93
|
+
if (authorityStep.module == null) {
|
|
94
|
+
throw new FlowStepMissconfigured(authorityStep.step);
|
|
95
|
+
}
|
|
96
|
+
const [authorityUrl] = await context.module(authorityStep.module).call();
|
|
97
|
+
const redirectTransition = flowModel.next();
|
|
98
|
+
flowModel.transit(redirectTransition.transition, true);
|
|
99
|
+
const redirectUrl = await flow.proceed(undefined, true);
|
|
100
|
+
// @TODO To proceed we need to provide client_id some way
|
|
101
|
+
const manager = new UserManager({
|
|
102
|
+
// client_id: context.cfg.oidc.consumer?.clientId ?? '',
|
|
103
|
+
client_id: '',
|
|
104
|
+
redirect_uri: redirectUrl,
|
|
105
|
+
authority: authorityUrl,
|
|
106
|
+
});
|
|
107
|
+
await manager.signinRedirect({ state: flowModel.serialize() });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return service;
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { InitializedService } from '@owlmeans/context';
|
|
2
|
+
import type { AppConfig, AppContext } from '@owlmeans/web-client';
|
|
3
|
+
import type { OIDCAuthInitParams, WithSharedConfig } from '@owlmeans/oidc';
|
|
4
|
+
import type { OidcAuthPurposes } from './consts.js';
|
|
5
|
+
import type { FlowModel, FlowPayload } from '@owlmeans/flow';
|
|
6
|
+
import type { ResourceRecord } from '@owlmeans/resource';
|
|
7
|
+
export interface OidcAuthService extends InitializedService {
|
|
8
|
+
dispatch: (params: Record<string, string>) => Promise<boolean>;
|
|
9
|
+
authenticate: (flow: FlowModel, params: OIDCAuthInitParams) => Promise<string | null>;
|
|
10
|
+
proceedToRedirectUrl: (extras: OidcAuthRedirectExtras) => Promise<string>;
|
|
11
|
+
dispatchClientOnly: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export interface OidcAuthRedirectExtras extends FlowPayload {
|
|
14
|
+
purpose: OidcAuthPurposes;
|
|
15
|
+
uid?: string;
|
|
16
|
+
alias?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Config extends AppConfig, WithSharedConfig {
|
|
19
|
+
}
|
|
20
|
+
export interface Context<C extends Config = Config> extends AppContext<C> {
|
|
21
|
+
}
|
|
22
|
+
export interface OidcInteraction extends ResourceRecord {
|
|
23
|
+
authUrl: string;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAE9D,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAGrF,oBAAoB,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAGzE,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,OAAO,EAAE,gBAAgB,CAAA;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,MAAO,SAAQ,SAAS,EAAE,gBAAgB;CAAI;AAE/D,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;CAAI;AAE7E,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,OAAO,EAAE,MAAM,CAAA;CAChB"}
|
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,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@owlmeans/web-oidc-rp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -b",
|
|
7
|
+
"dev": "sleep 378 && 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
|
+
"./auth/plugins": {
|
|
22
|
+
"import": "./build/auth/plugins/index.js",
|
|
23
|
+
"require": "./build/auth/plugins/index.js",
|
|
24
|
+
"default": "./build/auth/plugins/index.js",
|
|
25
|
+
"module": "./build/auth/plugins/index.js",
|
|
26
|
+
"types": "./build/auth/plugins/index.d.ts"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@owlmeans/auth": "^0.1.0",
|
|
31
|
+
"@owlmeans/basic-envelope": "^0.1.0",
|
|
32
|
+
"@owlmeans/client": "^0.1.0",
|
|
33
|
+
"@owlmeans/client-auth": "^0.1.0",
|
|
34
|
+
"@owlmeans/client-flow": "^0.1.0",
|
|
35
|
+
"@owlmeans/client-i18n": "^0.1.0",
|
|
36
|
+
"@owlmeans/context": "^0.1.0",
|
|
37
|
+
"@owlmeans/flow": "^0.1.0",
|
|
38
|
+
"@owlmeans/module": "^0.1.0",
|
|
39
|
+
"@owlmeans/oidc": "^0.1.0",
|
|
40
|
+
"@owlmeans/resource": "^0.1.0",
|
|
41
|
+
"@owlmeans/web-client": "^0.1.0",
|
|
42
|
+
"@owlmeans/web-flow": "^0.1.0",
|
|
43
|
+
"oidc-client-ts": "^3.1.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@mui/material": "*",
|
|
47
|
+
"react": "*",
|
|
48
|
+
"react-router-dom": "*"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/react": "^18.3.11",
|
|
52
|
+
"nodemon": "^3.1.7",
|
|
53
|
+
"npm-check": "^6.0.1",
|
|
54
|
+
"typescript": "^5.6.3"
|
|
55
|
+
},
|
|
56
|
+
"private": false,
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
|
|
2
|
+
import { plugins as authPlugins } from '@owlmeans/client-auth/manager'
|
|
3
|
+
import { OIDC_CLIENT_AUTH } from '@owlmeans/oidc'
|
|
4
|
+
import { oidcClientPlugin } from './oidc-client.js'
|
|
5
|
+
|
|
6
|
+
authPlugins[OIDC_CLIENT_AUTH] = oidcClientPlugin
|
|
7
|
+
|
|
8
|
+
export const plugins = authPlugins
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
|
|
2
|
+
import type { AuthenticationPlugin } from '@owlmeans/client-auth/manager/plugins'
|
|
3
|
+
import { AUTH_SCOPE, AuthenticationStage, AuthManagerError, AuthRole } from '@owlmeans/auth'
|
|
4
|
+
import type { AuthCredentials } from '@owlmeans/auth'
|
|
5
|
+
import { OIDC_CLIENT_AUTH } from '@owlmeans/oidc'
|
|
6
|
+
import { useEffect } from 'react'
|
|
7
|
+
import LinearProgress from '@mui/material/LinearProgress'
|
|
8
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
9
|
+
import type { Config, Context, OidcAuthService } from '../../types.js'
|
|
10
|
+
import { useContext } from '@owlmeans/web-client'
|
|
11
|
+
import { DEFAULT_ALIAS, OidcAuthPurposes } from '../../consts.js'
|
|
12
|
+
import { OidcAuthStep, OidpAuthStep, UnknownFlowStep } from '@owlmeans/flow'
|
|
13
|
+
import { useModule } from '@owlmeans/client'
|
|
14
|
+
|
|
15
|
+
export const oidcClientPlugin: AuthenticationPlugin = {
|
|
16
|
+
type: OIDC_CLIENT_AUTH,
|
|
17
|
+
|
|
18
|
+
Implementation: Renderer => ({ type, stage, control }) => {
|
|
19
|
+
const context = useContext<Config, Context>()
|
|
20
|
+
Renderer = Renderer ?? oidcClientPlugin.Renderer
|
|
21
|
+
const module = useModule()
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
let canceled = false
|
|
25
|
+
|
|
26
|
+
// @TODO extract somewhere else and make it more consequential
|
|
27
|
+
// This way it looks too messy
|
|
28
|
+
switch (control.stage) {
|
|
29
|
+
case AuthenticationStage.Init:
|
|
30
|
+
control.hasPersistentState().then(async hasState => {
|
|
31
|
+
if (canceled) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
// 3. Properly process additional paramters on sequential rendering to restore control state
|
|
35
|
+
if (hasState) {
|
|
36
|
+
await control.restore()
|
|
37
|
+
await control.cleanUpState()
|
|
38
|
+
const flow = await control.flow()
|
|
39
|
+
if (flow != null) {
|
|
40
|
+
const state = await flow.state()
|
|
41
|
+
if ([OidcAuthStep.PostAuthen, OidpAuthStep.PostAuth].includes(state?.step().step as OidcAuthStep)) {
|
|
42
|
+
const url = new URL(window.location.href)
|
|
43
|
+
|
|
44
|
+
const auth: AuthCredentials = {
|
|
45
|
+
...control.allowance,
|
|
46
|
+
type,
|
|
47
|
+
challenge: control.allowance?.challenge ?? '',
|
|
48
|
+
credential: url.searchParams.toString(),
|
|
49
|
+
role: AuthRole.User,
|
|
50
|
+
userId: 'code',
|
|
51
|
+
scopes: [AUTH_SCOPE]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const tokenized = await control.authenticate(auth)
|
|
55
|
+
// @TODO Introduce some standard further flow in case this plugin/component
|
|
56
|
+
// is used without a callback
|
|
57
|
+
if (tokenized.token !== '') {
|
|
58
|
+
throw new AuthManagerError('callback')
|
|
59
|
+
}
|
|
60
|
+
return // @TODO Will it work here?
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 1. Initialize OIDC server side authentication
|
|
67
|
+
const oidc = context.service<OidcAuthService>(DEFAULT_ALIAS)
|
|
68
|
+
|
|
69
|
+
// @TODO we need to provide an identity provider client as entityId here for flexibel usage
|
|
70
|
+
const _source = await oidc.proceedToRedirectUrl({
|
|
71
|
+
purpose: control.source as OidcAuthPurposes ?? OidcAuthPurposes.Unknown,
|
|
72
|
+
uid: 'uid' in module.params ? `${module.params.uid}` : undefined,
|
|
73
|
+
alias: module.alias
|
|
74
|
+
})
|
|
75
|
+
const source = new URL(_source)
|
|
76
|
+
source.search = ''
|
|
77
|
+
await control.requestAllowence({ type, source: source.toString() })
|
|
78
|
+
})
|
|
79
|
+
case AuthenticationStage.Authenticate:
|
|
80
|
+
control.flow().then(async flow => {
|
|
81
|
+
if (canceled) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
const flowState = await flow?.state()
|
|
85
|
+
if (flowState == null) {
|
|
86
|
+
throw new UnknownFlowStep(AuthenticationStage.Authenticate)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (control.allowance?.challenge != null) {
|
|
90
|
+
const envelope = makeEnvelopeModel(control.allowance?.challenge, EnvelopeKind.Wrap)
|
|
91
|
+
const challenge = envelope.message<string>(true)
|
|
92
|
+
const parts = challenge.split(':http')
|
|
93
|
+
const url = 'http' + parts[1]
|
|
94
|
+
|
|
95
|
+
// 2. Include additional parameters (control state with allowance to flow state)
|
|
96
|
+
await control.persist()
|
|
97
|
+
|
|
98
|
+
document.location.href = url
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return () => { canceled = true }
|
|
104
|
+
}, [type, stage])
|
|
105
|
+
|
|
106
|
+
if (Renderer == null) {
|
|
107
|
+
throw new SyntaxError('Renderer is not defined for OIDC plugin')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return <Renderer type={type} stage={stage} control={control} params={module.params} />
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
Renderer: () => <LinearProgress />
|
|
114
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
import { DispatcherHOC } from '@owlmeans/client-auth'
|
|
3
|
+
import { useSearchParams } from 'react-router-dom'
|
|
4
|
+
import { useEffect } from 'react'
|
|
5
|
+
import { useContext } from '@owlmeans/web-client'
|
|
6
|
+
import { useI18nLib } from '@owlmeans/client-i18n'
|
|
7
|
+
import { AUTH_QUERY } from '@owlmeans/auth'
|
|
8
|
+
import { useFlow } from '@owlmeans/web-flow'
|
|
9
|
+
import { OidcAuthService } from '../types.js'
|
|
10
|
+
import { DEFAULT_ALIAS } from '../consts.js'
|
|
11
|
+
|
|
12
|
+
export const Dispatcher = DispatcherHOC(({ provideToken, navigate }) => {
|
|
13
|
+
const [query] = useSearchParams()
|
|
14
|
+
const context = useContext()
|
|
15
|
+
const client = useFlow()
|
|
16
|
+
|
|
17
|
+
const t = useI18nLib('auth', 'dispatcher')
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (client == null) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
const token = query.get(AUTH_QUERY)
|
|
24
|
+
const params: Record<string, string> = {}
|
|
25
|
+
query.forEach((value, key) => {
|
|
26
|
+
if (key !== AUTH_QUERY) {
|
|
27
|
+
params[key] = value
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
if (token != null) {
|
|
32
|
+
// This is required for compatibility with a standard OwlMeans Auth flow.
|
|
33
|
+
provideToken({ token }, params)
|
|
34
|
+
} else {
|
|
35
|
+
const oidc = context.service<OidcAuthService>(DEFAULT_ALIAS)
|
|
36
|
+
oidc.dispatch(params).then(async dispatched => {
|
|
37
|
+
if (dispatched) {
|
|
38
|
+
return await navigate()
|
|
39
|
+
}
|
|
40
|
+
if (client == null) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
const redirect = await oidc.authenticate(client.flow(), params)
|
|
44
|
+
if (redirect != null && redirect !== '') {
|
|
45
|
+
document.location.href = redirect
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
const authzToken = await context.auth().authenticated()
|
|
49
|
+
if (authzToken == null) {
|
|
50
|
+
provideToken({ token: '' }, undefined)
|
|
51
|
+
} else {
|
|
52
|
+
await navigate()
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
}, [client])
|
|
57
|
+
|
|
58
|
+
return query.has(AUTH_QUERY)
|
|
59
|
+
? <div>{t('loading')}</div>
|
|
60
|
+
: undefined
|
|
61
|
+
})
|
package/src/consts.ts
ADDED
package/src/guard.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { OidcGuardOptions } from '@owlmeans/oidc'
|
|
2
|
+
import type { Config, Context } from './types.js'
|
|
3
|
+
import type { CommonModule } from '@owlmeans/module'
|
|
4
|
+
import {
|
|
5
|
+
appendOidcGuard as appendBasicOidcGuard,
|
|
6
|
+
setupOidcGuard as setupBasicOidcGuard,
|
|
7
|
+
DISPATCHER_OIDC, DISPATCHER_OIDC_INIT
|
|
8
|
+
} from '@owlmeans/oidc'
|
|
9
|
+
import { elevate } from '@owlmeans/web-client'
|
|
10
|
+
import { DISPATCHER } from '@owlmeans/auth'
|
|
11
|
+
import { handler } from '@owlmeans/client'
|
|
12
|
+
import { Dispatcher } from './components/dispatcher.js'
|
|
13
|
+
import { makeOidcAuthService } from './service.js'
|
|
14
|
+
|
|
15
|
+
export const appendOidcGuard = <C extends Config, T extends Context<C>>(
|
|
16
|
+
context: T, opts?: OidcGuardOptions
|
|
17
|
+
) => {
|
|
18
|
+
context.registerService(makeOidcAuthService())
|
|
19
|
+
|
|
20
|
+
const ctx = appendBasicOidcGuard<C, T>(context, opts)
|
|
21
|
+
|
|
22
|
+
return ctx
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const setupOidcGuard = (modules: CommonModule[], coguards?: string | string[]) => {
|
|
26
|
+
setupBasicOidcGuard(modules, coguards)
|
|
27
|
+
|
|
28
|
+
elevate(modules, DISPATCHER_OIDC_INIT)
|
|
29
|
+
elevate(modules, DISPATCHER_OIDC)
|
|
30
|
+
elevate(modules, DISPATCHER, handler(Dispatcher), { force: true })
|
|
31
|
+
}
|