Compare commits
5 commits
d46c48e326
...
b55b26dd20
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b55b26dd20 | ||
![]() |
8eb279b376 | ||
![]() |
44e6f638ba | ||
![]() |
bf8919f7a7 | ||
![]() |
6521f60601 |
6 changed files with 124 additions and 87 deletions
10
lib/plankton/plankton.d.ts
vendored
10
lib/plankton/plankton.d.ts
vendored
|
@ -4320,7 +4320,7 @@ declare namespace lib_plankton.auth.oidc {
|
|||
*/
|
||||
export type type_subject = {
|
||||
parameters: type_parameters;
|
||||
state: {};
|
||||
cases: Record<string, {}>;
|
||||
};
|
||||
/**
|
||||
*/
|
||||
|
@ -4328,7 +4328,13 @@ declare namespace lib_plankton.auth.oidc {
|
|||
/**
|
||||
* @see https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||
*/
|
||||
export function authorization_url(subject: type_subject): string;
|
||||
export function authorization_url(subject: type_subject, state: string): string;
|
||||
/**
|
||||
*/
|
||||
export function prepare_login(subject: type_subject): {
|
||||
state: string;
|
||||
authorization_url: string;
|
||||
};
|
||||
/**
|
||||
*/
|
||||
export function handle_authorization_callback(subject: type_subject, cookie: (null | string), stuff: Record<string, string>): Promise<{
|
||||
|
|
|
@ -15246,12 +15246,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 = {}));
|
||||
;
|
||||
/**
|
||||
*/
|
||||
|
@ -15271,26 +15271,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(subject, state),
|
||||
};
|
||||
}
|
||||
oidc.prepare_login = prepare_login;
|
||||
/**
|
||||
* https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
|
||||
*/
|
||||
|
@ -15365,6 +15377,11 @@ var lib_plankton;
|
|||
/**
|
||||
*/
|
||||
async function handle_authorization_callback(subject, cookie, stuff) {
|
||||
const state = stuff["state"];
|
||||
if (!(state in subject.cases)) {
|
||||
return Promise.reject(new Error("no case for this state"));
|
||||
}
|
||||
else {
|
||||
if (("error" in stuff)
|
||||
||
|
||||
(!("code" in stuff))
|
||||
|
@ -15381,6 +15398,7 @@ var lib_plankton;
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
oidc.handle_authorization_callback = handle_authorization_callback;
|
||||
})(oidc = auth.oidc || (auth.oidc = {}));
|
||||
})(auth = lib_plankton.auth || (lib_plankton.auth = {}));
|
||||
|
|
|
@ -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
|
|||
"<html><head><meta http-equiv=\"refresh\" content=\"0; url={{url}}\" /></head><body></body></html>",
|
||||
{
|
||||
"url": lib_plankton.string.coin(
|
||||
redirect_uri_template,
|
||||
data.redirect_uri_template,
|
||||
{
|
||||
"session_key": session_key,
|
||||
}
|
||||
|
|
125
source/auth.ts
125
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) || (_oidc_redict_uri_template_map === 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,30 +150,52 @@ lib_plankton.log.info(
|
|||
|
||||
/**
|
||||
*/
|
||||
export function execute(
|
||||
input : any
|
||||
) : Promise<string>
|
||||
export async function oidc_handle_authorization_callback(
|
||||
cookie : (null | string),
|
||||
data : Record<string, string>
|
||||
) : Promise<
|
||||
{
|
||||
if (_subject === null) {
|
||||
return Promise.reject(new Error("not initialized yet"));
|
||||
token : string;
|
||||
userinfo : {
|
||||
name : (null | string);
|
||||
email : (null | string);
|
||||
};
|
||||
redirect_uri_template : string;
|
||||
}
|
||||
>
|
||||
{
|
||||
if ((_subject_oidc === null) || (_oidc_redict_uri_template_map === null)) {
|
||||
throw (new Error("not initialized yet"));
|
||||
}
|
||||
else {
|
||||
return _subject.login_execute(input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function control(
|
||||
input : any
|
||||
) : Promise<void>
|
||||
const state : string = data["state"];
|
||||
const result : {
|
||||
token : string;
|
||||
userinfo : {
|
||||
name : (null | string);
|
||||
email : (null | string);
|
||||
};
|
||||
} = await lib_plankton.auth.oidc.handle_authorization_callback(
|
||||
_subject_oidc,
|
||||
cookie,
|
||||
data
|
||||
);
|
||||
return Promise.resolve<
|
||||
{
|
||||
if (_subject === null) {
|
||||
return Promise.reject(new Error("not initialized yet"));
|
||||
token : string;
|
||||
userinfo : {
|
||||
name : (null | string);
|
||||
email : (null | string);
|
||||
};
|
||||
redirect_uri_template : string;
|
||||
}
|
||||
else {
|
||||
return _subject.login_control(input);
|
||||
>(
|
||||
{
|
||||
"token": result.token,
|
||||
"userinfo": result.userinfo,
|
||||
"redirect_uri_template": _oidc_redict_uri_template_map.get(state),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
todo.md
1
todo.md
|
@ -9,5 +9,4 @@
|
|||
- Termin-Eigenschaft "öffentlich"
|
||||
- optional: Kalender-Eigenschaft: "neue Termine standard-mäßig öffentlich"
|
||||
- CalDAV-Export
|
||||
- Caching
|
||||
- OIDC session mapping ordentlich machen
|
||||
|
|
|
@ -28,7 +28,7 @@ def main():
|
|||
"--build-directory",
|
||||
type = str,
|
||||
dest = "build_directory",
|
||||
default = "build",
|
||||
default = "/tmp/zeitbild",
|
||||
metavar = "<build-directory>",
|
||||
help = "directory to where the build was put",
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue