diff --git a/source/api/actions/session_oidc.ts b/source/api/actions/session_oidc.ts index 389f51c..5a08a3a 100644 --- a/source/api/actions/session_oidc.ts +++ b/source/api/actions/session_oidc.ts @@ -50,40 +50,68 @@ namespace _zeitbild.api "response_body_encode": (output => Buffer.from(output)), "restriction": restriction_none, "execution": async (stuff) => { - _zeitbild.auth.control( - { - "kind": "authorization_callback", - "data": { - "stuff": stuff.query_parameters, - "cookie": (stuff.headers["Cookie"] ?? stuff.headers["cookie"]), - } - } + const data : { + token : string; + userinfo : { + name : (null | string); + email : (null | string); + }; + } = await lib_plankton.auth.oidc.handle_authorization_callback( + _zeitbild.auth.oidc_subject(), + (stuff.headers["Cookie"] ?? stuff.headers["cookie"] ?? null), + stuff.query_parameters ); - return ( - _zeitbild.auth.execute( - undefined - ) - .then( - (name) => lib_plankton.session.begin(name) - ) - .then( - (session_key) => Promise.resolve({ + if (data.userinfo.name === null) { + return Promise.reject( + new Error( + "IDP did not return user name" + ) + ); + } + else { + try { + await _zeitbild.service.user.add( + { + "name": data.userinfo.name, + "email_address": data.userinfo.email, + } + ); + lib_plankton.log.info( + "user_provisioned", + { + "name": data.userinfo.name, + } + ); + } + catch (error) { + // do nothing + } + const session_key : string = await lib_plankton.session.begin( + data.userinfo.name, + { + "data": { + "oidc_token": data.token, + } + } + ); + const redirect_uri_template : string = _zeitbild.auth.oidc_get_redirect_uri_template("foo"); + return Promise.resolve( + { "status_code": 200, "data": lib_plankton.string.coin( "", { - // TODO: get url from frontend "url": lib_plankton.string.coin( - "http://localhost:8888/#oidc_finish,session_key={{session_key}}", + redirect_uri_template, { "session_key": session_key, } ), } ), - }) - ) - ); + } + ); + } }, } ); diff --git a/source/api/actions/session_prepare.ts b/source/api/actions/session_prepare.ts index d284a4d..e76e225 100644 --- a/source/api/actions/session_prepare.ts +++ b/source/api/actions/session_prepare.ts @@ -9,17 +9,14 @@ namespace _zeitbild.api ) : void { lib_plankton.rest.register< - { - name : string; - password : string; - }, + any, { kind : string; data : any; } >( rest_subject, - lib_plankton.http.enum_method.get, + lib_plankton.http.enum_method.post, "/session/prepare", { "description": "gibt die nötigen Werkzeuge für eine Anmeldung aus", @@ -30,8 +27,8 @@ namespace _zeitbild.api "nullable": false }), "restriction": restriction_none, - "execution": async () => { - const preparation = await _zeitbild.auth.prepare(); + "execution": async (stuff) => { + const preparation = await _zeitbild.auth.prepare(stuff.input); return Promise.resolve({ "status_code": 200, "data": preparation, diff --git a/source/auth.ts b/source/auth.ts index ec8da0c..7862241 100644 --- a/source/auth.ts +++ b/source/auth.ts @@ -11,6 +11,60 @@ namespace _zeitbild.auth ) = null; + /** + */ + let _oidc_redict_uri_template_map : ( + null + | + lib_plankton.map.type_map + ) = null; + + + /** + */ + export function oidc_subject( + ) + { + return lib_plankton.auth.oidc.make( + { + "url_authorization": _zeitbild.conf.get().authentication.data.url_authorization, + "url_token": _zeitbild.conf.get().authentication.data.url_token, + "url_userinfo": _zeitbild.conf.get().authentication.data.url_userinfo, + "client_id": _zeitbild.conf.get().authentication.data.client_id, + "client_secret": _zeitbild.conf.get().authentication.data.client_secret, + "url_redirect": (_zeitbild.conf.get().authentication.data.backend_url_base + "/session/oidc"), + "scopes": [ + "openid", + "profile", + "email", + ], + "label": _zeitbild.conf.get().authentication.data.label, + } + ); + } + + + /** + */ + export function oidc_get_redirect_uri_template( + key : string + ) : string + { + if (_oidc_redict_uri_template_map === null) { + throw (new Error("apparently not initialized yet")); + } + else { +lib_plankton.log.info( + "oidc_redirect_uri_templates", + { + "val": lib_plankton.map.dump(_oidc_redict_uri_template_map), + } +); + return _oidc_redict_uri_template_map.get(key); + } + } + + /** */ export function init( @@ -34,23 +88,12 @@ namespace _zeitbild.auth break; } case "oidc": { - _subject = lib_plankton.auth.oidc.implementation_auth( - { - "url_authorization": _zeitbild.conf.get().authentication.data.url_authorization, - "url_token": _zeitbild.conf.get().authentication.data.url_token, - "url_userinfo": _zeitbild.conf.get().authentication.data.url_userinfo, - "client_id": _zeitbild.conf.get().authentication.data.client_id, - "client_secret": _zeitbild.conf.get().authentication.data.client_secret, - "url_redirect": (_zeitbild.conf.get().authentication.data.backend_url_base + "/session/oidc"), - "scopes": [ - "openid", - "profile", - "email", - ], - "label": _zeitbild.conf.get().authentication.data.label, - "login_url_mode": "log", - } + _oidc_redict_uri_template_map = lib_plankton.map.simplemap.implementation_map( + lib_plankton.map.simplemap.make( + ) ); + // TODO + return Promise.resolve(undefined); break; } default: { @@ -65,21 +108,49 @@ namespace _zeitbild.auth /** */ export function prepare( + input : any ) : Promise<{kind : string; data : any;}> { - if (_subject === null) { - return Promise.reject(new Error("not initialized yet")); - } - else { - return ( - _subject.login_prepare() - .then( - (data : any) => ({ - "kind": _zeitbild.conf.get().authentication.kind, - "data": data, - }) - ) - ); + switch (_zeitbild.conf.get().authentication.kind) { + case "oidc": { + const subject : lib_plankton.auth.oidc.type_subject = oidc_subject(); + if (_oidc_redict_uri_template_map === null) { + throw (new Error("apparently not initialized yet")); + } + else { + _oidc_redict_uri_template_map.set( + "foo", // TODO proper key + input["oidc_redirect_uri_template"] + ); + return Promise.resolve( + { + "kind": "oidc", + "data": { + "url": lib_plankton.auth.oidc.authorization_url(subject), + "label": subject.parameters.label, + } + } + ); + } + break; + } + default: { + if (_subject === null) { + return Promise.reject(new Error("not initialized yet")); + } + else { + return ( + _subject.login_prepare() + .then( + (data : any) => ({ + "kind": _zeitbild.conf.get().authentication.kind, + "data": data, + }) + ) + ); + } + break; + } } } @@ -99,6 +170,8 @@ namespace _zeitbild.auth } + /** + */ export function control( input : any ) : Promise