diff --git a/guacamole/src/main/webapp/app/auth/service/authenticationService.js b/guacamole/src/main/webapp/app/auth/service/authenticationService.js index 339a3e1cf..e6fc0d789 100644 --- a/guacamole/src/main/webapp/app/auth/service/authenticationService.js +++ b/guacamole/src/main/webapp/app/auth/service/authenticationService.js @@ -42,7 +42,8 @@ angular.module('auth').factory('authenticationService', ['$injector', function authenticationService($injector) { // Required types - var Error = $injector.get('Error'); + var AuthenticationResult = $injector.get('AuthenticationResult'); + var Error = $injector.get('Error'); // Required services var $cookieStore = $injector.get('$cookieStore'); @@ -53,13 +54,61 @@ angular.module('auth').factory('authenticationService', ['$injector', var service = {}; /** - * The unique identifier of the local cookie which stores the user's - * current authentication token and username. + * The unique identifier of the local cookie which stores the result of the + * last authentication attempt. * * @type String */ var AUTH_COOKIE_ID = "GUAC_AUTH"; + /** + * Retrieves the last successful authentication result. If the user has not + * yet authenticated, the user has logged out, or the last authentication + * attempt failed, null is returned. + * + * @returns {AuthenticationResult} + * The last successful authentication result, or null if the user is not + * currently authenticated. + */ + var getAuthenticationResult = function getAuthenticationResult() { + + // Return explicit null if no auth data is currently stored + var data = $cookieStore.get(AUTH_COOKIE_ID); + if (!data) + return null; + + return new AuthenticationResult(data); + + }; + + /** + * Stores the given authentication result for future retrieval. The given + * result MUST be the result of the most recent authentication attempt. + * + * @param {AuthenticationResult} data + * The last successful authentication result, or null if the last + * authentication attempt failed. + */ + var setAuthenticationResult = function setAuthenticationResult(data) { + + // Clear the currently-stored result if the last attempt failed + if (!data) + $cookieStore.remove(AUTH_COOKIE_ID); + + // Otherwise store the authentication attempt directly + else + $cookieStore.put(AUTH_COOKIE_ID, data); + + }; + + /** + * Clears the stored authentication result, if any. If no authentication + * result is currently stored, this function has no effect. + */ + var clearAuthenticationResult = function clearAuthenticationResult() { + setAuthenticationResult(null); + }; + /** * Makes a request to authenticate a user using the token REST API endpoint * and given arbitrary parameters, returning a promise that succeeds only @@ -95,12 +144,7 @@ angular.module('auth').factory('authenticationService', ['$injector', var completeAuthentication = function completeAuthentication(data) { // Store auth data - $cookieStore.put(AUTH_COOKIE_ID, { - 'authToken' : data.authToken, - 'username' : data.username, - 'dataSource' : data.dataSource, - 'availableDataSources' : data.availableDataSources - }); + setAuthenticationResult(new AuthenticationResult(data)); // Process is complete authenticationProcess.resolve(); @@ -114,7 +158,7 @@ angular.module('auth').factory('authenticationService', ['$injector', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - data: $.param(parameters), + data: $.param(parameters) }) // If authentication succeeds, handle received auth data @@ -243,7 +287,7 @@ angular.module('auth').factory('authenticationService', ['$injector', // Clear authentication data var token = service.getCurrentToken(); - $cookieStore.remove(AUTH_COOKIE_ID); + clearAuthenticationResult(); // Notify listeners that a token is being destroyed $rootScope.$broadcast('guacLogout', token); @@ -280,7 +324,7 @@ angular.module('auth').factory('authenticationService', ['$injector', service.getCurrentUsername = function getCurrentUsername() { // Return username, if available - var authData = $cookieStore.get(AUTH_COOKIE_ID); + var authData = getAuthenticationResult(); if (authData) return authData.username; @@ -300,7 +344,7 @@ angular.module('auth').factory('authenticationService', ['$injector', service.getCurrentToken = function getCurrentToken() { // Return auth token, if available - var authData = $cookieStore.get(AUTH_COOKIE_ID); + var authData = getAuthenticationResult(); if (authData) return authData.authToken; @@ -320,7 +364,7 @@ angular.module('auth').factory('authenticationService', ['$injector', service.getDataSource = function getDataSource() { // Return data source, if available - var authData = $cookieStore.get(AUTH_COOKIE_ID); + var authData = getAuthenticationResult(); if (authData) return authData.dataSource; @@ -340,7 +384,7 @@ angular.module('auth').factory('authenticationService', ['$injector', service.getAvailableDataSources = function getAvailableDataSources() { // Return data sources, if available - var authData = $cookieStore.get(AUTH_COOKIE_ID); + var authData = getAuthenticationResult(); if (authData) return authData.availableDataSources; diff --git a/guacamole/src/main/webapp/app/auth/types/AuthenticationResult.js b/guacamole/src/main/webapp/app/auth/types/AuthenticationResult.js new file mode 100644 index 000000000..e2774619f --- /dev/null +++ b/guacamole/src/main/webapp/app/auth/types/AuthenticationResult.js @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Service which defines the AuthenticationResult class. + */ +angular.module('auth').factory('AuthenticationResult', [function defineAuthenticationResult() { + + /** + * The object returned by REST API calls when representing the successful + * result of an authentication attempt. + * + * @constructor + * @param {AuthenticationResult|Object} [template={}] + * The object whose properties should be copied within the new + * AuthenticationResult. + */ + var AuthenticationResult = function AuthenticationResult(template) { + + // Use empty object by default + template = template || {}; + + /** + * The unique token generated for the user that authenticated. + * + * @type String + */ + this.authToken = template.authToken; + + /** + * The name which uniquely identifies the user that authenticated. + * + * @type String + */ + this.username = template.username; + + /** + * The unique identifier of the data source which authenticated the + * user. + * + * @type String + */ + this.dataSource = template.dataSource; + + /** + * The identifiers of all data sources available to the user that + * authenticated. + * + * @type String[] + */ + this.availableDataSources = template.availableDataSources; + + }; + + /** + * The username reserved by the Guacamole extension API for users which have + * authenticated anonymously. + * + * @type String + */ + AuthenticationResult.ANONYMOUS_USERNAME = ''; + + return AuthenticationResult; + +}]);