From f488ba11bce424706481f7761e6281330675a297 Mon Sep 17 00:00:00 2001 From: Jos Groot Lipman Date: Thu, 16 Mar 2017 19:46:30 +0000 Subject: [PATCH] DJIN#36213 SAML/Authenticatie verbeteringen. svn path=/Website/trunk/; revision=33179 --- APPL/API2/api2.inc | 40 ++++++-- APPL/API2/model_fac_idp.inc | 25 ++++- APPL/API2/model_fac_idp_map.inc | 72 +++++++++++++++ APPL/API2/model_fac_sp.inc | 159 ++++++++++++++++++++++++++++++++ APPL/API2/model_fac_sp_map.inc | 71 ++++++++++++++ APPL/API2/model_prs_perslid.inc | 29 +++--- APPL/AUT/Login.inc | 155 +++++++++++++++++-------------- APPL/AUT/loginTry.asp | 97 ++++++++++++++++++- APPL/MGT/fac_sp.asp | 43 +++++++++ APPL/MGT/prs_perslid.asp | 2 +- 10 files changed, 590 insertions(+), 103 deletions(-) create mode 100644 APPL/API2/model_fac_idp_map.inc create mode 100644 APPL/API2/model_fac_sp.inc create mode 100644 APPL/API2/model_fac_sp_map.inc create mode 100644 APPL/MGT/fac_sp.asp diff --git a/APPL/API2/api2.inc b/APPL/API2/api2.inc index 8a49487dd5..8ed3ce89ba 100644 --- a/APPL/API2/api2.inc +++ b/APPL/API2/api2.inc @@ -732,10 +732,28 @@ api2 = { switch (field.typ) { case "key": // De foreign keys action { "id": "5", "name": "afhalen" } - if (newval && typeof newval == "object" && "id" in newval) - { // dereference - newval = newval.id; - jsondata[fld] = newval; + if (newval && typeof newval == "object") + { + if ("id" in newval) + { // dereference + newval = newval.id; + jsondata[fld] = newval; + } + else if ("name" in newval && field.foreign && typeof field.foreign != 'function') + { + if (typeof field.foreign == 'string') + { + field.foreign = foreignKeyTable(field.foreign); + } + if (field.foreign.desc_is_unique) // Dan mag je die bij saven ook opgeven + { + field.typ = "sql"; + newval = "(SELECT {0} FROM {1} WHERE {2} = {3})".format(field.foreign.key, + field.foreign.tbl, + field.foreign.desc, + safe.quoted_sql(newval.name)); + } + } } break; case "date": @@ -1433,8 +1451,10 @@ function generic_REST_POST(model, gparams) { params.isNew = true; // negeer eventuele bestaande keys if (model.autfunction !== false) + { var autparams = user.checkAutorisation(model.autfunction); - user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); + user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); + } if ("disc_params" in model) { @@ -1496,8 +1516,10 @@ function generic_REST_PUT(model, gparams) return function _generic_REST_PUT(params, jsondata, the_key) { if (model.autfunction !== false) + { var autparams = user.checkAutorisation(model.autfunction); - user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); + user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); + } if ("disc_params" in model) { @@ -1524,6 +1546,8 @@ function generic_REST_PUT(model, gparams) if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); + var inctrack = api2.process_includes(params, this, jsondata, the_key); + if ("disc_params" in model) { // Nu de one-on-one tabel @@ -1546,8 +1570,10 @@ function generic_REST_DELETE(model, gparams) return function _generic_REST_DELETE(params, the_key) { if (model.autfunction !== false) + { var autparams = user.checkAutorisation(model.autfunction); - user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); + user.auth_required_or_abort(autparams.PRSwritelevel < 9 && autparams.ALGwritelevel < 9); + } if (model.soft_delete) { diff --git a/APPL/API2/model_fac_idp.inc b/APPL/API2/model_fac_idp.inc index 2ded4004df..5175e7df6f 100644 --- a/APPL/API2/model_fac_idp.inc +++ b/APPL/API2/model_fac_idp.inc @@ -7,6 +7,9 @@ Notes: Documentatie in de wiki onder Authenticeren */ +%> + +<% function fac_idp() { this.records_name = "identityproviders"; @@ -17,6 +20,8 @@ function fac_idp() this.record_title = L("fac_idp"); this.records_title = L("fac_idp_m"); + this.askfirst = "type"; + this.fields = { "id": { "dbs": "fac_idp_key", @@ -40,6 +45,7 @@ function fac_idp() "label": L("fac_idp_type"), "typ": "key", "required": true, + "insertonly": true, "LOV": L("fac_idp_typeLOV") }, "remark": { @@ -107,21 +113,26 @@ function fac_idp() "label": L("fac_idp_ipauto"), "typ": "check0" }, -/* + "autocreate": { + "dbs": "fac_idp_autocreate", + "label": L("fac_idp_autocreate"), + "typ": "key", + "required": "true", + "LOV": "0;Weigeren bij onbekend;1;Aanmaken;2;Alleen bijwerken;3;Aanmaken en bijwerken" ///L("fac_idp_autocreateLOV") + }, "company": { "dbs": "prs_bedrijf_key", "typ": "key", "foreign": "prs_bedrijf", "label": L("lcl_idp_company") - } - , + }, "department": { "dbs": "prs_afdeling_key", "typ": "key", "foreign": "prs_afdeling", "label": L("lcl_idp_department") }, - "authorization": { +/* "authorization": { "dbs": "fac_functie_key", "label": L("fac_idp_functie_key"), "typ": "key", @@ -135,6 +146,12 @@ function fac_idp() "readonly": true } } + this.includes = + {"idpmappings": { model: new model_fac_idp_map(), + joinfield: "identityprovider", + enable_update: true + } + }; this.REST_GET = generic_REST_GET(this); this.REST_POST = generic_REST_POST(this); diff --git a/APPL/API2/model_fac_idp_map.inc b/APPL/API2/model_fac_idp_map.inc new file mode 100644 index 0000000000..77d0150e6a --- /dev/null +++ b/APPL/API2/model_fac_idp_map.inc @@ -0,0 +1,72 @@ +<% /* + $Revision$ + $Id$ + + File: model_fac_idp_map.inc + Description: + Notes: +*/ + +function model_fac_idp_map() +{ + this.records_name = "idpmappings"; + this.record_name = "idpmapping"; + this.table = "fac_idp_map"; + this.primary = "fac_idp_map_key"; + this.autfunction = "WEB_FACFAC"; + this.record_title = L("fac_idp_map"); + this.records_title = L("fac_idp_map_m"); + + this.fields = { + "id": { + "dbs": "fac_idp_map_key", + "label": L("lcl_key"), + "typ": "key", + "seq": "fac_s_fac_idp_map_key" + }, + "identityprovider": { + "dbs": "fac_idp_key", + "label": L("fac_idp"), + "typ": "key", + "hidden_fld": true, + "required": true + }, + "identify": { + "dbs": "fac_idp_map_identify", + "label": L("fac_idp_map_identify"), + "typ": "check0" + }, + "name": { + "dbs": "fac_idp_map_to", + "label": L("fac_idp_map_to"), + "typ": "key", + "required": true, + "LOV": "1;Login;2;Achternaam;3;Voornaam;4;E-mail;5;Afdeling;6;Kostenplaats;7;Functie;100;*Werkplekken;101;*Authorisatiegroepen" ///L("fac_idp_map_toLOV") + }, + "from": { + "dbs": "fac_idp_map_from", + "label": L("fac_idp_map_from"), + "typ": "varchar", + "required": true + }, + "default": { + "dbs": "fac_idp_map_default", + "label": L("fac_idp_map_default"), + "typ": "varchar" + } + } + + this.edit = { + "modal": true + }; + + this.list = { + "columns": ["identify", "name", "from", "default"] + }; + + this.REST_GET = generic_REST_GET(this); + this.REST_POST = generic_REST_POST(this); + this.REST_PUT = generic_REST_PUT(this); + this.REST_DELETE = generic_REST_DELETE(this); +} +%> \ No newline at end of file diff --git a/APPL/API2/model_fac_sp.inc b/APPL/API2/model_fac_sp.inc new file mode 100644 index 0000000000..5d4957c508 --- /dev/null +++ b/APPL/API2/model_fac_sp.inc @@ -0,0 +1,159 @@ +<% /* + $Revision$ + $Id$ + + File: model_fac_sp.inc + Description: + Notes: +*/ + +%> + +<% +function fac_sp() +{ + this.records_name = "identityproviders"; + this.record_name = "identityprovider"; + this.table = "fac_sp"; + this.primary = "fac_sp_key"; + this.autfunction = "WEB_FACFAC"; + this.record_title = L("fac_sp"); + this.records_title = L("fac_sp_m"); + + this.fields = { + "id": { + "dbs": "fac_sp_key", + "label": L("lcl_key"), + "typ": "key", + "seq": "fac_s_fac_sp_key" + }, + "code": { + "dbs": "fac_sp_code", + "label": L("fac_sp_code"), + "typ": "varchar" + }, + "name": { + "dbs": "fac_sp_omschrijving", + "label": L("fac_sp_omschrijving"), + "typ": "varchar", + "required": true + }, + "type": { + "dbs": "fac_sp_type", + "label": L("fac_sp_type"), + "typ": "key", + "required": true, + "LOV": L("fac_idp_typeLOV") // TODO? + }, + "remark": { + "dbs": "fac_sp_opmerking", + "label": L("fac_sp_opmerking"), + "typ": "memo" + }, + "secret": { + "dbs": "fac_sp_secret", + "label": L("fac_sp_secret"), + "typ": "varchar", + "defaultvalue": shared.random(32), + "secret": true + }, + "audience": { + "dbs": "fac_sp_audience", + "label": L("fac_sp_audience"), + "typ": "varchar", + "placeholder": customerId + ".facilitor.nl" + }, + "issuer": { + "dbs": "fac_sp_issuer", + "label": L("fac_sp_issuer"), + "typ": "varchar" + }, + "algorithm": { + "dbs": "fac_sp_algorithm", + "label": L("fac_sp_algorithm"), + "typ": "varchar" + }, + "timeout": { + "dbs": "fac_sp_clockskew", + "label": L("fac_sp_clockskew"), + "typ": "number", + "defaultvalue": 30 + }, + "duration": { + "dbs": "fac_sp_duration", + "label": L("fac_sp_duration"), + "typ": "number" + }, + "remoteloginurl": { + "dbs": "fac_sp_remote_loginurl", + "label": L("fac_sp_remote_loginurl"), + "typ": "varchar" + }, + "remotelogouturl": { + "dbs": "fac_sp_remote_logouturl", + "label": L("fac_sp_remote_logouturl"), + "typ": "varchar" + }, + "usermapping": { + "dbs": "fac_sp_usermapping", + "label": L("fac_sp_usermapping"), + "typ": "varchar" + }, + "ipfilter": { + "dbs": "fac_sp_ipfilter", + "label": L("fac_sp_ipfilter"), + "typ": "varchar" + }, + "_currentIP" : { + "dbs": "", + "label": "Current IP", + "typ": "label", + "labelvalue": String(Request.ServerVariables("REMOTE_ADDR")) + }, + "ipauto": { + "dbs": "fac_sp_ipauto", + "label": L("fac_sp_ipauto"), + "typ": "check0" + }, +/* + "company": { + "dbs": "prs_bedrijf_key", + "typ": "key", + "foreign": "prs_bedrijf", + "label": L("lcl_idp_company") + } + , + "department": { + "dbs": "prs_afdeling_key", + "typ": "key", + "foreign": "prs_afdeling", + "label": L("lcl_idp_department") + }, + "authorization": { + "dbs": "fac_functie_key", + "label": L("fac_sp_functie_key"), + "typ": "key", + "foreign": "fac_functie" + }, +*/ + "internal": { + "dbs": "fac_sp_internal", + "label": L("fac_sp_internal"), + "typ": "check0", + "readonly": true + } + } + + this.includes = + {"spmappings": { model: new model_fac_sp_map(), + joinfield: "serviceprovider", + enable_update: true + } + }; + + this.REST_GET = generic_REST_GET(this); + this.REST_POST = generic_REST_POST(this); + this.REST_PUT = generic_REST_PUT(this); + this.REST_DELETE = generic_REST_DELETE(this); +} +%> \ No newline at end of file diff --git a/APPL/API2/model_fac_sp_map.inc b/APPL/API2/model_fac_sp_map.inc new file mode 100644 index 0000000000..50b4a7e834 --- /dev/null +++ b/APPL/API2/model_fac_sp_map.inc @@ -0,0 +1,71 @@ +<% /* + $Revision$ + $Id$ + + File: model_fac_sp_map.inc + Description: Door sp 'released attributes' + Notes: +*/ + +function model_fac_sp_map() +{ + this.records_name = "idpappings"; + this.record_name = "idpapping"; + this.table = "fac_sp_map"; + this.primary = "fac_sp_map_key"; + this.autfunction = "WEB_FACFAC"; + this.record_title = L("fac_sp_map"); + this.records_title = L("fac_sp_map_m"); + + this.fields = { + "id": { + "dbs": "fac_sp_map_key", + "label": L("lcl_key"), + "typ": "key", + "seq": "fac_s_fac_sp_map_key" + }, + "serviceprovider": { + "dbs": "fac_sp_key", + "label": L("fac_sp"), + "typ": "key", + "hidden_fld": true, + "required": true + }, + "name": { + "dbs": "fac_sp_map_from", + "label": L("fac_sp_map_from"), + "typ": "key", + "required": true, + "LOV": "1;" + L("lcl_prs_person_login") + + ";2;" + L("lcl_prs_person_achternaam") + + ";3;" + L("lcl_prs_person_voornaam") + + ";4;" + L("lcl_prs_person_email") + + ";5;" + L("lcl_prs_organisatie") + + ";6;" + L("lcl_account") + + ";7;" + L("lcl_prs_person_function") + + ";8;" + L("lcl_lcl_taal") + + ";100;" + L("lcl_workplace") + + ";101;" + L("fac_groeprechten_m") + }, + "to": { + "dbs": "fac_sp_map_to", + "label": L("fac_sp_map_to"), + "typ": "varchar", + "required": true + } + } + + this.edit = { + "modal": true + }; + + this.list = { + "columns": ["name", "to"] + }; + + this.REST_GET = generic_REST_GET(this); + this.REST_POST = generic_REST_POST(this); + this.REST_PUT = generic_REST_PUT(this); + this.REST_DELETE = generic_REST_DELETE(this); +} +%> \ No newline at end of file diff --git a/APPL/API2/model_prs_perslid.inc b/APPL/API2/model_prs_perslid.inc index 58cf29b372..fef7fe55a0 100644 --- a/APPL/API2/model_prs_perslid.inc +++ b/APPL/API2/model_prs_perslid.inc @@ -33,7 +33,7 @@ function genderLOV() return s; } -function model_persons() +function model_prs_perslid() { this.records_name = "persons"; this.record_name = "person"; @@ -55,14 +55,14 @@ function model_persons() this.primary = "prs_perslid_key"; this.record_title = L("prs_perslid"); this.records_title = L("prs_perslid_m"); - + this.autfunction = false; // we controleren zelf this.fields = { "id": { "dbs": "prs_perslid_key", "label": L("lcl_key"), "typ": "key", - "filter": "exact" + "seq": "prs_s_prs_alluitvoerende_keys" }, "name": { "dbs": "pf.prs_perslid_naam_friendly", @@ -152,13 +152,15 @@ function model_persons() "foreign": { "tbl": "prs_srtperslid", "key": "prs_srtperslid_key", - "desc": "prs_srtperslid_omschrijving" + "desc": "prs_srtperslid_omschrijving", + "desc_is_unique": true } }, "department": { "dbs": "prs_afdeling_key", "label": L("lcl_prs_organisatie"), - "typ": "key", "foreign": "prs_afdeling" + "typ": "key", + "foreign": "prs_afdeling" }, "company": { "dbs": "pa.prs_bedrijf_key", @@ -198,7 +200,6 @@ function model_persons() "model": new model_fac_gebruikersgroep(), "joinfield": "person", "multiadd": "authorizationgroup" - }, "customfields" : { "model": new model_custom_fields(this, "PRS", { readman: true, readuse: true, pNiveau: "P" }), @@ -274,17 +275,9 @@ function model_persons() return json; }; - this.PUT = function (params) /* update perslid */ - { - // Nog niet ondersteund - }; - this.POST = function (params) /* new perslid */ - { - // Nog niet ondersteund - }; - this.DELETE = function (params) /* delete perslid */ - { - // Nog niet ondersteund - }; + + this.REST_POST = generic_REST_POST(this); + this.REST_PUT = generic_REST_PUT(this); + this.REST_DELETE = generic_REST_DELETE(this); } %> \ No newline at end of file diff --git a/APPL/AUT/Login.inc b/APPL/AUT/Login.inc index 9f359e1378..6250736e4a 100644 --- a/APPL/AUT/Login.inc +++ b/APPL/AUT/Login.inc @@ -42,14 +42,14 @@ function doLogin(prs_key, params) if (deze.has("WEB_FACFAC") && !params.isFACFACinternal) { __DoLog("Illegal login WEB_FACFAC"); - shared.internal_error("This IDP cannot be used for users with WEB_FACFAC (prs_key={0}).".format(prs_key)); + shared.internal_error("IDP '{0}' cannot be used for users with WEB_FACFAC (prs_key={1}).".format(params.idp_code, prs_key)); } // Als fac_idp_internal aan staat mag alleen je alleen SSO doen naar een FACFAC gebruiker // Tenzij S("idp_internal_anyuser") true is, dan mag je toch naar iedereen // Dat doen we op OTA via custenc.wsc, dat doen we niet in PROD if (params.isFACFACinternal && !S("idp_internal_anyuser") && !deze.has("WEB_FACFAC")) { - shared.internal_error("This IDP can only be used for users with WEB_FACFAC (prs_key={0}).".format(prs_key)); + shared.internal_error("IDP '{0}' can only be used for users with WEB_FACFAC (prs_key={1}).".format(params.idp_code, prs_key)); } } @@ -958,90 +958,107 @@ function IntegratedSSO() } // aud is identificatie van de partij die de informatie *wil weten* -// of het is een hash van usermapping, iss, aud en secret -// dat gebruiken we hardcoded vanuit login_save.asp -function jwt_create(perslid_key, aud_or_prop) +function jwt_create(perslid_key, aud) { var thisPrs = new Perslid(perslid_key) var params = aud_or_prop; - if (typeof aud_or_prop == "string") // dan is het een audience naam - { - var sql = "SELECT *" - + " FROM fac_sp" - + " WHERE fac_sp_audience = " + safe.quoted_sql(aud); // TODO ook issuer meenemen? - var oRs = Oracle.Execute(sql); - if (oRs.Eof) - shared.internal_error("Service provider for '{0}' is not configured for {1}".format(aud, customerId)); - params = { + var sp_key = -1; + + var sql = "SELECT *" + + " FROM fac_sp" + + " WHERE fac_sp_audience = " + safe.quoted_sql(aud); // TODO ook issuer meenemen? + var oRs = Oracle.Execute(sql); + if (oRs.Eof) + shared.internal_error("Service provider for '{0}' is not configured for {1}".format(aud, customerId)); + sp_key = oRs("fac_sp_key").value; + var params = { usermapping: oRs("fac_sp_usermapping").Value, iss: oRs("fac_sp_issuer").Value, aud: aud, secret: oRs("fac_sp_secret").Value }; - oRs.Close(); - } + oRs.Close(); var claim = { - jti: "#" + (perslid_key) + "#" + new Date().getTime() + jti: "#" + (perslid_key) + "#" + new Date().getTime(), + iat: Math.round(new Date().getTime() / 1000), + iss: params.iss, + aud: params.aud } - // usermapping bevat de attributen die wij vrijgeven voor deze SP - // Het kunnen er meerdere zijn gescheiden door een komma. - // Het is telkens in het formaat 'username->username' waarbij de linker - // usernaam onze interne code is (zie verderop de switch) en de rechter - // username hoe hij in de jwt genoemd wordt. Als ze gelijk zijn volstaat - // gewoon 'username' - // TODO: Beter gewoon JSON formaat doen? - var usermapping = params.usermapping || "preferred_username->username"; - var arr = usermapping.split(","); - for (var i = 0; i < arr.length; i++) + // fac_sp_map bevat de attributen die wij vrijgeven voor deze SP + + if (sp_key > 0) { - var spl = arr[i].split('->'); - var attr = spl[0]; - if (spl.length > 1) - var clm = spl[1] - else - clm = attr; - switch (attr) + var sql = "SELECT *" + + " FROM fac_sp_map" + + " WHERE fac_sp_key = " + sp_key; + var oRs = Oracle.Execute(sql); + while (!oRs.Eof) { - // Zo veel mogelijk volgens http://openid.net/specs/openid-connect-basic-1_0.html#StandardClaims - case "preferred_username": - claim[clm] = thisPrs.oslogin(); - break; - case "sub": claim[clm] = String(perslid_key); // Als enige gegarandeerd en blijvend uniek voor deze issuer - break; // http://openid.net/specs/openid-connect-basic-1_0.html#ClaimStability - case "given_name": claim[clm] = thisPrs.prs_perslid_voornaam(); - break; - case "family_name": claim[clm] = thisPrs.prs_perslid_achternaam(); - break; - case "middle_name": claim[clm] = thisPrs.prs_perslid_tussenvoegsel(); - break; - case "name": claim[clm] = thisPrs.naam(); - break; - case "email": claim[clm] = thisPrs.prs_perslid_email(); - break; - case "gender": claim[clm] = { "0": "female", "1": "male" }[thisPrs.prs_perslid_geslacht()] || ""; - break; - case "locale": claim[clm] = { "nl": "nl-NL", // RFC5646 - "en": "en-GB", - "de": "de-DE", - "fr": "fr-FR", - "no": "nn-NO", - "sv": "sv-SE", - "da": "da-DK", - "fi": "fi-FI" }[String(thisPrs.dblang()).toLowerCase()] || ""; - break; - case "zoneinfo": claim[clm] = thisPrs.prs_perslid_timezone(); - break; + var clm = oRs("fac_sp_map_to").Value; // zo gaat hij heten in de JWT + switch (oRs("fac_sp_map_from").Value) // zie model_fac_sp_map.inc voor codering + { + // Zo veel mogelijk volgens http://openid.net/specs/openid-connect-basic-1_0.html#StandardClaims + case 1: claim[clm] = thisPrs.oslogin(); + break; + case "sub": claim[clm] = String(perslid_key); // Als enige gegarandeerd en blijvend uniek voor deze issuer + break; // http://openid.net/specs/openid-connect-basic-1_0.html#ClaimStability + case 3: claim[clm] = thisPrs.prs_perslid_voornaam(); + break; + case 2: claim[clm] = thisPrs.prs_perslid_achternaam(); + break; +// case "middle_name": claim[clm] = thisPrs.prs_perslid_tussenvoegsel(); +// break; +// case "name": claim[clm] = thisPrs.naam(); +// break; + case 4: claim[clm] = thisPrs.prs_perslid_email(); + break; +// case "gender": claim[clm] = { "0": "female", "1": "male" }[thisPrs.prs_perslid_geslacht()] || ""; +// break; + case "locale": claim[clm] = { "nl": "nl-NL", // RFC5646 + "en": "en-GB", + "de": "de-DE", + "fr": "fr-FR", + "no": "nn-NO", + "sv": "sv-SE", + "da": "da-DK", + "fi": "fi-FI" }[String(thisPrs.dblang()).toLowerCase()] || ""; + break; +// case "zoneinfo": claim[clm] = thisPrs.prs_perslid_timezone(); +// break; + // de custom claims + case 101: /* fclt_authorization */ + var sql = "SELECT fac_groep_omschrijving" + + " FROM fac_gebruikersgroep fgg, fac_groep fg" + + " WHERE fgg.fac_groep_key = fg.fac_groep_key" + + " AND SUBSTR(fac_groep_omschrijving, 1, 1) <> '_'" + + " AND prs_perslid_key = " + user_key; + var oRs2 = Oracle.Execute(sql); + var aarr = []; + while (!oRs2.Eof) + { + aarr.push(oRs2("fac_groep_omschrijving").value); + oRs2.MoveNext(); + } + oRs2.Close(); + claim[clm] = aarr.join("|"); + break; + case 100: /* fclt_occupation */ + var wps = user.werkplekken(); + var warr = []; + for (var i2 = 0; i2 < wps.length; i2++) + warr.push(wps[i2].prs_werkplek_aanduiding()); + claim[clm] = warr.join("|"); + break; + } + oRs.MoveNext(); } + oRs.Close(); } - - claim.iat = Math.round(new Date().getTime() / 1000); - claim.iss = params.iss; - claim.aud = params.aud; - + __Log(claim); return jwt_encode(claim, params.secret); } @@ -1178,7 +1195,7 @@ function trySSO(ssocode) } if (!ip_ok) - shared.internal_error("IP {0} not allowed for this IDP".format(ip)); // TODO of 400 code forbidden? + shared.internal_error("IP {0} not allowed for IDP '{0}'".format(ip, ssocode)); // TODO of 400 code forbidden? if (oRs("fac_idp_type").Value == 3) // Oldstyle SecureSSO, die doet het verder zelf { diff --git a/APPL/AUT/loginTry.asp b/APPL/AUT/loginTry.asp index d0806d63b1..610d4a17ed 100644 --- a/APPL/AUT/loginTry.asp +++ b/APPL/AUT/loginTry.asp @@ -24,6 +24,8 @@ if (Response.Expires > 0) + + <% __Log("== Entering loginTry.asp =="); @@ -137,6 +139,7 @@ if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && jwt) } // en claim.jit registreren/ controleren in fac_session + var idp_code = oRs("fac_idp_code").Value; var isFACFACinternal = oRs("fac_idp_internal").Value != 0; if (isFACFACinternal && !claim.payload.fclt_realuser && !by_bearer) { @@ -147,26 +150,111 @@ if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && jwt) if (claim.payload.username) // je mag username meegeven { settings.overrule_setting("login_use_email", 0); - tryLogin(claim.payload.username, null, { noPassword: true, noFacSession: by_bearer, isFACFACinternal: isFACFACinternal }); + tryLogin(claim.payload.username, null, { noPassword: true, idp_code: idp_code, noFacSession: by_bearer, isFACFACinternal: isFACFACinternal }); if (user_key < 0) __DoLog("JWT Claimed username not found: {0}".format(claim.payload.username)) } if (user_key < 0 && claim.payload.email) // je mag email meegeven { settings.overrule_setting("login_use_email", 1); - tryLogin(claim.payload.email, null, { noPassword: true, noFacSession: by_bearer, isFACFACinternal: isFACFACinternal }); + tryLogin(claim.payload.email, null, { noPassword: true, noFacSession: by_bearer, idp_code: idp_code, isFACFACinternal: isFACFACinternal }); if (user_key < 0) __DoLog("JWT Claimed email not found: {0}".format(claim.payload.email)) } if (user_key < 0 && claim.payload.perslid_key > 0) { - doLogin(claim.payload.perslid_key, { noFacSession: by_bearer, isFACFACinternal: isFACFACinternal }); // je mag ook key meegeven + doLogin(claim.payload.perslid_key, { noFacSession: by_bearer, idp_code: idp_code, isFACFACinternal: isFACFACinternal }); // je mag ook key meegeven if (user_key < 0) - __DoLog("JWT Claimed perslid_key not found: {0}".format(claim.payload.perslid_key)) + __DoLog("JWT Claimed perslid_key not found: {0}".format(claim.payload.perslid_key)); + } + + if ( user_key < 0 && oRs("fac_idp_autocreate").Value & 1 // Misschien dan maar aanmaken? + || user_key > 0 && oRs("fac_idp_autocreate").Value & 2 // en/ of bijwerken + ) + { + __Log("JWT user automatically created with data:"); + __Log(claim.payload); + + // Tot nu toe waren we nog anoniem. Om personen aan te maken of bij te werken + // (via de API) mogen we echt(er) niet meer anoniem zijn. + // De API2 controleert daar (terecht) op +// /*global*/ user_key = 33083; // Moet PRSSYS hebben +// /*global*/ user = new Perslid(user_key); + + var person = new model_prs_perslid(); + var persdata = {}; + var sql = "SELECT *" + + " FROM fac_idp_map" + + " WHERE fac_idp_key = " + oRs("fac_idp_key").Value; + var oRsMap = Oracle.Execute(sql); + while (!oRsMap.Eof) + { + var val = oRsMap("fac_idp_map_default").Value; + if (oRsMap("fac_idp_map_from").Value in claim.payload) + val = claim.payload[oRsMap("fac_idp_map_from").Value]; + switch (oRsMap("fac_idp_map_to").Value) // zie model_fac_idp_map.inc voor codering + { + case 1: persdata["login"] = val; break; + case 2: persdata["lastname"] = val; break; + case 3: persdata["firstname"] = val; break; + case 4: persdata["email"] = val; break; + case 5: if (val) persdata["department"] = { name: val }; break; + // kostenplaats case 6: persdata["costcenter"] = { name: val }; break; + case 7: if (val) persdata["function"] = { name: val }; break; + //case 100: persdata.werkplekken = val; break; + case 101: persdata.authorisation = val; break; + } + + oRsMap.MoveNext(); + } + oRsMap.Close(); + if (!("department" in persdata)) + persdata["department"] = oRs("prs_afdeling_key").Value; // dan moet die ingevuld zijn + + var persparams = {}; + + if (user_key > 0) // bijwerken + { + person.REST_PUT( persparams, persdata, user_key ); + } + else // nieuwe + { + var res = person.REST_POST( persparams, persdata); +// user = user_key = null; + __DoLog("Created user '{0} {1}' with key {2} for idp '{3}'".format(persdata["firstname"], persdata["lastname"], res.key, idp_code)); + doLogin(res.key, { noFacSession: by_bearer, idp_code: idp_code, isFACFACinternal: isFACFACinternal }); + } + // Nu authorisatie groepen nog bijwerken + // Via het model was me even iets te hoog gegrepen: ik zou toch (nog) de id's er bij moeten halen + if ("authorisation" in persdata) + { + var autharr = persdata["authorisation"].toLowerCase().split("|"); + var sql = "DELETE FROM fac_gebruikersgroep" + + " WHERE prs_perslid_key = " + user_key + + " AND fac_groep_key NOT IN (SELECT fac_groep_key " + + " FROM fac_groep" + + " WHERE LOWER(fac_groep_omschrijving) IN ({0})".format(safe.quoted_sql_join(autharr)) + + " OR SUBSTR(fac_groep_omschrijving, 1, 1) = '_'" // Die blijven altijd + + " )"; + Oracle.Execute(sql); + var sql = "INSERT INTO fac_gebruikersgroep(prs_perslid_key, fac_groep_key)" + + " SELECT " + user_key + ", fac_groep_key" + + " FROM fac_groep fg" + + " WHERE LOWER(fac_groep_omschrijving) IN ({0})".format(safe.quoted_sql_join(autharr)) + + " AND SUBSTR(fac_groep_omschrijving, 1, 1) <> '_'" // Die nooit + + " AND NOT EXISTS (SELECT 1" + + " FROM fac_gebruikersgroep fg2" + + " WHERE fg2.fac_groep_key = fg.fac_groep_key" + + " AND fg2.prs_perslid_key = " + user_key + ")"; + Oracle.Execute(sql); + } + // TODO: werkplekken verwerken } if (user_key > 0) { + // TODO: Als prs_perslid_credentials_datum > claim.payload.iat dan toch niet accepteren + if (!oRs("fac_idp_duration").Value) // single use tokens wil ik niet weer zien { // ook al zijn ze alleen geldig van -clockskew tot +clockskew // Ongeldige lukken de volgende keer ook niet. Geldige wil ik niet weer zien @@ -191,6 +279,7 @@ if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && jwt) // Onthouden hoe je bent binnengekomen zodat logout naar logout_url kan leiden Session("idp_key") = oRs("fac_idp_key").Value; + oRs.Close(); // nu niet meer nodig if (claim.payload.fclt_realuser) shared.trackaction("PRSLOG", user_key, L("lcl_logged_on_sso").format(claim.payload.fclt_realuser, Request.ServerVariables("REMOTE_ADDR"))); diff --git a/APPL/MGT/fac_sp.asp b/APPL/MGT/fac_sp.asp new file mode 100644 index 0000000000..b8a3314019 --- /dev/null +++ b/APPL/MGT/fac_sp.asp @@ -0,0 +1,43 @@ +<%@language = "javascript" %> +<% /* + $Revision$ + $Id$ + + File: fac_sp.asp + + Description: + + Context: + + Notes: +*/ +%> + + + +<% +var this_model = new fac_sp(); + +scaffolding(this_model, + { + "search": { + "autosearch": true, + "filters": [ + "name", + "action" + ] + }, + "list": { + "columns": [ + "id", + "code", + "name", + "type", + "remoteloginurl" + ] + }, + "edit": { + "modal": false + } + }); +%> diff --git a/APPL/MGT/prs_perslid.asp b/APPL/MGT/prs_perslid.asp index 86087d7480..37a9f1ab8e 100644 --- a/APPL/MGT/prs_perslid.asp +++ b/APPL/MGT/prs_perslid.asp @@ -16,7 +16,7 @@ if (mode == 'list') { Oracle.Execute("alter session set nls_comp = 'LINGUISTIC' NLS_SORT = 'BINARY_AI'"); // Zodat müller gevonden wordt } -var this_model = new model_persons(); +var this_model = new model_prs_perslid(); scaffolding(this_model, {