Files
Facilitor/APPL/AUT/loginTry.asp
Jos Groot Lipman f488ba11bc DJIN#36213 SAML/Authenticatie verbeteringen.
svn path=/Website/trunk/; revision=33179
2017-03-16 19:46:30 +00:00

365 lines
15 KiB
Plaintext
Raw Blame History

<%@language = "javascript" %>
<% /*
$Revision$
$Id$
Met vernieuwde kennis zou ik dit bestand authenticate.asp noemen
We weten niet wie de gebruiker is.
Probeer op allerlei manieren SSO
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
*/
DOCTYPE_Disable = 1;
ANONYMOUS_Allowed = 1;
LOGIN_try = 1; // prevent recursion
NO_ADDHEADER = 1; // common.inc voert wat globale acties hierdoor niet meer uit
THIS_FILE = 'appl/shared/logintry.asp';
if (Response.Expires > 0)
FCLTEXPIRES = Response.Expires; // Aanroeper wist het beter?
%>
<!-- #include file="../Shared/common.inc" -->
<!-- #include file="./login.inc" -->
<!-- #include file="../api/api.inc" -->
<!-- #include file="../api2/api2.inc" -->
<!-- #include file="../api2/model_prs_perslid.inc" -->
<%
__Log("== Entering loginTry.asp ==");
if (typeof Session("sso_sgf") == "string") // Vanuit FACWS001-portal/ sso_sgf.asp
{
Session.Contents.Remove("ASPFIXATION"); // Niet moeilijk doen
settings.overrule_setting("login_use_email", 0); // We hebben altijd login gescanned namelijk
tryLogin(String(Session("sso_sgf")), null, { noPassword: true });
if (user_key < 0 && parseInt(String(Session("sso_sgf")), 10))
doLogin(parseInt(String(Session("sso_sgf")), 10)); // je mag ook key meegeven
var realuser = Session("sso_sgf_realuser");
if (user_key > 0 && realuser)
shared.trackaction("PRSLOG", user_key, L("lcl_logged_on_sso").format(realuser, Request.ServerVariables("REMOTE_ADDR")));
Session.Contents.Remove("sso_sgf");
Session.Contents.Remove("sso_sgf_realuser");
}
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_AUTHORIZATION"));
if (auth.match(/^Basic /))
{
__Log("Found Authorization: Basic");
var b64 = auth.substring(6);
var plain = decode_b64(b64);
if (plain.split(":").length > 1)
{
var ww = plain.split(":");
ww.shift();
tryLogin(plain.split(":")[0], ww.join(":")); // Behoudt eventuele ':' in wachtwoord
}
}
}
if (user_key < 0)
{
// Deeplink met &userauth=27399&userhmac=1387370160%3AECQXKFpi8RU5WTK2pfJ0zRnc7QY
if (Request.QueryString("userauth").Count > 0)
{
var userauth = getQParamInt("userauth"); // Zal een perslid_key zijn
var userhmac = getQParam("userhmac");
protectHMAC.verify(String(userauth), userhmac);
doLogin(userauth);
}
}
// jwt claim
// Niet zo maar een getFParam proberen. Dat nekt API2/PUT's binaryRead
var jwt = getQParam("jwt", "");
if (user_key < 0 && !jwt)
{
var auth = String(Request.ServerVariables("HTTP_AUTHORIZATION"));
if (auth.match(/^Bearer /))
{
__Log("Found Authorization: Bearer");
jwt = auth.substring(7);
var by_bearer = true; // deze is stateless dus geen sessie aanmaken.
Session.Abandon();
}
}
if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && jwt)
{
var claim = jwt_decode(jwt);
if (claim.err)
shared.internal_error("Invalid JWT: " + claim.err);
__Log(claim.payload);
var sql = "SELECT *"
+ " FROM fac_idp"
+ " WHERE fac_idp_type = 4" // JWT
+ " AND fac_idp_issuer = " + safe.quoted_sql(claim.payload.iss)
+ " AND fac_idp_audience = " + safe.quoted_sql(claim.payload.aud);
var oRs = Oracle.Execute(sql);
if (oRs.Eof)
shared.internal_error("Unknown JWT issuer {0} for audience {1}".format(claim.payload.iss, claim.payload.aud));
var verify = jwt_verify(claim, oRs("fac_idp_secret").Value, oRs("fac_idp_clockskew").Value, oRs("fac_idp_duration").Value);
if (verify.err)
shared.internal_error("Invalid JWT: " + verify.err);
if (!oRs("fac_idp_duration").Value) // single use tokens wil ik niet weer zien
{
// Voorkomt alle replay-aanvallen
// Iets verderop onthouden we signature
var sql = "SELECT prs_perslid_key, fac_session_data "
+ " FROM fac_session "
+ " WHERE fac_session_expire > sysdate "
+ " AND fac_session_sessionid_hash = " + safe.quoted_sql(claim.signature64);
var oRs2 = Oracle.Execute( sql );
if (!oRs2.eof)
shared.internal_error("Invalid JWT: it has been used before.");
oRs2.Close();
}
// 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)
{
shared.internal_error("Missing fclt_realuser in claim. It is required for IDP_internal.");
}
// Ok, de claim is geldig. Nu kijken of we er iets mee kunnen
if (claim.payload.username) // je mag username meegeven
{
settings.overrule_setting("login_use_email", 0);
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, 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, 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));
}
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
// De expiretijd gaat er alleen over wanneer ik mag opruimen. Neem daarbij uur speling
var agent = String(Request.ServerVariables("HTTP_USER_AGENT"));
var ip = String(Request.ServerVariables("REMOTE_ADDR"));
var sql = "INSERT INTO fac_session"
+ " (fac_session_sessionid_hash,"
+ " fac_session_data,"
+ " prs_perslid_key,"
+ " fac_session_expire,"
+ " fac_session_useragent,"
+ " fac_session_ip)"
+ " VALUES(" + safe.quoted_sql(claim.signature64) + ", "
+ " 'JWT replay preventer', "
+ user_key + ", "
+ " SYSDATE + 1/24 + 1/24/60/60 * " + oRs("fac_idp_clockskew").Value + ", "
+ safe.quoted_sql(agent, 256) + ", "
+ safe.quoted_sql(ip, 64) + ")";
Oracle.Execute(sql);
}
// 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")));
if (!by_bearer) // bearer is stateless/ single request dus geen redirect
{
var return_to = getQParam("return_to", "/") || "/";
// validate: enkele / voor root, /? voor root met params
// en anders iets in de /appl folder. Andere redirects kennen we niet
if (return_to != "/" &&
!return_to.match(/^\/\?/i) &&
!return_to.match(/^\/appl\/?/i)
)
{
__DoLog("Invalid return_to: " + return_to, "#f00");
return_to = "/";
}
// Ga weer helemaal terug naar de pagina waar je mee begon.
// Ook mooi als iemand er een bookmark naar legt.
Response.Redirect(rooturl + return_to);
}
}
}
var sso = getQParam("sso", "");
if (user_key < 0 && sso && sso != "0") // "0" is een hardcoded special case
trySSO(sso); // keert niet terug bij geldige ssocode
if (user_key < 0)
{
if (Session("fallback_user_key") > 0) // (QRC) bookmark met fallback user_key
{
__Log("Login by fallback_user_key {0}".format(Session("fallback_user_key")));
doLogin(Session("fallback_user_key"), { noFacSession: true });// gezet in Shorturl.asp
Session("login_by_fallback") = true; // fac_like_deep.asp wist dan sessie
Session.Contents.Remove("fallback_user_key");
}
}
// Pas h<><68>l laat api_user_key zetten om te voorkomen dat je
// bestaande sessie ongeldig wordt (Vinder/ telefoongids)
// JGL (later) maar volgens mij komt je dan hier helemaal niet dus is het niet echt relevant
var APIname = getQParam("API", "");
if (user_key < 0 && APIname)
{
var API = new API_func(); // controleert vanzelf
if (API.apidata.prs_perslid_key)
user_key = API.apidata.prs_perslid_key;
}
// LogOff.asp kan Session("no_sso") gezet hebben
// Ook: met &sso=0
if (Request.QueryString("sso") == "0")
Session("no_sso") = 1;
// Integrated authentication?
if (user_key < 0 && S("os_logon")
&& typeof Session("no_sso") == "undefined"
&& !Request.ServerVariables("HTTP_X_FACILITOR_API_KEY").Count
&& !Request.QueryString("APIKEY").Count)
{
var extern=false;
var i;
for (var i in S("os_logon_exclude")) // via proxy binnen?
{
if (Request.ServerVariables(S("os_logon_exclude")[i]).count>0)
extern = true;
}
if (!extern)
IntegratedSSO(); // Voor licentieklanten
}
//if (user_key < 0)
// trySSO("DEFAULT"); // zal je standaard naar het loginscherm sturen
if (user_key > 0)
{ // gelukt, teruggeven aan aanroeper
Session("user_key") = user_key;
}
__Log("== Leaving loginTry.asp ==");
%>