diff --git a/avRegistration/login-directive/login-directive.js b/avRegistration/login-directive/login-directive.js index 6ac7f424..9fe8a1b5 100644 --- a/avRegistration/login-directive/login-directive.js +++ b/avRegistration/login-directive/login-directive.js @@ -32,6 +32,7 @@ angular.module('avRegistration') Patterns) { var OIDC_CSRF_COOKIE = "OIDC_CSRF"; + var OIDC_ERROR_COOKIE = "OIDC_ERROR_COOKIE"; // we use it as something similar to a controller here function link(scope, element, attrs) { @@ -58,7 +59,26 @@ angular.module('avRegistration') var adminId = ConfigService.freeAuthId + ''; var autheventid = null; + function parseOidcErrorCookie() + { + if (!$cookies.get(OIDC_ERROR_COOKIE)) + { + return null; + } + // validate csrf token format and data + return angular.fromJson($cookies.get(OIDC_ERROR_COOKIE)); + } + scope.oidcError = parseOidcErrorCookie(); + if (scope.oidcError) { + scope.selectedAltMethod = scope.oidcError.altAuthMethodId; + scope.error = $i18next( + 'avRegistration.loginError.openid-connect.' + scope.oidcError.errorCodename, + { + support: '' + ConfigService.contact.email + "" + } + ); + } // simply redirect to login function simpleRedirectToLogin() @@ -134,11 +154,40 @@ angular.module('avRegistration') return decodeURIComponent(params[2].replace(/\+/g, ' ')); } + function setOIDCErrorCookie(errorCodename) + { + var options = {}; + if (ConfigService.authTokenExpirationSeconds) { + options.expires = new Date( + Date.now() + 1000 * ConfigService.authTokenExpirationSeconds + ); + } + $cookies.put( + OIDC_ERROR_COOKIE, + angular.toJson({ + altAuthMethodId: scope.current_alt_auth_method_id, + eventId: scope.eventId, + errorCodename: errorCodename + }), + options + ); + } + + function setError(errorCodename, error) + { + scope.error = error; + if (scope.isOpenId) { + setOIDCErrorCookie(errorCodename); + redirectToLogin(); + } + } + // Validates the CSRF token function validateCsrfToken() { if (!$cookies.get(OIDC_CSRF_COOKIE)) { + setOIDCErrorCookie("unexpectedOIDCRedirect"); redirectToLogin(); return null; } @@ -179,6 +228,7 @@ angular.module('avRegistration') if (!isCsrfValid) { + setOIDCErrorCookie("invalidCsrf"); redirectToLogin(); return null; } @@ -569,7 +619,9 @@ angular.module('avRegistration') var postfix = "_authevent_" + autheventid; var options = {}; if (ConfigService.authTokenExpirationSeconds) { - options.expires = new Date(Date.now() + 1000 * ConfigService.authTokenExpirationSeconds); + options.expires = new Date( + Date.now() + 1000 * ConfigService.authTokenExpirationSeconds + ); } $cookies.put("authevent_" + autheventid, autheventid, options); $cookies.put("userid" + postfix, response.data.username, options); @@ -644,25 +696,35 @@ angular.module('avRegistration') $window.location.href = '/booth/' + autheventid + '/vote'; } else { - scope.error = $i18next( - 'avRegistration.loginError.' + scope.method + '.unrecognizedServerResponse', - {support: '' + ConfigService.contact.email + ""} + setError( + "unrecognizedServerResponse", + $i18next( + 'avRegistration.loginError.' + scope.method + '.unrecognizedServerResponse', + {support: '' + ConfigService.contact.email + ""} + ) ); } } else { scope.sendingData = false; - scope.error = $i18next( - 'avRegistration.loginError.' + scope.method + '.invalidServerResponse', - {support: '' + ConfigService.contact.email + ""} + setError( + "invalidServerResponse", + $i18next( + 'avRegistration.loginError.' + scope.method + '.invalidServerResponse', + {support: '' + ConfigService.contact.email + ""} + ) ); } }, function onError(response) { scope.sendingData = false; var codename = response.data.error_codename; - scope.error = $i18next( - 'avRegistration.loginError.' + scope.method + '.' + codename, - {support: '' + ConfigService.contact.email + ""} + + setError( + "codename", + $i18next( + 'avRegistration.loginError.' + scope.method + '.' + codename, + {support: '' + ConfigService.contact.email + ""} + ) ); } ); @@ -901,7 +963,8 @@ angular.module('avRegistration') if ( !scope.isOtl && !scope.isCensusQuery && - !scope.withCode + !scope.withCode && + !scope.oidcError ) { scope.loginUser(true); } diff --git a/dist/appCommon-v10.0.2.js b/dist/appCommon-v10.0.2.js index bad1c5c2..0ec4539b 100644 --- a/dist/appCommon-v10.0.2.js +++ b/dist/appCommon-v10.0.2.js @@ -472,13 +472,28 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist paramName2 = paramName2.replace(/[\[\]]/g, "\\$&"), params = new RegExp("[?&]" + paramName2 + "(=([^&#]*)|&|#|$)").exec(params); return params ? params[2] ? decodeURIComponent(params[2].replace(/\+/g, " ")) : "" : null; } - if (scope.isOpenId) { + function setOIDCErrorCookie(errorCodename) { + var options = {}; + ConfigService.authTokenExpirationSeconds && (options.expires = new Date(Date.now() + 1e3 * ConfigService.authTokenExpirationSeconds)), + $cookies.put("OIDC_ERROR_COOKIE", angular.toJson({ + altAuthMethodId: scope.current_alt_auth_method_id, + eventId: scope.eventId, + errorCodename: errorCodename + }), options); + } + function setError(errorCodename, error) { + scope.error = error, scope.isOpenId && (setOIDCErrorCookie(errorCodename), redirectToLogin()); + } + if (scope.oidcError = $cookies.get("OIDC_ERROR_COOKIE") ? angular.fromJson($cookies.get("OIDC_ERROR_COOKIE")) : null, + scope.oidcError && (scope.selectedAltMethod = scope.oidcError.altAuthMethodId, scope.error = $i18next("avRegistration.loginError.openid-connect." + scope.oidcError.errorCodename, { + support: '' + ConfigService.contact.email + "" + })), scope.isOpenId) { if (!function() { - if ($cookies.get("OIDC_CSRF")) { - var csrf = scope.csrf = angular.fromJson($cookies.get("OIDC_CSRF")), uri = "?" + $window.location.hash.substr(1); - if ($cookies.remove("OIDC_CSRF"), !!csrf && angular.isObject(csrf) && angular.isString(csrf.randomState) && angular.isString(csrf.randomNonce) && angular.isString(csrf.providerId) && angular.isNumber(csrf.created) && angular.isDefined(csrf.altAuthMethodId) && getURIParameter("state", uri) === csrf.randomState && csrf.created - Date.now() < ConfigService.authTokenExpirationSeconds) return 1; - redirectToLogin(); - } else redirectToLogin(); + if (!$cookies.get("OIDC_CSRF")) return setOIDCErrorCookie("unexpectedOIDCRedirect"), + void redirectToLogin(); + var csrf = scope.csrf = angular.fromJson($cookies.get("OIDC_CSRF")), uri = "?" + $window.location.hash.substr(1); + return $cookies.remove("OIDC_CSRF"), !!csrf && angular.isObject(csrf) && angular.isString(csrf.randomState) && angular.isString(csrf.randomNonce) && angular.isString(csrf.providerId) && angular.isNumber(csrf.created) && angular.isDefined(csrf.altAuthMethodId) && getURIParameter("state", uri) === csrf.randomState && csrf.created - Date.now() < ConfigService.authTokenExpirationSeconds ? 1 : (setOIDCErrorCookie("invalidCsrf"), + void redirectToLogin()); }()) return; autheventid = scope.eventId = attrs.eventId = scope.csrf.eventId, scope.selectedAltMethod = scope.csrf.altAuthMethodId; } else autheventid = scope.eventId = attrs.eventId; @@ -606,17 +621,17 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist sessionStartedAtMs: sessionStartedAtMs }; }).value(), $window.sessionStorage.setItem("vote_permission_tokens", JSON.stringify(tokens)), - $window.location.href = "/booth/" + autheventid + "/vote") : scope.error = $i18next("avRegistration.loginError." + scope.method + ".unrecognizedServerResponse", { + $window.location.href = "/booth/" + autheventid + "/vote") : setError("unrecognizedServerResponse", $i18next("avRegistration.loginError." + scope.method + ".unrecognizedServerResponse", { support: '' + ConfigService.contact.email + "" - })) : (scope.sendingData = !1, scope.error = $i18next("avRegistration.loginError." + scope.method + ".invalidServerResponse", { + }))) : (scope.sendingData = !1, setError("invalidServerResponse", $i18next("avRegistration.loginError." + scope.method + ".invalidServerResponse", { support: '' + ConfigService.contact.email + "" - })); + }))); }, function(codename) { scope.sendingData = !1; codename = codename.data.error_codename; - scope.error = $i18next("avRegistration.loginError." + scope.method + "." + codename, { + setError("codename", $i18next("avRegistration.loginError." + scope.method + "." + codename, { support: '' + ConfigService.contact.email + "" - }); + })); }); } }, scope.getUriParam = function(paramName2) { @@ -670,7 +685,7 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist filledFields = _.filter(filledFields, function(el) { return null !== el.value || "otp-code" === el.type; }); - !scope.isOpenId && filledFields.length !== scope.login_fields.length || scope.isOtl || scope.isCensusQuery || scope.withCode || scope.loginUser(!0); + !scope.isOpenId && filledFields.length !== scope.login_fields.length || scope.isOtl || scope.isCensusQuery || scope.withCode || scope.oidcError || scope.loginUser(!0); }, scope.view = function(id) { Authmethod.viewEvent(id).then(function(altAuthMethod) { "ok" === altAuthMethod.data.status ? (scope.base_authevent = angular.copy(altAuthMethod.data.events),