diff --git a/app/portainer/services/localStorage.js b/app/portainer/services/localStorage.js index 134eaff60..d50369710 100644 --- a/app/portainer/services/localStorage.js +++ b/app/portainer/services/localStorage.js @@ -14,6 +14,12 @@ angular.module('portainer.app') getEndpointPublicURL: function() { return localStorageService.get('ENDPOINT_PUBLIC_URL'); }, + storeLoginStateUUID: function(uuid) { + localStorageService.set('LOGIN_STATE_UUID', uuid); + }, + getLoginStateUUID: function() { + return localStorageService.get('LOGIN_STATE_UUID'); + }, storeOfflineMode: function(isOffline) { localStorageService.set('ENDPOINT_OFFLINE_MODE', isOffline); }, diff --git a/app/portainer/views/auth/authController.js b/app/portainer/views/auth/authController.js index 120de69af..7bd3295cb 100644 --- a/app/portainer/views/auth/authController.js +++ b/app/portainer/views/auth/authController.js @@ -1,6 +1,8 @@ +import uuidv4 from 'uuid/v4'; + angular.module('portainer.app') -.controller('AuthenticationController', ['$async', '$q', '$scope', '$state', '$stateParams', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'ExtensionService', 'StateManager', 'Notifications', 'SettingsService', 'URLHelper', -function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, UserService, EndpointService, ExtensionService, StateManager, Notifications, SettingsService, URLHelper) { +.controller('AuthenticationController', ['$async', '$q', '$scope', '$state', '$stateParams', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'ExtensionService', 'StateManager', 'Notifications', 'SettingsService', 'URLHelper', 'LocalStorage', +function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, UserService, EndpointService, ExtensionService, StateManager, Notifications, SettingsService, URLHelper, LocalStorage) { $scope.logo = StateManager.getState().application.logo; $scope.formValues = { @@ -116,12 +118,23 @@ function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, Us return 'OAuth'; } + function generateState() { + const uuid = uuidv4(); + LocalStorage.storeLoginStateUUID(uuid); + return '&state=' + uuid; + } + + function hasValidState(state) { + const savedUUID = LocalStorage.getLoginStateUUID(); + return savedUUID === state; + } + function initView() { SettingsService.publicSettings() .then(function success(settings) { $scope.AuthenticationMethod = settings.AuthenticationMethod; - $scope.OAuthLoginURI = settings.OAuthLoginURI; $scope.state.OAuthProvider = determineOauthProvider(settings.OAuthLoginURI); + $scope.OAuthLoginURI = settings.OAuthLoginURI + generateState(); }); if ($stateParams.logout || $stateParams.error) { @@ -142,8 +155,9 @@ function($async, $q, $scope, $state, $stateParams, $sanitize, Authentication, Us authenticatedFlow(); } - var code = URLHelper.getParameter('code'); - if (code) { + const code = URLHelper.getParameter('code'); + const state = URLHelper.getParameter('state'); + if (code && hasValidState(state)) { oAuthLogin(code); } else { $scope.state.isInOAuthProcess = false;