diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 2d664db..74e1432 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -1,11 +1,11 @@ /** * @author fenris */ -type int = number; +declare type int = number; /** * @author fenris */ -type float = number; +declare type float = number; declare var process: any; declare var require: any; declare class Buffer { @@ -22,7 +22,7 @@ declare namespace lib_plankton.base { /** * @author fenris */ -type type_pseudopointer = { +declare type type_pseudopointer = { value: type_value; }; /** @@ -2186,7 +2186,7 @@ declare namespace lib_plankton.storage.memory { clear(): Promise; write(key: any, value: any): Promise; delete(key: any): Promise; - read(key: any): Promise>; + read(key: any): Promise; search(term: any): Promise<{ key: string; preview: string; @@ -4175,7 +4175,7 @@ declare namespace lib_plankton.auth.oidc { */ export type type_subject = { parameters: type_parameters; - state: {}; + cases: Record; }; /** */ diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index bd4afd2..2c7cfb2 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -1568,7 +1568,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { + while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -6564,7 +6564,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { + while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -9886,7 +9886,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { + while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -13940,7 +13940,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { + while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -14771,12 +14771,12 @@ var lib_plankton; (function (oidc) { /** */ - let enum_state_label; - (function (enum_state_label) { - enum_state_label["idle"] = "idle"; - enum_state_label["wait"] = "wait"; - enum_state_label["ready"] = "ready"; - })(enum_state_label || (enum_state_label = {})); + let enum_condition; + (function (enum_condition) { + enum_condition["idle"] = "idle"; + enum_condition["wait"] = "wait"; + enum_condition["ready"] = "ready"; + })(enum_condition || (enum_condition = {})); ; /** */ @@ -14796,26 +14796,38 @@ var lib_plankton; ?? "OIDC"), }, - "state": {} + "cases": {} }; } oidc.make = make; /** * @see https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest */ - function authorization_url(subject) { - return lib_plankton.url.encode(Object.assign(lib_plankton.url.decode(subject.parameters.url_authorization), { + function authorization_url(subject, state) { + const url = lib_plankton.url.encode(Object.assign(lib_plankton.url.decode(subject.parameters.url_authorization), { "query": lib_plankton.www_form.encode({ "response_type": "code", "client_id": subject.parameters.client_id, // "client_secret": subject.parameters.client_secret, "scope": subject.parameters.scopes.join(" "), - "state": lib_plankton.random.generate_guid(), + "state": state, "redirect_uri": subject.parameters.url_redirect, }) })); + return url; } oidc.authorization_url = authorization_url; + /** + */ + function prepare_login(subject) { + const state = lib_plankton.random.generate_guid(); + subject.cases[state] = {}; + return { + "state": state, + "authorization_url": authorization_url(state), + }; + } + oidc.prepare_login = prepare_login; /** * https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest */ @@ -14890,20 +14902,26 @@ var lib_plankton; /** */ async function handle_authorization_callback(subject, cookie, stuff) { - if (("error" in stuff) - || - (!("code" in stuff)) - || - (cookie === null)) { - return Promise.reject(new Error("failed")); + const state = stuff["state"]; + if (!(state in subject.cases)) { + return Promise.reject(new Error("no case for this state")); } else { - const token = await token_call(subject, cookie, stuff["code"]); - const userinfo = await userinfo_call(subject, cookie, token); - return Promise.resolve({ - "token": token, - "userinfo": userinfo, - }); + if (("error" in stuff) + || + (!("code" in stuff)) + || + (cookie === null)) { + return Promise.reject(new Error("failed")); + } + else { + const token = await token_call(subject, cookie, stuff["code"]); + const userinfo = await userinfo_call(subject, cookie, token); + return Promise.resolve({ + "token": token, + "userinfo": userinfo, + }); + } } } oidc.handle_authorization_callback = handle_authorization_callback; diff --git a/source/api/actions/session_oidc.ts b/source/api/actions/session_oidc.ts index 5a08a3a..d609537 100644 --- a/source/api/actions/session_oidc.ts +++ b/source/api/actions/session_oidc.ts @@ -56,8 +56,8 @@ namespace _zeitbild.api name : (null | string); email : (null | string); }; - } = await lib_plankton.auth.oidc.handle_authorization_callback( - _zeitbild.auth.oidc_subject(), + redirect_uri_template : string; + } = await _zeitbild.auth.oidc_handle_authorization_callback( (stuff.headers["Cookie"] ?? stuff.headers["cookie"] ?? null), stuff.query_parameters ); @@ -94,7 +94,6 @@ namespace _zeitbild.api } } ); - const redirect_uri_template : string = _zeitbild.auth.oidc_get_redirect_uri_template("foo"); return Promise.resolve( { "status_code": 200, @@ -102,7 +101,7 @@ namespace _zeitbild.api "", { "url": lib_plankton.string.coin( - redirect_uri_template, + data.redirect_uri_template, { "session_key": session_key, } diff --git a/source/auth.ts b/source/auth.ts index 7862241..7613cd4 100644 --- a/source/auth.ts +++ b/source/auth.ts @@ -11,6 +11,13 @@ namespace _zeitbild.auth ) = null; + + /** + */ + let _subject_oidc : (null | lib_plankton.auth.oidc.type_subject) = null; + + + /** */ let _oidc_redict_uri_template_map : ( @@ -20,30 +27,6 @@ namespace _zeitbild.auth ) = 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( @@ -54,12 +37,6 @@ namespace _zeitbild.auth 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); } } @@ -88,6 +65,22 @@ lib_plankton.log.info( break; } case "oidc": { + _subject_oidc = 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, + } + ); _oidc_redict_uri_template_map = lib_plankton.map.simplemap.implementation_map( lib_plankton.map.simplemap.make( ) @@ -113,21 +106,21 @@ lib_plankton.log.info( { 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")); + if (_subject_oidc === null) { + throw (new Error("not initialized yet")); } else { + const stuff : {state : string; authorization_url : string;} = lib_plankton.auth.oidc.prepare_login(_subject_oidc); _oidc_redict_uri_template_map.set( - "foo", // TODO proper key + stuff.state, input["oidc_redirect_uri_template"] ); return Promise.resolve( { "kind": "oidc", "data": { - "url": lib_plankton.auth.oidc.authorization_url(subject), - "label": subject.parameters.label, + "url": stuff.authorization_url, + "label": _zeitbild.conf.get().authentication.data.label, } } ); @@ -157,31 +150,48 @@ lib_plankton.log.info( /** */ - export function execute( - input : any - ) : Promise + export function oidc_handle_authorization_callback( + cookie : (null | string), + data : Record + ) : Promise< + { + token : string; + userinfo : { + name : (null | string); + email : (null | string); + }; + redirect_uri_template : string; + } + > { - if (_subject === null) { - return Promise.reject(new Error("not initialized yet")); - } - else { - return _subject.login_execute(input); - } - } - - - /** - */ - export function control( - input : any - ) : Promise - { - if (_subject === null) { - return Promise.reject(new Error("not initialized yet")); - } - else { - return _subject.login_control(input); - } + const state : string = data["state"]; + const result : { + token : string; + userinfo : { + name : (null | string); + email : (null | string); + }; + } = await lib_plankton.auth.oidc.handle_authorization_callback( + _oidc_subject, + cookie, + data + ); + return Promise.resolve< + { + token : string; + userinfo : { + name : (null | string); + email : (null | string); + }; + redirect_uri_template : string; + } + >( + { + "token": result.token, + "userinfo": result.userinfo, + "redirect_uri_template": _oidc_redict_uri_template_map.get(state), + } + ) } }