DJIN#36213 SAML/Authenticatie verbeteringen. Introuductie AUT(henticatie) folder
svn path=/Website/trunk/; revision=33106
This commit is contained in:
@@ -11,7 +11,7 @@ var JSON_Result = true;
|
||||
|
||||
<!-- #include file="../Shared/common.inc" -->
|
||||
<!-- #include file="../Shared/json2.js" -->
|
||||
<!-- #include file="../Shared/login.inc" -->
|
||||
<!-- #include file="./login.inc" -->
|
||||
|
||||
<%
|
||||
protectRequest.validateToken();
|
||||
@@ -19,6 +19,7 @@
|
||||
// Elders is prs_key geauthenticeerd. Registreer die hier als de actieve gebruiker.
|
||||
function doLogin(prs_key, params)
|
||||
{
|
||||
__Log("==== doLogin " + prs_key);
|
||||
params = params || {};
|
||||
// Paranoia mode
|
||||
var sql = "SELECT prs_perslid_login"
|
||||
@@ -61,7 +62,10 @@ function doLogin(prs_key, params)
|
||||
/* global */ user_key = prs_key;
|
||||
//user_lang = oRs(1).Value; // globale moet er nog uit!
|
||||
if (typeof LCL_Disable == "undefined")
|
||||
{
|
||||
__Log("==== LCL opnieuw laden voor nieuwe gebruiker");
|
||||
lcl.loadLCL();
|
||||
}
|
||||
|
||||
setASPFIXATION();
|
||||
|
||||
@@ -321,16 +325,16 @@ function otpcodes(otpsecret)
|
||||
otpoffset: parseInt(arr[3], 10),
|
||||
otpseed: arr[4],
|
||||
codes: [] };
|
||||
//Response.Write("<p>Current time: {0}".format(toDateTimeString(result.tokentime, true)));
|
||||
//Response.Write("<p>Current time: {0}".format(toISODateTimeString(result.tokentime, true)));
|
||||
if (result.otpoffset != 0)
|
||||
{
|
||||
result.tokentime.setSeconds(result.tokentime.getSeconds() + result.otpoffset)
|
||||
//Response.Write("</br>Token time: {0} ({1} s)".format(toDateTimeString(result.tokentime, true), result.otpoffset));
|
||||
//Response.Write("</br>Token time: {0} ({1} s)".format(toISODateTimeString(result.tokentime, true), result.otpoffset));
|
||||
}
|
||||
var ts = Math.round(result.tokentime.getTime() / 1000);
|
||||
var cnt = Math.floor(ts / result.otpstep) ; // Google doet 30 seconde
|
||||
result.tokenpassed = (ts / result.otpstep - cnt); // zo ver zijn we al in de periode gevorderd
|
||||
__Log("OTP time {0} counter {1}".format(toDateTimeString(result.tokentime, true), cnt));
|
||||
__Log("OTP time {0} counter {1}".format(toISODateTimeString(result.tokentime, true), cnt));
|
||||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
|
||||
for (var i = -Math.floor(S("prs_password_otp_window") / result.otpstep); i <= Math.floor(S("prs_password_otp_window") / result.otpstep); i++)
|
||||
{
|
||||
@@ -528,30 +532,13 @@ function verify_otp (prs_key, otprequest, otpsecret, otpcounter)
|
||||
return otp_oke;
|
||||
}
|
||||
|
||||
//
|
||||
// zet Session("user_key") als username en wachtwoord geldig zijn.
|
||||
// Login na verzending via sms moet binnen 1 kwartier ingevuld zijn.
|
||||
// resultaat: true bij succesvolle login, false bij niet succesvol
|
||||
// drie username opties:
|
||||
// - prs_perslid_oslogin
|
||||
// - prs_perslid_oslogin2
|
||||
// - upper(prs_perslid_email)
|
||||
// drie wachtwoord opties
|
||||
// - leeg (single-signon)
|
||||
// - prs_perslid_wachtwoord (of eigenlijk: prs_perslid_salt en prs_perslid_wachtwoord_hash)
|
||||
// - prs_perslid_authenticatie (en prs_perslid_authenticatie_exp > sysdate)
|
||||
// de laatste wordt gebruikt voor mobile/SMS
|
||||
|
||||
/* global */ login_fail_reason = L("lcl_login_wrong");
|
||||
/* global */ otp_user_key = -1;
|
||||
|
||||
function tryLogin(username, wachtwoord, params)
|
||||
function getIdentity(username, wachtwoord, params)
|
||||
{
|
||||
var result = { success: false, fail_reason: L("lcl_login_wrong") };
|
||||
params = params || {};
|
||||
Session.Contents.Remove("org_user_key");
|
||||
|
||||
if (!username || username == 'undefined')
|
||||
return false;
|
||||
return result;
|
||||
|
||||
if (username.indexOf("\\") > -1)
|
||||
username = username.split("\\")[1]; // strip domain name
|
||||
@@ -582,7 +569,7 @@ function tryLogin(username, wachtwoord, params)
|
||||
|
||||
var oRs = Oracle.Execute(sql);
|
||||
if (oRs.Eof)
|
||||
return false; // Gebruikersnaam niet eens gevonden
|
||||
return result; // Gebruikersnaam niet eens gevonden
|
||||
|
||||
var otpsecret = oRs("prs_perslid_otpsecret").Value;
|
||||
var otpcounter = oRs("prs_perslid_otpcounter").Value || -1;
|
||||
@@ -594,12 +581,12 @@ function tryLogin(username, wachtwoord, params)
|
||||
found = testpassword(oRs("prs_perslid_key").Value, wachtwoord, params.mobile);
|
||||
|
||||
if (!found)
|
||||
return false;
|
||||
return result;
|
||||
|
||||
if ((oRs("prs_perslid_flags").Value & 2) == 2)
|
||||
{
|
||||
login_fail_reason = L("lcl_self_register_unconfirmed");
|
||||
return false;
|
||||
result.fail_reason = L("lcl_self_register_unconfirmed");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!otpsecret || !wachtwoord)
|
||||
@@ -607,17 +594,47 @@ function tryLogin(username, wachtwoord, params)
|
||||
var deze = new Perslid(oRs("prs_perslid_key").Value);
|
||||
if (wachtwoord && deze.has("WEB_FACFAC"))
|
||||
{
|
||||
login_fail_reason = L("lcl_login_needs_otpsecret");
|
||||
return false;
|
||||
result.fail_reason = L("lcl_login_needs_otpsecret");
|
||||
return result;
|
||||
}
|
||||
doLogin(oRs("prs_perslid_key").Value, params);
|
||||
result = { success: true, user_key: oRs("prs_perslid_key").Value };
|
||||
}
|
||||
else if (params.otpcode && testotp(oRs("prs_perslid_key").Value, params.otpcode))
|
||||
doLogin(oRs("prs_perslid_key").Value, params);
|
||||
result = { success: true, user_key: oRs("prs_perslid_key").Value };
|
||||
else // Wordt opgepikt door login_save.asp
|
||||
/* global */ otp_user_key = oRs("prs_perslid_key").Value;
|
||||
result = { success: true, otp_user_key: oRs("prs_perslid_key").Value };
|
||||
|
||||
oRs.Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// zet Session("user_key") als username en wachtwoord geldig zijn.
|
||||
// Login na verzending via sms moet binnen 1 kwartier ingevuld zijn.
|
||||
// resultaat: true bij succesvolle login, false bij niet succesvol
|
||||
// drie username opties:
|
||||
// - prs_perslid_oslogin
|
||||
// - prs_perslid_oslogin2
|
||||
// - upper(prs_perslid_email)
|
||||
// drie wachtwoord opties
|
||||
// - leeg (single-signon)
|
||||
// - prs_perslid_wachtwoord (of eigenlijk: prs_perslid_salt en prs_perslid_wachtwoord_hash)
|
||||
// - prs_perslid_authenticatie (en prs_perslid_authenticatie_exp > sysdate)
|
||||
// de laatste wordt gebruikt voor mobile/SMS
|
||||
|
||||
|
||||
function tryLogin(username, wachtwoord, params)
|
||||
{
|
||||
params = params || {};
|
||||
Session.Contents.Remove("org_user_key");
|
||||
|
||||
var ident = getIdentity(username, wachtwoord, params);
|
||||
if (!ident.success)
|
||||
return false;
|
||||
|
||||
if (ident.user_key > 0)
|
||||
doLogin(ident.user_key, params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -937,14 +954,114 @@ function IntegratedSSO()
|
||||
}
|
||||
}
|
||||
|
||||
/* resultaat:
|
||||
{ err: "Iets niet goed" }
|
||||
of { header: header,
|
||||
payload: payload (claim)
|
||||
signature: signature
|
||||
}
|
||||
LET OP: signature is nog niet gevalideerd!
|
||||
*/
|
||||
// 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)
|
||||
{
|
||||
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 = {
|
||||
usermapping: oRs("fac_sp_usermapping").Value,
|
||||
iss: oRs("fac_sp_issuer").Value,
|
||||
aud: aud,
|
||||
secret: oRs("fac_sp_secret").Value
|
||||
};
|
||||
oRs.Close();
|
||||
}
|
||||
|
||||
var claim =
|
||||
{
|
||||
jti: "#" + (perslid_key) + "#" + new Date().getTime()
|
||||
}
|
||||
|
||||
// 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++)
|
||||
{
|
||||
var spl = arr[i].split('->');
|
||||
var attr = spl[0];
|
||||
if (spl.length > 1)
|
||||
var clm = spl[1]
|
||||
else
|
||||
clm = attr;
|
||||
switch (attr)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
claim.iat = Math.round(new Date().getTime() / 1000);
|
||||
claim.iss = params.iss;
|
||||
claim.aud = params.aud;
|
||||
|
||||
return jwt_encode(claim, params.secret);
|
||||
}
|
||||
|
||||
function jwt_encode(claim, secret)
|
||||
{
|
||||
var header =
|
||||
{
|
||||
"typ":"JWT",
|
||||
"alg":"HS256"
|
||||
};
|
||||
|
||||
claim.ver = "1.0";
|
||||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
|
||||
|
||||
var sheader = oCrypto.base64(JSON.stringify(header, false)); // no padding
|
||||
var sclaim = oCrypto.base64(JSON.stringify(claim, false));
|
||||
var signature = oCrypto.hex_hmac_sha256(secret, sheader + "." + sclaim);
|
||||
var sig64 = oCrypto.hex2base64(signature, false, true); // no padding, urlsafe
|
||||
var jwt = sheader + "." + sclaim + "." + sig64;
|
||||
|
||||
return jwt;
|
||||
}
|
||||
|
||||
function jwt_decode(token)
|
||||
{
|
||||
// check token
|
||||
@@ -973,7 +1090,7 @@ function jwt_decode(token)
|
||||
}
|
||||
catch (s)
|
||||
{
|
||||
return { err: "Invalid JSON: " + e.description };
|
||||
return { err: "Invalid JSON: {0} {1}".format(s.name, s.message) };
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1005,14 +1122,14 @@ function jwt_verify(decoded_jwt, secret, skew, duration)
|
||||
|
||||
// Onze eigen duration/expiration controleren we ook nog
|
||||
if (claim.payload.iat + duration < now - skew) {
|
||||
__DoLog("Token expired. Now is {0}, got {1}, skew {2}".format(toDateTimeString(new Date(now * 1000), true),
|
||||
toDateTimeString(new Date(claim.payload.iat * 1000), true),
|
||||
__DoLog("Token expired. Now is {0}, got {1}, skew {2}".format(toISODateTimeString(new Date(now * 1000), true),
|
||||
toISODateTimeString(new Date(claim.payload.iat * 1000), true),
|
||||
skew));
|
||||
return { err: 'Token expired' };
|
||||
}
|
||||
if (claim.payload.iat > now + skew) {
|
||||
__DoLog("Token not yet active. Now is {0}, got {1}, skew {2}".format(toDateTimeString(new Date(now * 1000), true),
|
||||
toDateTimeString(new Date(claim.payload.iat * 1000), true),
|
||||
__DoLog("Token not yet active. Now is {0}, got {1}, skew {2}".format(toISODateTimeString(new Date(now * 1000), true),
|
||||
toISODateTimeString(new Date(claim.payload.iat * 1000), true),
|
||||
skew));
|
||||
return { err: 'Token not yet active' };
|
||||
}
|
||||
@@ -1023,6 +1140,63 @@ function jwt_verify(decoded_jwt, secret, skew, duration)
|
||||
return { err: "Token signature did not verify" };
|
||||
}
|
||||
|
||||
function trySSO(ssocode)
|
||||
{
|
||||
var sql = "SELECT *"
|
||||
+ " FROM fac_idp"
|
||||
+ " WHERE fac_idp_code = " + safe.quoted_sql_upper(ssocode); // een trigger zorgt dat fac_idp_code uppercase is
|
||||
var oRs = Oracle.Execute(sql);
|
||||
if (oRs.Eof)
|
||||
shared.internal_error("Identity provider '{0}' is not configured for {1}".format(ssocode, customerId));
|
||||
|
||||
var isFACFACinternal = oRs("fac_idp_internal").Value != 0;
|
||||
var ip_restrict = oRs("fac_idp_ipfilter").Value;
|
||||
if (isFACFACinternal && S("idp_internal_anyuser"))
|
||||
ip_restrict = ""; // dan niet al te moeilijk doen
|
||||
var ip_ok = true;
|
||||
if (ip_restrict) // Application("otap_environment") != "O")
|
||||
{
|
||||
var ip = String(Request.ServerVariables("REMOTE_ADDR"));
|
||||
if (ip != '::1' && ip != '127.0.0.1') // local access always ok
|
||||
{
|
||||
ip_ok = IP.inAnySubnet(ip, ip_restrict);
|
||||
__Log("SSO IP-restrictie {0} versus remote {1}: {2}".format(ip_restrict, ip, ip_ok));
|
||||
if (!ip_ok)
|
||||
{ // Always allow Private networks (RFC 1918)
|
||||
ip_ok = IP.inAnySubnet(ip, "192.168.0.0/16,172.16.0.0/12,10.0.0.0/8");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ip_ok)
|
||||
shared.internal_error("IP {0} not allowed for this IDP".format(ip)); // TODO of 400 code forbidden?
|
||||
|
||||
if (oRs("fac_idp_type").Value == 3) // Oldstyle SecureSSO, die doet het verder zelf
|
||||
{
|
||||
SecureSSO({ strSharedKey: oRs("fac_idp_secret").Value,
|
||||
Timeout: oRs("fac_idp_clockskew").Value,
|
||||
ssoURL: oRs("fac_idp_remote_loginurl").Value,
|
||||
sso: ssocode
|
||||
});
|
||||
/* keert niet terug */
|
||||
}
|
||||
var audience = oRs("fac_idp_audience").Value;
|
||||
var issuer = oRs("fac_idp_issuer").Value;
|
||||
var url = oRs("fac_idp_remote_loginurl").Value;
|
||||
if (!url) // regulier bij Logcenter-sso CUSTOMER als gebruiker (nog) niet bekend is
|
||||
shared.internal_error("User unknown and Identity Provider '{0}' has no login url".format(ssocode));
|
||||
if (url.indexOf("://") < 0) // geen protocol?
|
||||
url = HTTP.urlzelf() + "/" + url;
|
||||
url += (url.indexOf("?")>=0?"&":"?") + "aud=" + safe.url(audience) + "&iss=" + safe.url(issuer) ;
|
||||
var redirect_uri = HTTP.urlzelf() + "/";
|
||||
var return_to = String(Request.ServerVariables("URL")).substr(rooturl.length) + "?" + String(Request.ServerVariables("QUERY_STRING"));
|
||||
return_to = return_to.replace(/^\/default.asp/i, "/"); // default.asp vooraan hoeft niet, ik wil cleane url
|
||||
url += "&redirect_uri={0}&return_to={1}".format(safe.url(redirect_uri), safe.url(return_to));
|
||||
oRs.Close();
|
||||
Response.Redirect(url); // die stuurt ons wel terug
|
||||
Response.End;
|
||||
}
|
||||
|
||||
%>
|
||||
<script language="VBScript" runat="Server">
|
||||
'' // Met de beste wil van de wereld kreeg ik dit niet werkend met JScript
|
||||
41
APPL/AUT/authenticate.asp
Normal file
41
APPL/AUT/authenticate.asp
Normal file
@@ -0,0 +1,41 @@
|
||||
<%@language = "javascript" %>
|
||||
<% /*
|
||||
$Revision$
|
||||
$Id$
|
||||
|
||||
File: authenticate.asp
|
||||
Description: Voor als je (een) FACILITOR als Identity Provider wilt
|
||||
gebruiken
|
||||
Parameters: redirect_uri
|
||||
return_to
|
||||
aud
|
||||
state
|
||||
Context:
|
||||
Note: Enigszins conform oAuth/ OpenID Connect maar daar (nog) niet
|
||||
noodzakelijkerwijs compatible mee.
|
||||
|
||||
*/
|
||||
%>
|
||||
<!-- #include file="../Shared/common.inc" -->
|
||||
<!-- #include file="./login.inc" -->
|
||||
<%
|
||||
var redirect_uri = getQParam("redirect_uri", rooturl + "/"); // TODO: verify?
|
||||
var return_to = getQParam("return_to", "");
|
||||
var aud = getQParam("aud", "");
|
||||
var state = getQParam("state", "");
|
||||
|
||||
if (user_key > 0)
|
||||
{
|
||||
var jwt = jwt_create(user_key, aud);
|
||||
|
||||
var url = redirect_uri + (redirect_uri.indexOf("?")>=0?"&":"?") + "jwt={0}";
|
||||
if (return_to)
|
||||
url = url + "&return_to=" + Server.URLencode(return_to);
|
||||
if (state)
|
||||
url = url + "&state=" + Server.URLencode(state);
|
||||
|
||||
Response.Redirect(url.format(jwt));
|
||||
}
|
||||
// Hier kom je nooit volgens mij
|
||||
Response.Write("Wie ben jij in {0}?".format(customerId));
|
||||
%>
|
||||
@@ -16,7 +16,7 @@ ANONYMOUS_Allowed = 1;
|
||||
%>
|
||||
<!-- #include file="../Shared/common.inc" -->
|
||||
<!-- #include file="../Shared/iface.inc" -->
|
||||
<!-- #include file="../Shared/login.inc" -->
|
||||
<!-- #include file="./login.inc" -->
|
||||
<!--#include file="../shared/useragent.inc" -->
|
||||
<%
|
||||
if (Request.QueryString.Count > 0)
|
||||
@@ -141,6 +141,22 @@ if (device.test(device.isMobile))
|
||||
if (S("self_register") == 1) {
|
||||
buttons.push ({ title: L("lcl_self_register"), action: "selfregister()" });
|
||||
}
|
||||
|
||||
/*
|
||||
var sql = "SELECT fac_idp_omschrijving"
|
||||
+ " , fac_idp_code"
|
||||
+ " FROM fac_idp"
|
||||
+ " WHERE fac_idp_code <> 'DEFAULT'"
|
||||
+ " AND fac_idp_internal = 0"
|
||||
+ " AND fac_idp_type = 4" // alleen nog even de JWT versie. Misschien SAML (5) er later bij
|
||||
var oRs = Oracle.Execute(sql);
|
||||
while (!oRs.Eof)
|
||||
{
|
||||
buttons.push ({ title: oRs("fac_idp_omschrijving").Value, action: "alert()".format(oRs("fac_idp_code").Value) });
|
||||
oRs.MoveNext();
|
||||
}
|
||||
oRs.Close()
|
||||
*/
|
||||
CreateButtons(buttons, { entersubmit: true, vertical: buttons.length>2});
|
||||
%></td>
|
||||
</tr>
|
||||
@@ -22,7 +22,7 @@ if (Response.Expires > 0)
|
||||
FCLTEXPIRES = Response.Expires; // Aanroeper wist het beter?
|
||||
%>
|
||||
<!-- #include file="../Shared/common.inc" -->
|
||||
<!-- #include file="../Shared/login.inc" -->
|
||||
<!-- #include file="./login.inc" -->
|
||||
<!-- #include file="../api/api.inc" -->
|
||||
<%
|
||||
__Log("== Entering loginTry.asp ==");
|
||||
@@ -87,7 +87,6 @@ if (user_key < 0)
|
||||
}
|
||||
}
|
||||
// jwt claim
|
||||
// TODO: altijd/ ook als user_key > 0?
|
||||
// Niet zo maar een getFParam proberen. Dat nekt API2/PUT's binaryRead
|
||||
var jwt = getQParam("jwt", "");
|
||||
if (user_key < 0 && !jwt)
|
||||
@@ -104,11 +103,12 @@ if (user_key < 0 && !jwt)
|
||||
if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && jwt)
|
||||
{
|
||||
var claim = jwt_decode(jwt);
|
||||
//__Log(claim);
|
||||
|
||||
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
|
||||
@@ -181,98 +181,43 @@ if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && jwt)
|
||||
+ " fac_session_useragent,"
|
||||
+ " fac_session_ip)"
|
||||
+ " VALUES(" + safe.quoted_sql(claim.signature64) + ", "
|
||||
+ " 'JWT replay preventer',"
|
||||
+ user_key + ","
|
||||
+ " '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(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;
|
||||
}
|
||||
|
||||
if (user_key > 0 && claim.payload.fclt_realuser)
|
||||
shared.trackaction("PRSLOG", user_key, L("lcl_logged_on_sso").format(claim.payload.fclt_realuser, Request.ServerVariables("REMOTE_ADDR")));
|
||||
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 && user_key > 0) // 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)
|
||||
)
|
||||
if (!by_bearer) // bearer is stateless/ single request dus geen redirect
|
||||
{
|
||||
__DoLog("Invalid return_to: " + return_to, "#f00");
|
||||
return_to = "/";
|
||||
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);
|
||||
}
|
||||
// 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
|
||||
{
|
||||
var sql = "SELECT *"
|
||||
+ " FROM fac_idp"
|
||||
+ " WHERE fac_idp_code = " + safe.quoted_sql_upper(sso); // een trigger zorg dat fac_idp_code uppercase is
|
||||
var oRs = Oracle.Execute(sql);
|
||||
if (oRs.Eof)
|
||||
shared.internal_error("Identity provider '{0}' is not configured for {1}".format(sso, customerId));
|
||||
|
||||
var isFACFACinternal = oRs("fac_idp_internal").Value != 0;
|
||||
var ip_restrict = oRs("fac_idp_ipfilter").Value;
|
||||
if (isFACFACinternal && S("idp_internal_anyuser"))
|
||||
ip_restrict = ""; // dan niet al te moeilijk doen
|
||||
var ip_ok = true;
|
||||
if (ip_restrict) // Application("otap_environment") != "O")
|
||||
{
|
||||
var ip = String(Request.ServerVariables("REMOTE_ADDR"));
|
||||
if (ip != '::1' && ip != '127.0.0.1') // local access always ok
|
||||
{
|
||||
ip_ok = IP.inAnySubnet(ip, ip_restrict);
|
||||
__Log("SSO IP-restrictie {0} versus remote {1}: {2}".format(ip_restrict, ip, ip_ok));
|
||||
if (!ip_ok)
|
||||
{ // Always allow Private networks (RFC 1918)
|
||||
ip_ok = IP.inAnySubnet(ip, "192.168.0.0/16,172.16.0.0/12,10.0.0.0/8");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ip_ok)
|
||||
shared.internal_error("IP {0} not allowed for this IDP".format(ip)); // TODO of 400 code forbidden?
|
||||
|
||||
if (oRs("fac_idp_type").Value == 3) // Oldstyle SecureSSO, die doet het verder zelf
|
||||
{
|
||||
SecureSSO({ strSharedKey: oRs("fac_idp_secret").Value,
|
||||
Timeout: oRs("fac_idp_clockskew").Value,
|
||||
ssoURL: oRs("fac_idp_remote_loginurl").Value,
|
||||
sso: sso
|
||||
});
|
||||
/* keert niet terug */
|
||||
}
|
||||
var audience = oRs("fac_idp_audience").Value;
|
||||
var issuer = oRs("fac_idp_issuer").Value;
|
||||
var url = oRs("fac_idp_remote_loginurl").Value;
|
||||
if (!url) // regulier bij Logcenter-sso CUSTOMER als gebruiker (nog) niet bekend is
|
||||
shared.internal_error("User unknown and Identity Provider '{0}' has no login url".format(sso));
|
||||
url += (url.indexOf("?")>=0?"&":"?") + "fac_id=" + customerId;
|
||||
url += "&aud=" + safe.url(audience) + "&iss=" + safe.url(issuer) ;
|
||||
var redirect_uri = HTTP.urlzelf() + "/";
|
||||
var return_to = String(Request.ServerVariables("URL")).substr(rooturl.length) + "?" + String(Request.ServerVariables("QUERY_STRING"));
|
||||
return_to = return_to.replace(/^\/default.asp/i, "/"); // default.asp vooraan hoeft niet, ik wil cleane url
|
||||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto"); // requires version 4.14
|
||||
var sig = oCrypto.hex_hmac_sha256(oRs("fac_idp_secret").Value, return_to);
|
||||
url += "&redirect_uri={0}&return_to={1}".format(safe.url(redirect_uri), safe.url(return_to));
|
||||
oRs.Close();
|
||||
Response.Redirect(url); // die stuurt ons wel terug
|
||||
Response.End;
|
||||
}
|
||||
trySSO(sso); // keert niet terug bij geldige ssocode
|
||||
|
||||
if (user_key < 0)
|
||||
{
|
||||
@@ -302,6 +247,7 @@ if (user_key < 0 && APIname)
|
||||
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
|
||||
@@ -318,8 +264,13 @@ if (user_key < 0 && S("os_logon")
|
||||
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 ==");
|
||||
|
||||
%>
|
||||
@@ -9,13 +9,16 @@
|
||||
Context:
|
||||
Note: Als de gebruiker ook een otp-code moet opgeven komen we
|
||||
hier *twee* keer langs, de tweede keer met een code
|
||||
|
||||
Bij success geven we een jwt-claim terug, de gebruiker is
|
||||
nog niet vanzelf ingelogd!
|
||||
*/ %>
|
||||
<%
|
||||
var JSON_Result = true;
|
||||
var ANONYMOUS_Allowed = 1;
|
||||
%>
|
||||
<!-- #include file="../Shared/common.inc" -->
|
||||
<!-- #include file="../Shared/login.inc" -->
|
||||
<!-- #include file="./login.inc" -->
|
||||
<!-- #include file="../Shared/json2.js" -->
|
||||
<%
|
||||
protectRequest.validateToken();
|
||||
@@ -25,24 +28,25 @@ var ps = getFParam("vis_pswd");
|
||||
var otpcode = getFParam("otpcode", "");
|
||||
|
||||
var remember = getFParam("remember", "off")=="on";
|
||||
|
||||
var ismobile = getFParam("mobile");
|
||||
|
||||
tryLogin(nm, ps, { mobile: ismobile, otpcode: otpcode}); // nm = username, ps = wachtwoord
|
||||
var ident = getIdentity(nm, ps, { mobile: ismobile, otpcode: otpcode });
|
||||
|
||||
result = { success: user_key > 0 };
|
||||
var result = { success: ident.user_key > 0 };
|
||||
|
||||
if (user_key > 0)
|
||||
if (ident.user_key > 0)
|
||||
{
|
||||
if (S("login_remember_days") > 0 && remember && user_key > 0)
|
||||
doLogin(ident.user_key, {});
|
||||
if (S("login_remember_days") > 0 && remember)
|
||||
makeSessionCookie("Remember Login");
|
||||
|
||||
result.success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (otp_user_key > 0)
|
||||
if (ident.otp_user_key > 0)
|
||||
{
|
||||
var otp_user = new Perslid(otp_user_key);
|
||||
var otp_user = new Perslid(ident.otp_user_key);
|
||||
var issuer = L("lcl_otp_issuer").format(HTTP.urlzelf());
|
||||
var friendly = L("lcl_otp_friendly").format(customerId, otp_user.oslogin(), otp_user.naam());
|
||||
|
||||
@@ -51,7 +55,7 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
result.message = login_fail_reason;
|
||||
result.message = ident.fail_reason;
|
||||
__DoLog("Inloggen '{0}' mislukt: {1}".format(nm, result.message) , "#f0f");
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
<!--#include file="../shared/iface.inc"-->
|
||||
<!--#include file="fac_menu.inc" -->
|
||||
<!--#include file="header.inc" -->
|
||||
<!--#include file="../Shared/login.inc" -->
|
||||
<!--#include file="../aut/login.inc" -->
|
||||
<!--#include file="../Shared/json2.js" -->
|
||||
|
||||
<%
|
||||
@@ -514,7 +514,7 @@ function menu(evt, item, regel, menu_key) // E
|
||||
<%
|
||||
if (!device.test(device.isTouch)) { %>
|
||||
<body>
|
||||
<form name="u2" action="../shared/LogOff.asp" method="post" onSubmit="logOff();">
|
||||
<form name="u2" action="../aut/LogOff.asp" method="post" onSubmit="logOff();">
|
||||
<% IFACE.FORM_END(); %>
|
||||
</form>
|
||||
<% if (!noHeader) { %>
|
||||
|
||||
@@ -233,7 +233,7 @@ function generateHeaderFunctions (params)
|
||||
{
|
||||
var data = {};
|
||||
<% protectRequest.dataToken("data"); %>
|
||||
$.post("../shared/LogOff.asp",
|
||||
$.post("../aut/LogOff.asp",
|
||||
data,
|
||||
FcltCallbackAndThen(logOffCallback),
|
||||
"json");
|
||||
|
||||
@@ -254,7 +254,7 @@ var app_user;
|
||||
|
||||
if ((user_key < 0 || getQParamInt("jwtforce", 0) == 1) && typeof LOGIN_try == "undefined")
|
||||
{
|
||||
Server.Execute(rooturl + "/appl/shared/loginTry.asp"); // Laat die het eens proberen op te lossen
|
||||
Server.Execute(rooturl + "/appl/aut/loginTry.asp"); // Laat die het eens proberen op te lossen
|
||||
if (Session("user_key") > 0)
|
||||
user_key = Session("user_key");
|
||||
}
|
||||
@@ -270,8 +270,11 @@ if (user_key < 0 && typeof ANONYMOUS_Allowed == "undefined")
|
||||
}
|
||||
|
||||
var url = Session("unauth_url") || S("login_url"); // unauth_url uit shorturl.asp
|
||||
if (url == 'appl/shared/login.asp') // even compatible blijven
|
||||
url = 'appl/aut/login.asp';
|
||||
|
||||
if (getQParam("sso", "") == "0") // forceer de default
|
||||
url = 'appl/shared/login.asp';
|
||||
url = 'appl/aut/login.asp';
|
||||
|
||||
if (!url.match(/^http/))
|
||||
var url = rooturl + "/" + url; // "appl/shared/login.asp";
|
||||
|
||||
1
APPL/Shared/login.inc
Normal file
1
APPL/Shared/login.inc
Normal file
@@ -0,0 +1 @@
|
||||
<!-- #include file="../aut/login.inc" -->
|
||||
Reference in New Issue
Block a user