diff --git a/guacamole/src/main/webapp/app/auth/service/authenticationService.js b/guacamole/src/main/webapp/app/auth/service/authenticationService.js index 9b1983821..c98b36bcc 100644 --- a/guacamole/src/main/webapp/app/auth/service/authenticationService.js +++ b/guacamole/src/main/webapp/app/auth/service/authenticationService.js @@ -23,8 +23,13 @@ /** * A service for authenticating a user against the REST API. */ -angular.module('auth').factory('authenticationService', ['$http', '$cookieStore', - function authenticationService($http, $cookieStore) { +angular.module('auth').factory('authenticationService', ['$injector', + function authenticationService($injector) { + + // Required services + var $cookieStore = $injector.get('$cookieStore'); + var $http = $injector.get('$http'); + var $q = $injector.get('$q'); var service = {}; @@ -58,19 +63,65 @@ angular.module('auth').factory('authenticationService', ['$http', '$cookieStore' * A promise which succeeds only if the login operation was successful. */ service.authenticate = function authenticate(parameters) { - return $http({ + + var authenticationProcess = $q.defer(); + + /** + * Stores the given authentication data within the browser and marks + * the authentication process as completed. + * + * @param {Object} data + * The authentication data returned by the token REST endpoint. + */ + var completeAuthentication = function completeAuthentication(data) { + + // Store auth data + $cookieStore.put(AUTH_COOKIE_ID, { + authToken : data.authToken, + userID : data.userID + }); + + // Process is complete + authenticationProcess.resolve(); + + }; + + // Attempt authentication + $http({ method: 'POST', url: 'api/tokens', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: $.param(parameters), - }).success(function success(data, status, headers, config) { - $cookieStore.put(AUTH_COOKIE_ID, { - authToken : data.authToken, - userID : data.userID - }); + }) + + // If authentication succeeds, handle received auth data + .success(function authenticationSuccessful(data) { + + var currentToken = service.getCurrentToken(); + + // If a new token was received, ensure the old token is invalidated + if (currentToken && data.authToken !== currentToken) { + service.logout() + ['finally'](function logoutComplete() { + completeAuthentication(data); + }); + } + + // Otherwise, just finish the auth process + else + completeAuthentication(data); + + }) + + // If authentication fails, propogate failure to returned promise + .error(function authenticationFailed() { + authenticationProcess.reject(); }); + + return authenticationProcess.promise; + }; /** @@ -142,10 +193,17 @@ angular.module('auth').factory('authenticationService', ['$http', '$cookieStore' * successful. */ service.logout = function logout() { + + // Clear authentication data + var token = service.getCurrentToken(); + $cookieStore.remove(AUTH_COOKIE_ID); + + // Delete old token return $http({ method: 'DELETE', - url: 'api/tokens/' + encodeURIComponent(service.getCurrentToken()) + url: 'api/tokens/' + token }); + }; /** diff --git a/guacamole/src/main/webapp/app/client/services/guacClientManager.js b/guacamole/src/main/webapp/app/client/services/guacClientManager.js index c3d0e0f56..67d20b98d 100644 --- a/guacamole/src/main/webapp/app/client/services/guacClientManager.js +++ b/guacamole/src/main/webapp/app/client/services/guacClientManager.js @@ -127,14 +127,22 @@ angular.module('client').factory('guacClientManager', ['$injector', }; - // Disconnect all clients when window is unloaded - $window.addEventListener('unload', function disconnectAllClients() { + /** + * Disconnects and removes all currently-connected clients. + */ + service.clear = function clear() { // Disconnect each managed client for (var id in service.managedClients) service.managedClients[id].client.disconnect(); - }); + // Clear managed clients + service.managedClients = {}; + + }; + + // Disconnect all clients when window is unloaded + $window.addEventListener('unload', service.clear); return service; diff --git a/guacamole/src/main/webapp/app/login/controllers/loginController.js b/guacamole/src/main/webapp/app/login/controllers/loginController.js index 565abc6c7..6d5a781f2 100644 --- a/guacamole/src/main/webapp/app/login/controllers/loginController.js +++ b/guacamole/src/main/webapp/app/login/controllers/loginController.js @@ -24,8 +24,9 @@ angular.module('login').controller('loginController', ['$scope', '$injector', function loginController($scope, $injector) { // Required services - var $location = $injector.get("$location"); - var authenticationService = $injector.get("authenticationService"); + var $location = $injector.get('$location'); + var authenticationService = $injector.get('authenticationService'); + var guacClientManager = $injector.get('guacClientManager'); var userPageService = $injector.get('userPageService'); /** @@ -48,19 +49,25 @@ angular.module('login').controller('loginController', ['$scope', '$injector', */ $scope.login = function login() { - // Attempt login + // Attempt login once existing session is destroyed authenticationService.login($scope.username, $scope.password) // Redirect to main view upon success - .success(function success(data, status, headers, config) { + .then(function loginSuccessful() { + + // Provide user with clean environment + guacClientManager.clear(); + + // Redirect to main view userPageService.getHomePage() .then(function homePageRetrieved(homePage) { $location.url(homePage.url); }); + }) // Reset and focus password upon failure - .error(function error(data, status, headers, config) { + ['catch'](function loginFailed() { $scope.loginError = true; $scope.passwordFocused = true; $scope.password = ''; diff --git a/guacamole/src/main/webapp/app/login/loginModule.js b/guacamole/src/main/webapp/app/login/loginModule.js index 54e531233..289aefa9d 100644 --- a/guacamole/src/main/webapp/app/login/loginModule.js +++ b/guacamole/src/main/webapp/app/login/loginModule.js @@ -23,4 +23,4 @@ /** * The module for the login functionality. */ -angular.module('login', ['element', 'navigation']); +angular.module('login', ['client', 'element', 'navigation']);