From c02e5b72a9e8b707ba00b3f8a4c7f9cfc4a9aca9 Mon Sep 17 00:00:00 2001 From: Eduardo Robles Elvira Date: Mon, 13 Nov 2023 07:05:51 +0100 Subject: [PATCH] WIP --- .../login-directive/login-directive.js | 108 +++++-- .../openid-connect-directive.js | 273 ------------------ dist/appCommon-v10.0.2.js | 31 +- 3 files changed, 102 insertions(+), 310 deletions(-) delete mode 100644 avRegistration/openid-connect-directive/openid-connect-directive.js diff --git a/avRegistration/login-directive/login-directive.js b/avRegistration/login-directive/login-directive.js index 9f017efa..a1e81d15 100644 --- a/avRegistration/login-directive/login-directive.js +++ b/avRegistration/login-directive/login-directive.js @@ -90,6 +90,81 @@ angular.module('avRegistration') } } + // Gets the list of current auth method providers + function getCurrentOidcProviders(auth_event) + { + if ( + !auth_event.auth_method_config || + !auth_event.auth_method_config.config || + !auth_event.auth_method_config.config.provider_ids + ) { + return []; + } + return _.map( + auth_event.auth_method_config.config.provider_ids, + function (provider_id) { + return _.find( + auth_event.oidc_providers, + function (provider) { return provider.public_info.id === provider_id; } + ); + } + ); + } + + // Returns the logout url if any from the appropiate openidprovider + // TODO: logout asumes that you are using the first provider, so it + // basically supports only one provider + function getLogoutUri(authEvent) + { + var eventId = null; + var redirectUri = null; + if (scope.csrf) + { + eventId = scope.csrf.eventId; + redirectUri = "/election/" + eventId + "/public/login"; + } else { + redirectUri = ConfigService.defaultRoute; + } + scope.oidc_providers = authEvent.oidc_providers; + scope.current_oidc_providers = getCurrentOidcProviders(authEvent); + + if (scope.current_oidc_providers.length === 0) + { + return redirectUri; + } + + var oidcProvider = _.find( + authEvent.oidc_providers, + function (provider) { + return provider.public_info.id === scope.csrf.providerId; + } + ); + + if (!oidcProvider || !oidcProvider.logout_uri) { + return redirectUri; + } + + redirectUri = oidcProvider.logout_uri; + redirectUri = redirectUri.replace("__EVENT_ID__", "" + eventId); + + var postfix = "_authevent_" + eventId; + if (!!$cookies.get("id_token_" + postfix)) + { + redirectUri = redirectUri.replace( + "__ID_TOKEN__", $cookies.get("id_token_" + postfix) + ); + + // if __ID_TOKEN__ is there but we cannot replace it, we need to + // directly redirect to the login, otherwise the URI might show an + // error 500 + } else if (redirectUri.indexOf("__ID_TOKEN__") > -1) + { + redirectUri = "/election/" + eventId + "/public/login"; + } + + return redirectUri; + } + // Redirects to the login page of the respective event_id if any function redirectToLogin() { @@ -100,7 +175,7 @@ angular.module('avRegistration') scope.sendingData = true; - if (!scope.csrf) + if (!scope.csrf || !scope.csrf.eventId) { $window.location.href = ConfigService.defaultRoute; return; @@ -118,13 +193,11 @@ angular.module('avRegistration') simpleRedirectToLogin(); return; } - // TODO: add back getLogoutUri - window.alert("TODO getLogoutUri not implemented"); - // var postfix = "_authevent_" + eventId; - // var uri = getLogoutUri(); - // $cookies.remove("id_token_" + postfix); - // $window.location.href = uri; + var postfix = "_authevent_" + eventId; + var uri = getLogoutUri(response.data.events); + $cookies.remove("id_token_" + postfix); + $window.location.href = uri; }, function onError() { @@ -293,27 +366,6 @@ angular.module('avRegistration') return null !== email.match(pattern); } - // Gets the list of current auth method providers - function getCurrentOidcProviders(auth_event) - { - if ( - !auth_event.auth_method_config || - !auth_event.auth_method_config.config || - !auth_event.auth_method_config.config.provider_ids - ) { - return []; - } - return _.map( - auth_event.auth_method_config.config.provider_ids, - function (provider_id) { - return _.find( - auth_event.oidc_providers, - function (provider) { return provider.public_info.id === provider_id; } - ); - } - ); - } - // obtain the openid login data function getOpenidLoginData() { diff --git a/avRegistration/openid-connect-directive/openid-connect-directive.js b/avRegistration/openid-connect-directive/openid-connect-directive.js deleted file mode 100644 index 67dd56a9..00000000 --- a/avRegistration/openid-connect-directive/openid-connect-directive.js +++ /dev/null @@ -1,273 +0,0 @@ -/** - * This file is part of common-ui. - * Copyright (C) 2015-2016 Sequent Tech Inc - - * common-ui is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License. - - * common-ui is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - - * You should have received a copy of the GNU Affero General Public License - * along with common-ui. If not, see . -**/ - -angular.module('avRegistration') - .directive( - 'avOpenidConnect', - function( - $cookies, - $window, - $location, - ConfigService, - Authmethod - ) { - // we use it as something similar to a controller here - function link(scope, element, attrs) - { - // Maximum Oauth Login Timeout is 5 minutes - var maxOAuthLoginTimeout = 1000 * 60 * 5; - - scope.csrf = null; - - // simply redirect to login - function simpleRedirectToLogin() - { - if (scope.csrf) - { - $window.location.href = "/election/" + scope.csrf.eventId + "/public/login"; - } else { - $window.location.href = "/"; - } - } - - // Returns the logout url if any from the appropiate openidprovider - // TODO: logout asumes that you are using the first provider, so it - // basically supports only one provider - function getLogoutUri() - { - if (ConfigService.openIDConnectProviders.length === 0 || !ConfigService.openIDConnectProviders[0].logout_uri) - { - return false; - } - - var eventId = null; - if (scope.csrf) - { - eventId = scope.csrf.eventId; - } - - var uri = ConfigService.openIDConnectProviders[0].logout_uri; - uri = uri.replace("__EVENT_ID__", "" + eventId); - - var postfix = "_authevent_" + eventId; - if (!!$cookies.get("id_token_" + postfix)) - { - uri = uri.replace("__ID_TOKEN__", $cookies.get("id_token_" + postfix)); - - // if __ID_TOKEN__ is there but we cannot replace it, we need to - // directly redirect to the login, otherwise the URI might show an - // error 500 - } else if (uri.indexOf("__ID_TOKEN__") > -1) - { - uri = "/election/" + eventId + "/public/login"; - } - - return uri; - } - - scope.redirectingToUri = false; - - // Redirects to the login page of the respective event_id if any - function redirectToLogin() - { - if (scope.redirectingToUri) - { - return; - } - - scope.redirectingToUri = true; - - var eventId = null; - if (scope.csrf) - { - eventId = scope.csrf.eventId; - } else { - $window.location.href = "/"; - return; - } - - Authmethod.viewEvent(eventId) - .then( - function onSuccess(response) - { - if (response.data.status !== "ok" || !response.data.events || response.data.events.auth_method !== 'openid-connect' || !getLogoutUri()) - { - simpleRedirectToLogin(); - return; - } - - var postfix = "_authevent_" + eventId; - var uri = getLogoutUri(); - $cookies.remove("id_token_" + postfix); - $window.location.href = uri; - }, - function onError(response) - { - simpleRedirectToLogin(); - } - ); - } - - // Get the decoded value of a uri parameter from any uri. The uri does not - // need to have any domain, it can start with the character "?" - function getURIParameter(paramName, uri) - { - var paramName2 = paramName.replace(/[\[\]]/g, '\\$&'); - var rx = new RegExp('[?&]' + paramName2 + '(=([^&#]*)|&|#|$)'); - var params = rx.exec(uri); - - if (!params) - { - return null; - } - - if (!params[2]) - { - return ''; - } - return decodeURIComponent(params[2].replace(/\+/g, ' ')); - } - - // validates the CSRF token - function validateCsrfToken() - { - if (!$cookies.get('openid-connect-csrf')) - { - redirectToLogin(); - return null; - } - - // validate csrf token format and data - var csrf = scope.csrf = angular.fromJson($cookies.get('openid-connect-csrf')); - var uri = "?" + $window.location.hash.substr(1); - - // NOTE: if you need to debug this callback, obtain the callback - // URL, get the callback received in the server (to obtain the - // nonce) that was received by the client and change the data here - // accordingly and set here the debug break point, then execute - // a line like the following in the comment. - // - // The only data that needs to be changed is the randomNonnce and - // the eventId. - // - // csrf = scope.csrf = { - // randomNonce: 'something', - // randomState: getURIParameter("state", uri), - // created: Date.now(), - // eventId: 11111 - // }; - - $cookies.remove('openid-connect-csrf'); - var isCsrfValid = (!!csrf && - angular.isObject(csrf) && - angular.isString(csrf.randomState) && - angular.isString(csrf.randomNonce) && - angular.isNumber(csrf.created) && - getURIParameter("state", uri) === csrf.randomState && - csrf.created - Date.now() < maxOAuthLoginTimeout - ); - - if (!isCsrfValid) - { - redirectToLogin(); - return null; - } - return true; - } - - // Process an OpenId Connect callback coming from the provider, try to - // validate the callback data and get the authentication token from our - // server and redirect to vote - function processOpenIdAuthCallback() - { - // validate csrf token from uri and from state in the hash - validateCsrfToken(); - - var uri = "?" + $window.location.hash.substr(1); - - var data = { - id_token: getURIParameter("id_token", uri), - provider: scope.csrf.providerId, - nonce: scope.csrf.randomNonce - }; - - var options = {}; - if (ConfigService.authTokenExpirationSeconds) { - options.expires = new Date(Date.now() + 1000 * ConfigService.authTokenExpirationSeconds); - } - - var postfix = "_authevent_" + scope.csrf.eventId; - $cookies.put("id_token_" + postfix, data.id_token, options); - - // Send the authentication request to our server - Authmethod.login(data, scope.csrf.eventId) - .then( - function onSuccess(response) - { - if (response.data.status === "ok") - { - scope.khmac = response.data.khmac; - var postfix = "_authevent_" + scope.csrf.eventId; - $cookies.put("authevent_" + scope.csrf.eventId, scope.csrf.eventId, options); - $cookies.put("userid" + postfix, response.data.username, options); - $cookies.put("user" + postfix, response.data.username, options); - $cookies.put("auth" + postfix, response.data['auth-token'], options); - $cookies.put("isAdmin" + postfix, false, options); - Authmethod.setAuth($cookies.get("auth" + postfix), scope.isAdmin, scope.csrf.eventId); - - if (angular.isDefined(response.data['redirect-to-url'])) - { - $window.location.href = response.data['redirect-to-url']; - } - else - { - // redirecting to vote link - Authmethod.getPerm("vote", "AuthEvent", scope.csrf.eventId) - .then(function onSuccess(response2) - { - var khmac = response2.data['permission-token']; - var path = khmac.split(";")[1]; - var hash = path.split("/")[0]; - var msg = path.split("/")[1]; - $window.location.href = '/booth/' + scope.csrf.eventId + '/vote/' + hash + '/' + msg; - }); - } - } else - { - // TODO: show error - redirectToLogin(); - return; - } - }, - function onError(response) - { - // TODO: show error - redirectToLogin(); - return; - } - ); - } - - processOpenIdAuthCallback(); - } - return { - restrict: 'AE', - scope: true, - link: link, - templateUrl: 'avRegistration/openid-connect-directive/openid-connect-directive.html' - }; - }); diff --git a/dist/appCommon-v10.0.2.js b/dist/appCommon-v10.0.2.js index 232ce36d..2135f235 100644 --- a/dist/appCommon-v10.0.2.js +++ b/dist/appCommon-v10.0.2.js @@ -459,11 +459,28 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist function simpleRedirectToLogin() { scope.csrf ? $window.location.href = "/election/" + scope.csrf.eventId + "/public/login" : $window.location.href = ConfigService.defaultRoute; } + function getCurrentOidcProviders(auth_event) { + return auth_event.auth_method_config && auth_event.auth_method_config.config && auth_event.auth_method_config.config.provider_ids ? _.map(auth_event.auth_method_config.config.provider_ids, function(provider_id) { + return _.find(auth_event.oidc_providers, function(provider) { + return provider.public_info.id === provider_id; + }); + }) : []; + } function redirectToLogin() { var eventId; - scope.sendingData || (scope.sendingData = !0, scope.csrf ? (eventId = scope.csrf.eventId, - Authmethod.viewEvent(eventId).then(function(response) { - "ok" === response.data.status && response.data.events ? window.alert("TODO getLogoutUri not implemented") : simpleRedirectToLogin(); + scope.sendingData || (scope.sendingData = !0, scope.csrf && scope.csrf.eventId ? (eventId = scope.csrf.eventId, + Authmethod.viewEvent(eventId).then(function(uri) { + var postfix; + "ok" === uri.data.status && uri.data.events ? (postfix = "_authevent_" + eventId, + uri = function(postfix) { + var eventId = null, redirectUri = null, redirectUri = scope.csrf ? "/election/" + (eventId = scope.csrf.eventId) + "/public/login" : ConfigService.defaultRoute; + return scope.oidc_providers = postfix.oidc_providers, scope.current_oidc_providers = getCurrentOidcProviders(postfix), + 0 === scope.current_oidc_providers.length || (postfix = _.find(postfix.oidc_providers, function(provider) { + return provider.public_info.id === scope.csrf.providerId; + })) && postfix.logout_uri && (redirectUri = (redirectUri = postfix.logout_uri).replace("__EVENT_ID__", "" + eventId), + postfix = "_authevent_" + eventId, $cookies.get("id_token_" + postfix) ? redirectUri = redirectUri.replace("__ID_TOKEN__", $cookies.get("id_token_" + postfix)) : -1 < redirectUri.indexOf("__ID_TOKEN__") && (redirectUri = "/election/" + eventId + "/public/login")), + redirectUri; + }(uri.data.events), $cookies.remove("id_token_" + postfix), $window.location.href = uri) : simpleRedirectToLogin(); }, function() { simpleRedirectToLogin(); })) : $window.location.href = ConfigService.defaultRoute); @@ -647,13 +664,9 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist authevent.extra_fields = altAuthMethod.extra_fields, authevent.auth_method_config = altAuthMethod.auth_method_config, authevent.auth_method = altAuthMethod.auth_method_name, scope.apply(authevent))); }, scope.apply = function(authevent) { - var auth_event; scope.hasOtpFieldsCode = Authmethod.hasOtpCodeField(authevent), scope.method = authevent.auth_method, - scope.oidc_providers = authevent.oidc_providers, scope.current_oidc_providers = (auth_event = authevent).auth_method_config && auth_event.auth_method_config.config && auth_event.auth_method_config.config.provider_ids ? _.map(auth_event.auth_method_config.config.provider_ids, function(provider_id) { - return _.find(auth_event.oidc_providers, function(provider) { - return provider.public_info.id === provider_id; - }); - }) : [], (scope.hasOtpFieldsCode || _.contains([ "sms-otp", "email-otp" ], scope.method)) && (scope.skipSendAuthCode = scope.successfulRegistration), + scope.oidc_providers = authevent.oidc_providers, scope.current_oidc_providers = getCurrentOidcProviders(authevent), + (scope.hasOtpFieldsCode || _.contains([ "sms-otp", "email-otp" ], scope.method)) && (scope.skipSendAuthCode = scope.successfulRegistration), scope.name = authevent.name, scope.parseAuthToken(), scope.registrationAllowed = "open" === authevent.census && (autheventid !== adminId || ConfigService.allowAdminRegistration), scope.isCensusQuery || scope.withCode || scope.isOtl ? scope.withCode ? scope.login_fields = Authmethod.getLoginWithCode(authevent) : scope.isCensusQuery ? scope.login_fields = Authmethod.getCensusQueryFields(authevent) : scope.isOtl && (scope.login_fields = Authmethod.getOtlFields(authevent)) : scope.login_fields = Authmethod.getLoginFields(authevent), scope.login_fields.sort(function(a, b) {