Merge pull request #136 from glyptodon/clear-connections

GUAC-1126: Automatically clear connections and auth tokens upon login (fixes GUAC-1066).
This commit is contained in:
James Muehlner
2015-04-07 12:50:50 -07:00
4 changed files with 91 additions and 18 deletions

View File

@@ -23,8 +23,13 @@
/** /**
* A service for authenticating a user against the REST API. * A service for authenticating a user against the REST API.
*/ */
angular.module('auth').factory('authenticationService', ['$http', '$cookieStore', angular.module('auth').factory('authenticationService', ['$injector',
function authenticationService($http, $cookieStore) { function authenticationService($injector) {
// Required services
var $cookieStore = $injector.get('$cookieStore');
var $http = $injector.get('$http');
var $q = $injector.get('$q');
var service = {}; var service = {};
@@ -58,19 +63,65 @@ angular.module('auth').factory('authenticationService', ['$http', '$cookieStore'
* A promise which succeeds only if the login operation was successful. * A promise which succeeds only if the login operation was successful.
*/ */
service.authenticate = function authenticate(parameters) { 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', method: 'POST',
url: 'api/tokens', url: 'api/tokens',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
data: $.param(parameters), data: $.param(parameters),
}).success(function success(data, status, headers, config) { })
$cookieStore.put(AUTH_COOKIE_ID, {
authToken : data.authToken, // If authentication succeeds, handle received auth data
userID : data.userID .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. * successful.
*/ */
service.logout = function logout() { service.logout = function logout() {
// Clear authentication data
var token = service.getCurrentToken();
$cookieStore.remove(AUTH_COOKIE_ID);
// Delete old token
return $http({ return $http({
method: 'DELETE', method: 'DELETE',
url: 'api/tokens/' + encodeURIComponent(service.getCurrentToken()) url: 'api/tokens/' + token
}); });
}; };
/** /**

View File

@@ -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 // Disconnect each managed client
for (var id in service.managedClients) for (var id in service.managedClients)
service.managedClients[id].client.disconnect(); service.managedClients[id].client.disconnect();
}); // Clear managed clients
service.managedClients = {};
};
// Disconnect all clients when window is unloaded
$window.addEventListener('unload', service.clear);
return service; return service;

View File

@@ -24,8 +24,9 @@ angular.module('login').controller('loginController', ['$scope', '$injector',
function loginController($scope, $injector) { function loginController($scope, $injector) {
// Required services // Required services
var $location = $injector.get("$location"); var $location = $injector.get('$location');
var authenticationService = $injector.get("authenticationService"); var authenticationService = $injector.get('authenticationService');
var guacClientManager = $injector.get('guacClientManager');
var userPageService = $injector.get('userPageService'); var userPageService = $injector.get('userPageService');
/** /**
@@ -48,19 +49,25 @@ angular.module('login').controller('loginController', ['$scope', '$injector',
*/ */
$scope.login = function login() { $scope.login = function login() {
// Attempt login // Attempt login once existing session is destroyed
authenticationService.login($scope.username, $scope.password) authenticationService.login($scope.username, $scope.password)
// Redirect to main view upon success // 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() userPageService.getHomePage()
.then(function homePageRetrieved(homePage) { .then(function homePageRetrieved(homePage) {
$location.url(homePage.url); $location.url(homePage.url);
}); });
}) })
// Reset and focus password upon failure // Reset and focus password upon failure
.error(function error(data, status, headers, config) { ['catch'](function loginFailed() {
$scope.loginError = true; $scope.loginError = true;
$scope.passwordFocused = true; $scope.passwordFocused = true;
$scope.password = ''; $scope.password = '';

View File

@@ -23,4 +23,4 @@
/** /**
* The module for the login functionality. * The module for the login functionality.
*/ */
angular.module('login', ['element', 'navigation']); angular.module('login', ['client', 'element', 'navigation']);