diff --git a/APPL/API2/api2_rest.inc b/APPL/API2/api2_rest.inc index a9de034620..249952b0c1 100644 --- a/APPL/API2/api2_rest.inc +++ b/APPL/API2/api2_rest.inc @@ -18,47 +18,22 @@ var DEZE = this; api2_rest = { authenticate: function _authenticate() { - var APIKEY; - if (S("fac_api_key_in_url")) - APIKEY = getQParam("APIKEY", ""); - if (!APIKEY && Request.ServerVariables("HTTP_X_FACILITOR_API_KEY").Count) - APIKEY = String(Request.ServerVariables("HTTP_X_FACILITOR_API_KEY")); // Meegegeven als X-FACILITOR-API-Key - - if (!APIKEY && Session("user_key") > 0) + var method = String(Request.ServerVariables("REQUEST_METHOD")); + if (method != "GET" && Session("stateless") != 1) // Vereis dan wel het CSRF token { - user_key = Session("user_key"); // Hierdoor is de API intern te gebruiken zonder authenticatie - var method = String(Request.ServerVariables("REQUEST_METHOD")); - if (method != "GET") // Vereis dan wel het CSRF token - { - var token = Request.ServerVariables("HTTP_X_CSRF_TOKEN").Count // Meegegeven als X-CSRF-TOKEN - ? String(Request.ServerVariables("HTTP_X_CSRF_TOKEN")) - : ""; - protectRequest.validateToken(token); - } + var token = Request.ServerVariables("HTTP_X_CSRF_TOKEN").Count // Meegegeven als X-CSRF-TOKEN + ? String(Request.ServerVariables("HTTP_X_CSRF_TOKEN")) + : ""; + protectRequest.validateToken(token); } - else + if (user_key < 0) { - if (Session("user_key") > 0) - {} // Tijdens ontwikkeling heb je soms in tweede tab de GUI open. Laat dat ongemoeid. - else - Session.Abandon(); // Altijd, voor de zekerheid - - var sql = "SELECT prs_perslid_key, prs_perslid_naam, prs_perslid_oslogin" - + " FROM prs_perslid" - + " WHERE prs_perslid_verwijder IS NULL" - + " AND prs_perslid_apikey = " + safe.quoted_sql(APIKEY); - var oRs = Oracle.Execute(sql); - if (oRs.Eof || !APIKEY) - { - Response.Status = "401 Unauthorized"; - // Sommige applicaties kunnen in reactie hierop een b64 encoded username:password sturen - // Die onderscheppen wij in LoginTry.asp uiteindelijk - if (S("basic_auth_realm")) - Response.AddHeader("WWW-Authenticate", "Basic realm=\"" + S("basic_auth_realm") + "\""); - Response.End; - }; - __Log("API2 User is: {0} ({1})".format(oRs("prs_perslid_naam").Value, oRs("prs_perslid_oslogin").Value)); - /* global */ user_key = oRs("prs_perslid_key").Value; + Response.Status = "401 Unauthorized"; + // Sommige applicaties kunnen in reactie hierop een b64 encoded username:password sturen + // Die onderscheppen wij in LoginTry.asp uiteindelijk + if (S("basic_auth_realm")) + Response.AddHeader("WWW-Authenticate", "Basic realm=\"" + S("basic_auth_realm") + "\""); + Response.End; if (typeof NO_ADDHEADER == "undefined" && Request.Servervariables("HTTP_FCLT_VERSION").Count > 0) { // wordt opgepikt door FCLTAPI.DLL voor in de logging en daarna gestript. Niet in Fiddler dus @@ -93,7 +68,6 @@ api2_rest = { oRs.Close() } - /* global */ user = new Perslid(user_key); // wordt mogelijk nog overruled door imporsonate CheckForLogging(Request.QueryString("logging")); // Nu pas kan autorisatie via user gecontroleerd worden }, diff --git a/APPL/API2/model_aut_idp_map.inc b/APPL/API2/model_aut_idp_map.inc index d89c6d495a..1d9fa1e090 100644 --- a/APPL/API2/model_aut_idp_map.inc +++ b/APPL/API2/model_aut_idp_map.inc @@ -53,6 +53,7 @@ function model_aut_idp_map(params) + ";9;" + L("lcl_prs_person_email") + ";10;" + L("lcl_prs_person_phone") + ";11;" + L("lcl_prs_person_mobile") + + ";12;" + L("prs_perslid_externid") // De foreign's + ";20;" + L("lcl_prs_person_function") diff --git a/APPL/API2/model_prs_perslid.inc b/APPL/API2/model_prs_perslid.inc index c4fd49a70a..324cb50de8 100644 --- a/APPL/API2/model_prs_perslid.inc +++ b/APPL/API2/model_prs_perslid.inc @@ -92,7 +92,7 @@ function model_prs_perslid(params) "label": L("lcl_prs_person_initials"), "typ": "varchar" }, - "prefix": { + "middlename": { "dbs": "prs_perslid_tussenvoegsel", "label": L("lcl_prs_person_tussen"), "typ": "varchar" @@ -169,6 +169,11 @@ function model_prs_perslid(params) "typ": "key", "foreign": "prs_afdeling" }, + "externalid": { + "dbs": "prs_perslid_externid", + "label": L("prs_perslid_externid"), + "typ": "varchar" + }, "company": { "dbs": "pa.prs_bedrijf_key", "label": L("lcl_prs_company"), diff --git a/APPL/AUT/Login.inc b/APPL/AUT/Login.inc index 260842bf1c..c2c04d3982 100644 --- a/APPL/AUT/Login.inc +++ b/APPL/AUT/Login.inc @@ -18,6 +18,7 @@ <% // Elders is prs_key geauthenticeerd. Registreer die hier als de actieve gebruiker. +// stateless komen we hier al niet function doLogin(prs_key, params) { __Log("==== doLogin " + prs_key); @@ -67,12 +68,6 @@ function doLogin(prs_key, params) } } - // Alvast nieuwe user_key loggen zodat je ziet wie er inlogt. - if (typeof NO_ADDHEADER == "undefined" && user_key != prs_key && Request.Servervariables("HTTP_FCLT_VERSION").Count > 0) - { // wordt opgepikt door FCLTAPI.DLL voor in de logging en daarna gestript. Niet in Fiddler te zien dus - Response.AddHeader ("FCLT_USERID", customerId + "\\" + String(prs_key)); - } - /* global */ user_key = prs_key; //user_lang = oRs(1).Value; // globale moet er nog uit! if (typeof LCL_Disable == "undefined") @@ -99,7 +94,7 @@ function doLogin(prs_key, params) var agent = String(Request.ServerVariables("HTTP_USER_AGENT")); // Welbeschouwd gebruiken we het volgende FAC_SESSION record nooit, we werken - // altijd met ASPSESSION==>IIS SESSION==>user_key + // altijd met ASPSESSION cookie==>IIS SESSION==>user_key var sql = "INSERT INTO fac_session" + " (fac_session_sessionid_hash," + " prs_perslid_key," @@ -180,16 +175,6 @@ function doLogin(prs_key, params) + " )"; Oracle.Execute(sql, true); } - else - { - __Log("Welcome.asp expired?"); - var sql = "DELETE FROM fac_menu" - + " WHERE fac_menu_altgroep = 5" - + " AND fac_menu_alturl = " + safe.quoted_sql(S("fac_firstlogin_url")) - + " AND prs_perslid_key = " + user_key - + " AND fac_menu_aanmaak < SYSDATE - " + S("fac_firstlogin_expire"); - Oracle.Execute(sql, true); - } var fac_lang = getQParamSafe("fac_lang", "").toUpperCase(); // overrule via param // Liever geen session maar m_connections heeft dit al nodig voor zijn fac.initsession @@ -200,6 +185,14 @@ function doLogin(prs_key, params) return true; } +function doLoginStateless(prs_key, params) +{ + /* global */ user_key = prs_key; + Session("user_key") = user_key; // Nu ben je pas *echt* ingelogd + /* global */ user = new Perslid(user_key); // wordt mogelijk nog overruled door imporsonate + Session("stateless") = 1; + Session.Abandon(); // Altijd, voor de zekerheid +} // Session.Abondon is gevaarlijk: dan verlies je ook CustomerID etc. // Bovendien krijg je met IIS dan nog steeds geen nieuwe ASPSESSIONID @@ -258,7 +251,7 @@ function makeSessionCookie (sessionData) + "fac.makehash(" + safe.quoted_sql(sessionId) + "), " + user_key + ", " + safe.quoted_sql(sessionData) + ", " - + " sysdate + " + S("login_remember_days") + ", " // sessie timeout op een half jaar. + + " sysdate + " + S("login_remember_days") + ", " // sessie timeout op 30 dagen. + safe.quoted_sql(agent, 256) + "," + safe.quoted_sql(ip, 64) + " )" Oracle.Execute(sql); @@ -440,7 +433,7 @@ function testpassword(prs_key, wachtwoord, pmobile) oRs.Close(); if (!found) return false; - // else TODO upgraden! + // else iets verderop upgraden! var workfactor = 0; } else // new style @@ -487,11 +480,11 @@ function setpassword(prs_key, wachtwoord, expired) { var passsalt = shared.random(32); var workfactor = S("prs_password_hash_factor"); - var is_hash = pbkdf2(wachtwoord, passsalt, workfactor); + var new_hash = pbkdf2(wachtwoord, passsalt, workfactor); var sql = "UPDATE prs_perslid" // Ooit expire op SYSDATE + fac.getsetting ('prs_password_expiration') als die is gevuld + " SET prs_perslid_wachtwoord_exp = " + (expired?"SYSDATE":"NULL") + " , prs_perslid_salt = " + safe.quoted_sql(passsalt) - + " , prs_perslid_wachtwoord_hash = " + safe.quoted_sql('1${0}${1}'.format(workfactor, is_hash)) + + " , prs_perslid_wachtwoord_hash = " + safe.quoted_sql('1${0}${1}'.format(workfactor, new_hash)) + " WHERE prs_perslid_key = " + prs_key; Oracle.Execute(sql); } @@ -505,7 +498,6 @@ function testotp (prs_key, otprequest) + " WHERE prs_perslid_key = " + prs_key; var oRs = Oracle.Execute(sql); - var otpsecret = oRs("prs_perslid_otpsecret").Value; var otpcounter = oRs("prs_perslid_otpcounter").Value || -1; oRs.Close(); @@ -549,6 +541,7 @@ function verify_otp (prs_key, otprequest, otpsecret, otpcounter) return otp_oke; } +// Op basis van usernaam/wachtwoord gaan we iemand authenticeren function getIdentity(username, wachtwoord, params) { var result = { success: false, fail_reason: L("lcl_login_wrong") }; @@ -622,9 +615,9 @@ function getIdentity(username, wachtwoord, params) { logins.push(" upper(prs_perslid_email) = " + safe.quoted_sql_upper(username)); } - else if (getQParam("API", "")) + else if (getQParam("API", "") || getQParam("API2", "")) { - logins.push(" prs_perslid_apikey = " + safe.quoted_sql_upper(username, 128)); + logins.push(" prs_perslid_apikey = " + safe.quoted_sql(username, 128)); // TODO zorgen dat result.stateless gezet raakt wachtwoord = null; } else @@ -653,6 +646,7 @@ function getIdentity(username, wachtwoord, params) var oSLNKDWF = new ActiveXObject("SLNKDWF.About"); var sleepmsec = Math.min(80000, tmicro / 1000 * 32); oSLNKDWF.Sleep(sleepmsec); + oRs.Close(); return result; } @@ -660,7 +654,7 @@ function getIdentity(username, wachtwoord, params) var otpcounter = oRs("prs_perslid_otpcounter").Value || -1; var found = false; - if (/* nog niet vanuit SAML/default.asp params.noPassword && */ wachtwoord == null) // SSO + if (/* nog niet vanuit SAML/default.asp params.noPassword && */ wachtwoord === null) // SSO found = true; // En zijn we verder wel klaar else found = testpassword(oRs("prs_perslid_key").Value, wachtwoord, params.mobile); @@ -735,7 +729,12 @@ function tryLogin(username, wachtwoord, params) return false; if (ident.user_key > 0) - doLogin(ident.user_key, params); + { + if (ident.stateless || params.stateless) + doLoginStateless(ident.user_key, params); + else + doLogin(ident.user_key, params); + } return true; } @@ -1015,11 +1014,6 @@ function SimpleSSO() __Log('User#2a = '+username); } if (username !='' && username!='undefined') { - // Strip domain name - while( (i = username.indexOf('\\')) >= 0 ) { - l = username.length; - if( i < l-1 ) username = username.substring(i+1,l); - } tryLogin(username, null, { noPassword: true }); } } @@ -1047,11 +1041,6 @@ function IntegratedSSO() } if (username !='' && username!='UNDEFINED') { - // Strip domain name - while( (i = username.indexOf('\\')) >= 0 ) { - l = username.length; - if( i < l-1 ) username = username.substring(i+1,l); - } tryLogin(username, null, { noPassword: true }); } } @@ -1370,14 +1359,14 @@ function process_claim(claim, idp_data, params) { case 1: // login settings.overrule_setting("login_use_email", 0); - tryLogin(claim[idpm.from], null, { noPassword: true, idp_code: idp_data.code, noFacSession: params.by_bearer, isFACFACinternal: isFACFACinternal }); + tryLogin(claim[idpm.from], null, { noPassword: true, idp_code: idp_data.code, stateless: params.by_bearer, isFACFACinternal: isFACFACinternal }); break; case 9: // email settings.overrule_setting("login_use_email", 1); - tryLogin(claim[idpm.from], null, { noPassword: true, idp_code: idp_data.code, noFacSession: params.by_bearer, isFACFACinternal: isFACFACinternal }); + tryLogin(claim[idpm.from], null, { noPassword: true, idp_code: idp_data.code, stateless: params.by_bearer, isFACFACinternal: isFACFACinternal }); break; case 99: // internal, prs_perslid_key - doLogin(parseInt(claim[idpm.from], 10), { noFacSession: params.by_bearer, idp_code: idp_data.code, isFACFACinternal: isFACFACinternal }); + doLogin(parseInt(claim[idpm.from], 10), { stateless: params.by_bearer, idp_code: idp_data.code, isFACFACinternal: isFACFACinternal }); break; default: if (idpm.name.id > 1000) // Flexkenmerk @@ -1394,7 +1383,7 @@ function process_claim(claim, idp_data, params) var oRs = Oracle.Execute(sql); if (!oRs.Eof) { - doLogin(oRs("prs_perslid_key").Value, { noFacSession: params.by_bearer, idp_code: idp_data.code, isFACFACinternal: isFACFACinternal }); + doLogin(oRs("prs_perslid_key").Value, { stateless: params.by_bearer, idp_code: idp_data.code, isFACFACinternal: isFACFACinternal }); } oRs.Close(); } @@ -1414,218 +1403,225 @@ function process_claim(claim, idp_data, params) || user_key > 0 && idp_data.autocreate.id & 2 // en/ of bijwerken ) { - var persdata = { }; - for (var i =0; i < idp_data.idpmappings.length; i++) - { - var idpm = idp_data.idpmappings[i]; - var val = idpm["default"]; - if (idpm.from in claim) - val = claim[idpm.from]; + process_claim_update(claim, idp_data, params) + } +} - switch (idpm.name.id) // zie model_aut_idp_map.inc voor codering +function process_claim_update(claim, idp_data, params) +{ + var isFACFACinternal = idp_data.internal != 0; + var persdata = { }; + for (var i =0; i < idp_data.idpmappings.length; i++) + { + var idpm = idp_data.idpmappings[i]; + var val = idpm["default"]; + if (idpm.from in claim) + val = claim[idpm.from]; + + switch (idpm.name.id) // zie model_aut_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["middlename"] = val; break; + case 5: persdata["initials"] = val; break; + case 6: persdata["gender"] = val; break; + case 7: persdata["phone"] = val; break; + case 8: persdata["title"] = val; break; + case 9: persdata["email"] = val; break; + case 10: persdata["phone"] = val; break; + case 11: persdata["mobile"] = val; break; + case 12: persdata["externalid"] = val; break; + // de foreigns + case 20: if (val) + persdata["function"] = { name: val }; break; // Kan omdat fields.function.desc_is_unique is gezet + case 21: if (val) // afdeling { - case 1: persdata["login"] = val; break; - case 2: persdata["lastname"] = val; break; - case 3: persdata["firstname"] = val; break; - case 4: persdata["prefix"] = val; break; - case 5: persdata["initials"] = val; break; - case 6: persdata["gender"] = val; break; - case 7: persdata["phone"] = val; break; - case 8: persdata["title"] = val; break; - case 9: persdata["email"] = val; break; - case 10: persdata["phone"] = val; break; - case 11: persdata["mobile"] = val; break; - // de foreigns - case 20: if (val) - persdata["function"] = { name: val }; break; // Kan omdat fields.function.desc_is_unique is gezet - case 21: if (val) // afdeling + // Zoek afdeling + var sql = "SELECT prs_afdeling_key" + + " FROM prs_v_afdeling" + + " WHERE prs_afdeling_verwijder IS NULL" + + " AND prs_afdeling_upper = " + safe.quoted_sql_upper(val); + if (idp_data.department) { - // Zoek afdeling - var sql = "SELECT prs_afdeling_key" - + " FROM prs_v_afdeling" - + " WHERE prs_afdeling_verwijder IS NULL" - + " AND prs_afdeling_upper = " + safe.quoted_sql_upper(val); - if (idp_data.department) - { - sql += " AND prs_afdeling_parentkey = " + idp_data.department.id; - } - else - { - if (idp_data.company) - sql += " AND prs_bedrijf_key = " + idp_data.company.id; - } - var oRs = Oracle.Execute(sql); - if (oRs.Eof) - { - __Log("Claimed department {0} not found".format(val)); - // Er komt eventueel wel een fallback naar idp_data.department.id - } - else - { - var afd_key = oRs("prs_afdeling_key").Value; - oRs.MoveNext(); - if (!oRs.Eof) - shared.internal_error("Claimed department {0} not unique".format(val)); - - persdata["department"] = afd_key; - } - oRs.Close(); - break; - } - // De 1-n - case 100: persdata.authorisation = val; break; - case 101: persdata.workplace = val; break; - // case 102: persdata.workplacevirtual = val; break; - // case 103: reserved voor mandatering? - default: - if (idpm.name.id > 1000) - set_custom_field(persdata, idpm.name.id - 1000, val, "C"); - break; - } - } - // Klantspecifieke check functie (hookfunction) voor de invoer - var pResult = new HookResult(); - if (!custfunc.aut_process_claim(persdata, claim, idp_data, pResult)) - { - abort_with_warning(pResult.errmsg); - } - - if (!("department" in persdata)) - { - if (!idp_data.department) - shared.internal_error("Department is not configured for Identity Provider {0} ({1})".format(idp_data.code, idp_data.name)); - - persdata["department"] = idp_data.department.id; // dan moet die ingevuld zijn - } - - if (user_key < 0) - __Log("User automatically created with data:"); - else - __Log("User automatically updated with data:"); - __Log(persdata); - - var persparams = {}; - var person = new model_prs_perslid({ internal: true }); // Internal: true om dit (nog) anoniem te mogen doen - if (user_key > 0) // bijwerken - { - person.REST_PUT( persparams, persdata, user_key ); - } - else // nieuwe - { - var prs = person.REST_POST( persparams, persdata ); - __DoLog("Created user '{0} {1}' with key {2} for idp '{3}'".format(persdata["firstname"], persdata["lastname"], prs.key, idp_data.code)); - // De nieuw aangemaakte gebruiker inloggen: - doLogin(prs.key, { idp_code: idp_data.code, isFACFACinternal: isFACFACinternal }); - // En nu pas kunnen we tracken - shared.trackaction("PRSUPD", prs.key, "Created user '{0} {1}' for idp '{2}'".format(persdata["firstname"], persdata["lastname"], idp_data.code)); - } - // 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) - { // authorisation bevat gebruikersgroepen gescheiden door '|' of ';' - /* SHIB: Within each CGI variable or header (see below), multiple attribute values - are separated by a semicolon, and semicolons in values are escaped with a backslash. - The data should be interpreted as UTF-8, which is a superset of ASCII. - */ - - var autharr = persdata["authorisation"].toLowerCase().split(/[;\|]/); // lowerCase, insensitive dus - 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); - } - - if ("workplace" in persdata) - { - // Eerst oude werkplekken ophalen - var sql = "SELECT pw.prs_werkplek_key, UPPER(alg_plaatsaanduiding) alg_plaatsaanduiding" - + " FROM prs_perslidwerkplek pw, prs_werkplek wp, alg_v_plaatsaanduiding" - + " WHERE pw.prs_perslid_key = " + user_key - + " AND pw.prs_werkplek_key = wp.prs_werkplek_key" - + " AND wp.prs_werkplek_type = 0" // alleen vaste plekken - + " AND alg_onroerendgoed_keys = wp.prs_alg_ruimte_key" - + " AND alg_onroerendgoed_type = 'R'"; - - var oRs = Oracle.Execute(sql); - var oldWP = {}; - while (!oRs.Eof) - { - oldWP[oRs("alg_plaatsaanduiding").Value] = oRs("prs_werkplek_key").Value; - oRs.MoveNext(); - } - oRs.Close(); - - // workplace bevat ruimtes gescheiden door '|' of ';' - // (we ondersteunen alleen impliciete werkplekken, geen 'named') - // Codering moet volgens alg_v_plaatsaanduiding zijn (locatiecode-gebouwcode-verdiepingcode-ruimtenr) - // Als er een '@' voor staat is het een virtuele werkplek - persdata["workplace"] = persdata["workplace"] || ""; - var workplacearr = persdata["workplace"].split(/[;\|]/); - for (var i = 0; i < workplacearr.length; i++) - { - var wpcode = workplacearr[i]; - var virtual = 0; - if (wpcode.substr(0, 1) == '@') - { - virtual = 1; - wpcode = wpcode.substr(1); - } - - if (wpcode in oldWP) - { - delete oldWP[wpcode]; // Hoeven we straks niet te wissen - } - else // Toevoegen - { - var sql = "SELECT alg_onroerendgoed_keys" - + " FROM alg_v_plaatsaanduiding" - + " WHERE alg_onroerendgoed_type = 'R'" - + " AND UPPER(alg_plaatsaanduiding) = " + safe.quoted_sql_upper(wpcode); - var oRs = Oracle.Execute(sql); - if (!oRs.Eof) - { - delete oldWP[wpcode.toUpperCase()]; // Die zal hergebruikt worden - var okey = oRs("alg_onroerendgoed_keys").Value; - sql = "BEGIN" - + " prs.movetoruimte ({0}, {1}, '{2}', {3}); ".format(user_key, okey, 'G', virtual) // G want maar één werkplek per gebouw - + "END;"; - Oracle.Execute(sql); - } - else - __Log("Workplace '{0}' not found".format(workplacearr[i])); - oRs.Close(); - } - } - for (wpcode in oldWP) // restant opruimen - { - __Log("Persoon verwijderen van WP {0}, wp-key {1}".format(wpcode, oldWP[wpcode])); - if (S("prs_werkplek_implicit") == 1) - { - var sql = "DELETE FROM prs_werkplek" - + " WHERE prs_werkplek_key = " + oldWP[wpcode]; + sql += " AND prs_afdeling_parentkey = " + idp_data.department.id; } else { - var sql = "DELETE FROM prs_perslid_werkplek" - + " WHERE prs_perslid_key = " + user_key - + " AND prs_werkplek_key = " + oldWP[wpcode]; + if (idp_data.company) + sql += " AND prs_bedrijf_key = " + idp_data.company.id; } - Oracle.Execute(sql); + var oRs = Oracle.Execute(sql); + if (oRs.Eof) + { + __Log("Claimed department {0} not found".format(val)); + // Er komt eventueel wel een fallback naar idp_data.department.id + } + else + { + var afd_key = oRs("prs_afdeling_key").Value; + oRs.MoveNext(); + if (!oRs.Eof) + shared.internal_error("Claimed department {0} not unique".format(val)); + + persdata["department"] = afd_key; + } + oRs.Close(); + break; } + // De 1-n + case 100: persdata.authorisation = val; break; + case 101: persdata.workplace = val; break; + // case 102: persdata.workplacevirtual = val; break; + // case 103: reserved voor mandatering? + default: + if (idpm.name.id > 1000) + set_custom_field(persdata, idpm.name.id - 1000, val, "C"); + break; + } + } + // Klantspecifieke check functie (hookfunction) voor de invoer + var pResult = new HookResult(); + if (!custfunc.aut_process_claim(persdata, claim, idp_data, pResult)) + { + abort_with_warning(pResult.errmsg); + } + + if (!("department" in persdata)) + { + if (!idp_data.department) + shared.internal_error("Department is not configured for Identity Provider {0} ({1})".format(idp_data.code, idp_data.name)); + + persdata["department"] = idp_data.department.id; // dan moet die ingevuld zijn + } + + if (user_key < 0) + __Log("User automatically created with data:"); + else + __Log("User automatically updated with data:"); + __Log(persdata); + + var persparams = {}; + var person = new model_prs_perslid({ internal: true }); // Internal: true om dit (nog) anoniem te mogen doen + if (user_key > 0) // bijwerken + { + person.REST_PUT( persparams, persdata, user_key ); + } + else // nieuwe + { + var prs = person.REST_POST( persparams, persdata ); + __DoLog("Created user '{0} {1}' with key {2} for idp '{3}'".format(persdata["firstname"], persdata["lastname"], prs.key, idp_data.code)); + // De nieuw aangemaakte gebruiker inloggen: + doLogin(prs.key, { idp_code: idp_data.code, isFACFACinternal: isFACFACinternal }); + // En nu pas kunnen we tracken + shared.trackaction("PRSUPD", prs.key, "Created user '{0} {1}' for idp '{2}'".format(persdata["firstname"], persdata["lastname"], idp_data.code)); + } + // 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) + { // authorisation bevat gebruikersgroepen gescheiden door '|' of ';' + /* SHIB: Within each CGI variable or header (see below), multiple attribute values + are separated by a semicolon, and semicolons in values are escaped with a backslash. + The data should be interpreted as UTF-8, which is a superset of ASCII. + */ + + var autharr = persdata["authorisation"].toLowerCase().split(/[;\|]/); // lowerCase, insensitive dus + 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); + } + + if ("workplace" in persdata) + { + // Eerst oude werkplekken ophalen + var sql = "SELECT pw.prs_werkplek_key, UPPER(alg_plaatsaanduiding) alg_plaatsaanduiding" + + " FROM prs_perslidwerkplek pw, prs_werkplek wp, alg_v_plaatsaanduiding" + + " WHERE pw.prs_perslid_key = " + user_key + + " AND pw.prs_werkplek_key = wp.prs_werkplek_key" + + " AND wp.prs_werkplek_type = 0" // alleen vaste plekken + + " AND alg_onroerendgoed_keys = wp.prs_alg_ruimte_key" + + " AND alg_onroerendgoed_type = 'R'"; + + var oRs = Oracle.Execute(sql); + var oldWP = {}; + while (!oRs.Eof) + { + oldWP[oRs("alg_plaatsaanduiding").Value] = oRs("prs_werkplek_key").Value; + oRs.MoveNext(); + } + oRs.Close(); + + // workplace bevat ruimtes gescheiden door '|' of ';' + // (we ondersteunen alleen impliciete werkplekken, geen 'named') + // Codering moet volgens alg_v_plaatsaanduiding zijn (locatiecode-gebouwcode-verdiepingcode-ruimtenr) + // Als er een '@' voor staat is het een virtuele werkplek + persdata["workplace"] = persdata["workplace"] || ""; + var workplacearr = persdata["workplace"].split(/[;\|]/); + for (var i = 0; i < workplacearr.length; i++) + { + var wpcode = workplacearr[i]; + var virtual = 0; + if (wpcode.substr(0, 1) == '@') + { + virtual = 1; + wpcode = wpcode.substr(1); + } + + if (wpcode in oldWP) + { + delete oldWP[wpcode]; // Hoeven we straks niet te wissen + } + else // Toevoegen + { + var sql = "SELECT alg_onroerendgoed_keys" + + " FROM alg_v_plaatsaanduiding" + + " WHERE alg_onroerendgoed_type = 'R'" + + " AND UPPER(alg_plaatsaanduiding) = " + safe.quoted_sql_upper(wpcode); + var oRs = Oracle.Execute(sql); + if (!oRs.Eof) + { + delete oldWP[wpcode.toUpperCase()]; // Die zal hergebruikt worden + var okey = oRs("alg_onroerendgoed_keys").Value; + sql = "BEGIN" + + " prs.movetoruimte ({0}, {1}, '{2}', {3}); ".format(user_key, okey, 'G', virtual) // G want maar één werkplek per gebouw + + "END;"; + Oracle.Execute(sql); + } + else + __Log("Workplace '{0}' not found".format(workplacearr[i])); + oRs.Close(); + } + } + for (wpcode in oldWP) // restant opruimen + { + __Log("Persoon verwijderen van WP {0}, wp-key {1}".format(wpcode, oldWP[wpcode])); + if (S("prs_werkplek_implicit") == 1) + { + var sql = "DELETE FROM prs_werkplek" + + " WHERE prs_werkplek_key = " + oldWP[wpcode]; + } + else + { + var sql = "DELETE FROM prs_perslid_werkplek" + + " WHERE prs_perslid_key = " + user_key + + " AND prs_werkplek_key = " + oldWP[wpcode]; + } + Oracle.Execute(sql); } } } diff --git a/APPL/AUT/loginTry.asp b/APPL/AUT/loginTry.asp index 104c920467..33558a0044 100644 --- a/APPL/AUT/loginTry.asp +++ b/APPL/AUT/loginTry.asp @@ -6,11 +6,24 @@ Met vernieuwde kennis zou ik dit bestand authenticate.asp noemen We weten niet wie de gebruiker is. - Probeer op allerlei manieren SSO + Probeer op allerlei manieren te authentiseren Als het lukt geven we een user_key terug in Session("user_key"); Als het niet lukt zal doorgaans door common.inc verder gegaan worden in de interactieve Logon.asp LET OP: Dit bestand wordt via Server.Transfer vanuit Common.inc aangeroepen + + We onderscheiden twee soorten authenticatie + Statefull + Dit is voor een interactieve gebruiker met een browser. Initieel wordt op + allerlei manieren authenticatie geprobeerd maar daarna wordt de user_key + in een Session opgeslagen en de volgende keer wordt via een Session-coolie + vanuit die session de authenticatie gedaan + In prs_perslid_login wordt het laatste moment van inloggen bijgewrkt + Er wordt een fac_session record aangemaakt (waar we verder weinig mee doen) + Stateless + Dit is voor API aanroepen. ELKE aanroep komt de authenticatie opnieuw + mee. Dit wordt niet geregistreerd in prs_perslid_login + Er wordt een Session.abandon gedaan om niet te veel IIS sessies te houden */ DOCTYPE_Disable = 1; ANONYMOUS_Allowed = 1; @@ -46,19 +59,28 @@ if (typeof Session("sso_sgf") == "string") // Vanuit FACWS001-portal/ sso_sgf.as Session.Contents.Remove("sso_sgf_realuser"); } +// De stateless varianten proberen we eerst, die worden tenslotte potentieel vaak uitgevoerd if (user_key < 0) - SimpleSSO(); // de base64 simple sso - -// Ingescande QR-code bookmark gaat naar \appl\prs\prs_perslid_qr_confirm.asp - -if (user_key < 0) // Probeer de user_key uit een cookie te halen { - var FcltId = "" + Request.Cookies("fcltid"); - if (FcltId != null && FcltId != "") + var APIKEY; + if (S("fac_api_key_in_url")) + APIKEY = getQParam("APIKEY", ""); + if (!APIKEY && Request.ServerVariables("HTTP_X_FACILITOR_API_KEY").Count) + APIKEY = String(Request.ServerVariables("HTTP_X_FACILITOR_API_KEY")); // Meegegeven als X-FACILITOR-API-Key + if (APIKEY) { - setUserFromSession (FcltId); - if (user_key > 0) - makeSessionCookie("Remember Login"); // Atijd nieuwe + var sql = "SELECT prs_perslid_key, prs_perslid_naam, prs_perslid_oslogin" + + " FROM prs_perslid" + + " WHERE prs_perslid_verwijder IS NULL" + + " AND prs_perslid_apikey = " + safe.quoted_sql(APIKEY); + var oRs = Oracle.Execute(sql); + if (!oRs.Eof) + { + __Log("API2 User is: {0} ({1})".format(oRs("prs_perslid_naam").Value, oRs("prs_perslid_oslogin").Value)); + doLoginStateless(oRs("prs_perslid_key").Value); + } + // else negeren + oRs.Close() } } @@ -74,11 +96,27 @@ if (user_key < 0) { var ww = plain.split(":"); ww.shift(); - tryLogin(plain.split(":")[0], ww.join(":")); // Behoudt eventuele ':' in wachtwoord + tryLogin(plain.split(":")[0], ww.join(":"), { stateless: true }); // Behoudt eventuele ':' in wachtwoord } } } +if (user_key < 0) + SimpleSSO(); // de base64 simple sso + +// Ingescande QR-code bookmark gaat naar \appl\prs\prs_perslid_qr_confirm.asp + +if (user_key < 0) // Probeer de user_key uit een cookie te halen +{ + var FcltId = "" + Request.Cookies("fcltid"); + if (FcltId != null && FcltId != "") + { + setUserFromSession (FcltId); + if (user_key > 0) + makeSessionCookie("Remember Login"); // Atijd nieuwe + } +} + if (user_key < 0) { var auth = String(Request.ServerVariables("HTTP_X_FACILITOR_ACCESS_TOKEN")); @@ -269,7 +307,7 @@ if (user_key < 0 && APIname) var API = new API_func(); // controleert vanzelf if (API.apidata.prs_perslid_key) - doLogin(API.apidata.prs_perslid_key, { noFacSession: true }); + doLogin(API.apidata.prs_perslid_key, { stateless: true }); } // LogOff.asp kan Session("no_sso") gezet hebben @@ -297,6 +335,15 @@ if (user_key < 0 && S("os_logon") //if (user_key < 0) // trySSO("DEFAULT"); // zal je standaard naar het loginscherm sturen +if (user_key > 0) // dan hebben we (nu) een nieuwe user +{ + // Alvast nieuwe user_key loggen zodat je ziet wie er inlogt. + if (typeof NO_ADDHEADER == "undefined" && Request.Servervariables("HTTP_FCLT_VERSION").Count > 0) + { // wordt opgepikt door FCLTAPI.DLL voor in de logging en daarna gestript. Niet in Fiddler dus + Response.AddHeader ("FCLT_USERID", customerId + "\\" + String(user_key)); + } +} + __Log("== Leaving loginTry.asp =="); %> \ No newline at end of file diff --git a/APPL/FAC/Facilitor.asp b/APPL/FAC/Facilitor.asp index b386fe099b..0ac81aa242 100644 --- a/APPL/FAC/Facilitor.asp +++ b/APPL/FAC/Facilitor.asp @@ -74,6 +74,14 @@ } // einde conversie user_options naar fac_menu + __Log("Welcome.asp expired?"); + var sql = "DELETE FROM fac_menu" + + " WHERE fac_menu_altgroep = 5" + + " AND fac_menu_alturl = " + safe.quoted_sql(S("fac_firstlogin_url")) + + " AND prs_perslid_key = " + user_key + + " AND fac_menu_aanmaak < SYSDATE - " + S("fac_firstlogin_expire"); + Oracle.Execute(sql, true); + // autoopen ophalen uit database var autoopen = []; var sql = "SELECT fac_menu_altlabel" diff --git a/APPL/FAC/fac_locale_data.asp b/APPL/FAC/fac_locale_data.asp index cd8520d94d..a80e1225ab 100644 --- a/APPL/FAC/fac_locale_data.asp +++ b/APPL/FAC/fac_locale_data.asp @@ -22,6 +22,8 @@ <% +debugger; + FCLTHeader.Requires({plugins:["suggest","jQuery"], js: ["jquery-ui.js"]}) var submitting = getQParamInt("submit", 0) == 1; diff --git a/APPL/FAC/fac_rewrite.config b/APPL/FAC/fac_rewrite.config index 4eb494ff22..12e1847d94 100644 --- a/APPL/FAC/fac_rewrite.config +++ b/APPL/FAC/fac_rewrite.config @@ -42,4 +42,18 @@ + + + + + +