mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-30 00:23:21 +00:00 
			
		
		
		
	GUAC-919: Rename LoginRESTService to TokenRESTService and provide logout semantics. Move Angular auth stuff to own module. Actually logout user.
This commit is contained in:
		| @@ -26,7 +26,7 @@ import com.google.inject.Scopes; | |||||||
| import com.google.inject.servlet.ServletModule; | import com.google.inject.servlet.ServletModule; | ||||||
| import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; | import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; | ||||||
| import org.codehaus.jackson.jaxrs.JacksonJsonProvider; | import org.codehaus.jackson.jaxrs.JacksonJsonProvider; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.auth.LoginRESTService; | import org.glyptodon.guacamole.net.basic.rest.auth.TokenRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; | import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; | import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService; | import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService; | ||||||
| @@ -51,7 +51,7 @@ public class RESTServletModule extends ServletModule { | |||||||
|         bind(PermissionRESTService.class); |         bind(PermissionRESTService.class); | ||||||
|         bind(ProtocolRESTService.class); |         bind(ProtocolRESTService.class); | ||||||
|         bind(UserRESTService.class); |         bind(UserRESTService.class); | ||||||
|         bind(LoginRESTService.class); |         bind(TokenRESTService.class); | ||||||
|          |          | ||||||
|         // Set up the servlet and JSON mappings |         // Set up the servlet and JSON mappings | ||||||
|         bind(GuiceContainer.class); |         bind(GuiceContainer.class); | ||||||
|   | |||||||
| @@ -131,6 +131,7 @@ public class BasicTokenSessionMap implements TokenSessionMap { | |||||||
|                 if (age >= sessionTimeout) { |                 if (age >= sessionTimeout) { | ||||||
|                     logger.debug("Session \"{}\" has timed out.", entry.getKey()); |                     logger.debug("Session \"{}\" has timed out.", entry.getKey()); | ||||||
|                     entries.remove(); |                     entries.remove(); | ||||||
|  |                     session.invalidate(); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // Otherwise, no other sessions can possibly be old enough |                 // Otherwise, no other sessions can possibly be old enough | ||||||
| @@ -162,6 +163,11 @@ public class BasicTokenSessionMap implements TokenSessionMap { | |||||||
|         sessionMap.put(authToken, session); |         sessionMap.put(authToken, session); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public GuacamoleSession remove(String authToken) { | ||||||
|  |         return sessionMap.remove(authToken); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void shutdown() { |     public void shutdown() { | ||||||
|         executor.shutdownNow(); |         executor.shutdownNow(); | ||||||
|   | |||||||
| @@ -24,9 +24,11 @@ package org.glyptodon.guacamole.net.basic.rest.auth; | |||||||
| 
 | 
 | ||||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||||
| import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||||
|  | import javax.ws.rs.DELETE; | ||||||
| import javax.ws.rs.FormParam; | import javax.ws.rs.FormParam; | ||||||
| import javax.ws.rs.POST; | import javax.ws.rs.POST; | ||||||
| import javax.ws.rs.Path; | import javax.ws.rs.Path; | ||||||
|  | import javax.ws.rs.PathParam; | ||||||
| import javax.ws.rs.Produces; | import javax.ws.rs.Produces; | ||||||
| import javax.ws.rs.core.Context; | import javax.ws.rs.core.Context; | ||||||
| import javax.ws.rs.core.MediaType; | import javax.ws.rs.core.MediaType; | ||||||
| @@ -42,16 +44,13 @@ import org.slf4j.Logger; | |||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A service for authenticating to the Guacamole REST API. Given valid |  * A service for managing auth tokens via the Guacamole REST API. | ||||||
|  * credentials, the service will return an auth token. Invalid credentials will |  | ||||||
|  * result in a permission error. |  | ||||||
|  *  |  *  | ||||||
|  * @author James Muehlner |  * @author James Muehlner | ||||||
|  */ |  */ | ||||||
| 
 | @Path("/token") | ||||||
| @Path("/login") |  | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| public class LoginRESTService { | public class TokenRESTService { | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * The authentication provider used to authenticate this user. |      * The authentication provider used to authenticate this user. | ||||||
| @@ -74,7 +73,7 @@ public class LoginRESTService { | |||||||
|     /** |     /** | ||||||
|      * Logger for this class. |      * Logger for this class. | ||||||
|      */ |      */ | ||||||
|     private static final Logger logger = LoggerFactory.getLogger(LoginRESTService.class); |     private static final Logger logger = LoggerFactory.getLogger(TokenRESTService.class); | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Authenticates a user, generates an auth token, associates that auth token |      * Authenticates a user, generates an auth token, associates that auth token | ||||||
| @@ -88,7 +87,7 @@ public class LoginRESTService { | |||||||
|      */ |      */ | ||||||
|     @POST |     @POST | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public APIAuthToken login(@FormParam("username") String username, |     public APIAuthToken createToken(@FormParam("username") String username, | ||||||
|             @FormParam("password") String password,  |             @FormParam("password") String password,  | ||||||
|             @Context HttpServletRequest request) throws GuacamoleException { |             @Context HttpServletRequest request) throws GuacamoleException { | ||||||
|          |          | ||||||
| @@ -121,4 +120,23 @@ public class LoginRESTService { | |||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Invalidates a specific auth token, effectively logging out the associated | ||||||
|  |      * user. | ||||||
|  |      *  | ||||||
|  |      * @param authToken The token being invalidated. | ||||||
|  |      */ | ||||||
|  |     @DELETE | ||||||
|  |     @Path("/{token}") | ||||||
|  |     @AuthProviderRESTExposure | ||||||
|  |     public void invalidateToken(@PathParam("token") String authToken) { | ||||||
|  |          | ||||||
|  |         GuacamoleSession session = tokenSessionMap.remove(authToken); | ||||||
|  |         if (session == null) | ||||||
|  |             throw new HTTPException(Status.NOT_FOUND, "No such token."); | ||||||
|  | 
 | ||||||
|  |         session.invalidate(); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| @@ -51,6 +51,15 @@ public interface TokenSessionMap { | |||||||
|      */ |      */ | ||||||
|     public GuacamoleSession get(String authToken); |     public GuacamoleSession get(String authToken); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Removes the GuacamoleSession associated with the given auth token. | ||||||
|  |      * | ||||||
|  |      * @param authToken The token to remove. | ||||||
|  |      * @return The GuacamoleSession for the given auth token, if the auth token | ||||||
|  |      *         represents a currently logged in user, null otherwise. | ||||||
|  |      */ | ||||||
|  |     public GuacamoleSession remove(String authToken); | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * Shuts down this session map, disallowing future sessions and reclaiming |      * Shuts down this session map, disallowing future sessions and reclaiming | ||||||
|      * any resources. |      * any resources. | ||||||
|   | |||||||
| @@ -21,33 +21,6 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A service for authenticating a user against the REST API. |  * The module for authentication and management of tokens. | ||||||
|  */ |  */ | ||||||
| angular.module('index').factory('authenticationService', ['$http',  | angular.module('auth', ['util']); | ||||||
|         function authenticationService($http) { |  | ||||||
|     var service = {}; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to authenticate a user using the login REST API endpoint,  |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} username The username to log in with. |  | ||||||
|      * @param {string} password The password to log in with. |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.login = function login(username, password) { |  | ||||||
|         return $http({ |  | ||||||
|             method: 'POST', |  | ||||||
|             url: 'api/login', |  | ||||||
|             headers: { |  | ||||||
|                 'Content-Type': 'application/x-www-form-urlencoded' |  | ||||||
|             }, |  | ||||||
|             data: $.param({ |  | ||||||
|                 username: username, |  | ||||||
|                 password: password |  | ||||||
|             }) |  | ||||||
|         }); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -0,0 +1,90 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (C) 2014 Glyptodon LLC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A service for authenticating a user against the REST API. | ||||||
|  |  */ | ||||||
|  | angular.module('auth').factory('authenticationService', ['$http', '$injector', | ||||||
|  |         function authenticationService($http, $injector) { | ||||||
|  |  | ||||||
|  |     var localStorageUtility = $injector.get("localStorageUtility"); | ||||||
|  |     var service = {}; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to authenticate a user using the token REST API endpoint,  | ||||||
|  |      * returning a promise that can be used for processing the results of the call. | ||||||
|  |      *  | ||||||
|  |      * @param {String} username The username to log in with. | ||||||
|  |      * @param {String} password The password to log in with. | ||||||
|  |      * @returns {Promise} A promise for the HTTP call. | ||||||
|  |      */ | ||||||
|  |     service.login = function login(username, password) { | ||||||
|  |         return $http({ | ||||||
|  |             method: 'POST', | ||||||
|  |             url: 'api/token', | ||||||
|  |             headers: { | ||||||
|  |                 'Content-Type': 'application/x-www-form-urlencoded' | ||||||
|  |             }, | ||||||
|  |             data: $.param({ | ||||||
|  |                 username: username, | ||||||
|  |                 password: password | ||||||
|  |             }) | ||||||
|  |         }).success(function success(data, status, headers, config) { | ||||||
|  |             localStorageUtility.set('authToken', data.authToken); | ||||||
|  |             localStorageUtility.set('userID', data.userID); | ||||||
|  |         }); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Makes a request to logout a user using the login REST API endpoint,  | ||||||
|  |      * returning a promise that can be used for processing the results of the call. | ||||||
|  |      *  | ||||||
|  |      * @returns {Promise} A promise for the HTTP call. | ||||||
|  |      */ | ||||||
|  |     service.logout = function logout() { | ||||||
|  |         return $http({ | ||||||
|  |             method: 'DELETE', | ||||||
|  |             url: 'api/token/' + encodeURIComponent(service.getCurrentToken()) | ||||||
|  |         }); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the user ID of the current user. | ||||||
|  |      * | ||||||
|  |      * @returns {String} The user ID of the current user. | ||||||
|  |      */ | ||||||
|  |     service.getCurrentUserID = function getCurrentUserID() { | ||||||
|  |         return localStorageUtility.get('userID'); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the auth token associated with the current user. If the current | ||||||
|  |      * user is not logged in, this token may not be valid. | ||||||
|  |      * | ||||||
|  |      * @returns {String} The auth token associated with the current user. | ||||||
|  |      */ | ||||||
|  |     service.getCurrentToken = function getCurrentToken() { | ||||||
|  |         return localStorageUtility.get('authToken'); | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     return service; | ||||||
|  | }]); | ||||||
| @@ -49,7 +49,7 @@ | |||||||
|  |  | ||||||
|     <div class="logout-panel"> |     <div class="logout-panel"> | ||||||
|         <a class="manage button" ng-show="currentUserHasUpdate" href="#/manage">{{'home.manage' | translate}}</a> |         <a class="manage button" ng-show="currentUserHasUpdate" href="#/manage">{{'home.manage' | translate}}</a> | ||||||
|         <a class="logout button" href="#/login">{{'home.logout' | translate}}</a> |         <a class="logout button" ng-click="logout()">{{'home.logout' | translate}}</a> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <!-- The recent connections for this user --> |     <!-- The recent connections for this user --> | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector', | |||||||
|     // Get the dependencies commonJS style |     // Get the dependencies commonJS style | ||||||
|     var permissionDAO           = $injector.get("permissionDAO"), |     var permissionDAO           = $injector.get("permissionDAO"), | ||||||
|         permissionCheckService  = $injector.get("permissionCheckService"), |         permissionCheckService  = $injector.get("permissionCheckService"), | ||||||
|         localStorageUtility     = $injector.get("localStorageUtility"), |         authenticationService   = $injector.get("authenticationService"), | ||||||
|         $q                      = $injector.get("$q"), |         $q                      = $injector.get("$q"), | ||||||
|         $document               = $injector.get("$document"), |         $document               = $injector.get("$document"), | ||||||
|         $window                 = $injector.get("$window"), |         $window                 = $injector.get("$window"), | ||||||
| @@ -64,7 +64,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector', | |||||||
|     var permissionsLoaded= $q.defer(); |     var permissionsLoaded= $q.defer(); | ||||||
|     $scope.basicPermissionsLoaded = permissionsLoaded.promise; |     $scope.basicPermissionsLoaded = permissionsLoaded.promise; | ||||||
|      |      | ||||||
|     $scope.currentUserID = localStorageUtility.get('userID'); |     $scope.currentUserID = authenticationService.getCurrentUserID(); | ||||||
|      |      | ||||||
|     // If the user is unknown, force a login |     // If the user is unknown, force a login | ||||||
|     if(!$scope.currentUserID) |     if(!$scope.currentUserID) | ||||||
| @@ -87,6 +87,13 @@ angular.module('index').controller('indexController', ['$scope', '$injector', | |||||||
|         }); |         }); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     // Provide simple mechanism for logging out the current user | ||||||
|  |     $scope.logout = function logout() { | ||||||
|  |         authenticationService.logout().success(function logoutSuccess() { | ||||||
|  |             $location.path('/login'); | ||||||
|  |         }); | ||||||
|  |     }; | ||||||
|  |      | ||||||
|     // Try to load them now |     // Try to load them now | ||||||
|     $scope.loadBasicPermissions(); |     $scope.loadBasicPermissions(); | ||||||
|      |      | ||||||
|   | |||||||
| @@ -23,4 +23,4 @@ | |||||||
| /** | /** | ||||||
|  * The module for the root of the application. |  * The module for the root of the application. | ||||||
|  */ |  */ | ||||||
| angular.module('index', ['ngRoute', 'pascalprecht.translate', 'home', 'manage', 'login', 'client']); | angular.module('index', ['ngRoute', 'pascalprecht.translate', 'auth', 'home', 'manage', 'login', 'client']); | ||||||
|   | |||||||
| @@ -25,21 +25,13 @@ angular.module('login').controller('loginController', ['$scope', '$injector', | |||||||
|              |              | ||||||
|     // Get the dependencies commonJS style |     // Get the dependencies commonJS style | ||||||
|     var authenticationService = $injector.get("authenticationService"); |     var authenticationService = $injector.get("authenticationService"); | ||||||
|     var localStorageUtility     = $injector.get("localStorageUtility"); |  | ||||||
|     var $location             = $injector.get("$location"); |     var $location             = $injector.get("$location"); | ||||||
|              |              | ||||||
|     // Clear the auth token and userID to log out the user |  | ||||||
|     localStorageUtility.clear("authToken"); |  | ||||||
|     localStorageUtility.clear("userID"); |  | ||||||
|          |  | ||||||
|     $scope.loginError = false; |     $scope.loginError = false; | ||||||
|      |      | ||||||
|     $scope.login = function login() { |     $scope.login = function login() { | ||||||
|         authenticationService.login($scope.username, $scope.password) |         authenticationService.login($scope.username, $scope.password) | ||||||
|             .success(function success(data, status, headers, config) { |             .success(function success(data, status, headers, config) { | ||||||
|                 localStorageUtility.set('authToken', data.authToken); |  | ||||||
|                 localStorageUtility.set('userID', data.userID); |  | ||||||
|                  |  | ||||||
|                 // Set up the basic permissions for the user |                 // Set up the basic permissions for the user | ||||||
|                 $scope.loadBasicPermissions(); |                 $scope.loadBasicPermissions(); | ||||||
|                 $location.path('/'); |                 $location.path('/'); | ||||||
| @@ -47,4 +39,5 @@ angular.module('login').controller('loginController', ['$scope', '$injector', | |||||||
|                 $scope.loginError = true; |                 $scope.loginError = true; | ||||||
|             }); |             }); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| }]); | }]); | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ THE SOFTWARE. | |||||||
|  |  | ||||||
| <div class="logout-panel"> | <div class="logout-panel"> | ||||||
|     <a class="back button" href="#/">{{'manage.back' | translate}}</a> |     <a class="back button" href="#/">{{'manage.back' | translate}}</a> | ||||||
|     <a class="logout button" href="#/login">{{'home.logout' | translate}}</a> |     <a class="logout button" ng-click="logout()">{{'home.logout' | translate}}</a> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <h2>{{'manage.administration' | translate}}</h2> | <h2>{{'manage.administration' | translate}}</h2> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user