Ticket #362: Added session timeout.

This commit is contained in:
James Muehlner
2013-09-19 20:58:40 -07:00
parent c4ad38e74a
commit 1c36eab1c7
4 changed files with 202 additions and 5 deletions

View File

@@ -0,0 +1,67 @@
package org.glyptodon.guacamole.properties;
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is guacamole-ext.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleServerException;
/**
* A GuacamoleProperty whose value is an long.
*
* @author James Muehlner
*/
public abstract class LongGuacamoleProperty implements GuacamoleProperty<Long> {
@Override
public Long parseValue(String value) throws GuacamoleException {
// If no property provided, return null.
if (value == null)
return null;
try {
Long longValue = new Long(value);
return longValue;
}
catch (NumberFormatException e) {
throw new GuacamoleServerException("Property \"" + getName() + "\" must be an long.", e);
}
}
}

View File

@@ -20,6 +20,7 @@ package org.glyptodon.guacamole.net.basic.properties;
*/ */
import org.glyptodon.guacamole.properties.FileGuacamoleProperty; import org.glyptodon.guacamole.properties.FileGuacamoleProperty;
import org.glyptodon.guacamole.properties.LongGuacamoleProperty;
/** /**
* Properties used by the default Guacamole web application. * Properties used by the default Guacamole web application.
@@ -64,4 +65,14 @@ public class BasicGuacamoleProperties {
}; };
/**
* The session timeout for the API, in milliseconds.
*/
public static final LongGuacamoleProperty API_SESSION_TIMEOUT = new LongGuacamoleProperty() {
@Override
public String getName() { return "api-session-timeout"; }
};
} }

View File

@@ -18,13 +18,113 @@ package org.glyptodon.guacamole.net.basic.rest.auth;
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
import org.glyptodon.guacamole.properties.GuacamoleProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A Basic, HashMap-based implementation of the TokenUserContextMap. * A basic, HashMap-based implementation of the TokenUserContextMap with support
* for session timeouts.
* *
* @author James Muehlner * @author James Muehlner
*/ */
public class BasicTokenUserContextMap extends HashMap<String, UserContext> public class BasicTokenUserContextMap implements TokenUserContextMap {
implements TokenUserContextMap {}
/**
* Logger for this class.
*/
private static Logger logger = LoggerFactory.getLogger(BasicTokenUserContextMap.class);
/**
* The last time a user with a specific auth token accessed the API.
*/
private Map<String, Long> lastAccessTimeMap = new HashMap<String, Long>();
/**
* Keeps track of the authToken to UserContext mapping.
*/
private Map<String, UserContext> userContextMap = new HashMap<String, UserContext>();
/**
* The session timeout configuration for an API session.
*/
private final long SESSION_TIMEOUT;
/**
* Create a new BasicTokenUserContextMap and initialize the session timeout value.
*/
public BasicTokenUserContextMap() {
// Set up the authToken => userContext hashmap
super();
// Set up the SESSION_TIMEOUT value, with a one hour default.
long sessionTimeoutValue = 3600000l;
try {
sessionTimeoutValue = GuacamoleProperties.getProperty(BasicGuacamoleProperties.API_SESSION_TIMEOUT, 3600000l);
} catch (GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while reading API_SESSION_TIMEOUT property.", e);
}
SESSION_TIMEOUT = sessionTimeoutValue;
}
/**
* Evict an authentication token from the map of logged in users and last
* access times.
*
* @param authToken The authentication token to evict.
*/
private void evict(String authToken) {
userContextMap.remove(authToken);
lastAccessTimeMap.remove(authToken);
}
/**
* Log that the user represented by this auth token has just used the API.
*
* @param authToken The authentication token to record access time for.
*/
private void logAccessTime(String authToken) {
lastAccessTimeMap.put(authToken, new Date().getTime());
}
private boolean sessionHasTimedOut(String authToken) {
if(!lastAccessTimeMap.containsKey(authToken))
return true;
long lastAccessTime = lastAccessTimeMap.get(authToken);
long currentTime = new Date().getTime();
return currentTime - lastAccessTime > SESSION_TIMEOUT;
}
@Override
public UserContext get(String authToken) {
// If the session has timed out, evict the token and force the user to log in again
if(sessionHasTimedOut(authToken)) {
evict(authToken);
return null;
}
// Update the last access time and return the UserContext
logAccessTime(authToken);
return userContextMap.get(authToken);
}
@Override
public void put(String authToken, UserContext userContext) {
// Update the last access time, and create the token/UserContext mapping
logAccessTime(authToken);
userContextMap.put(authToken, userContext);
}
}

View File

@@ -18,7 +18,6 @@ package org.glyptodon.guacamole.net.basic.rest.auth;
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import java.util.Map;
import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.UserContext;
/** /**
@@ -27,4 +26,24 @@ import org.glyptodon.guacamole.net.auth.UserContext;
* *
* @author James Muehlner * @author James Muehlner
*/ */
public interface TokenUserContextMap extends Map<String, UserContext> {} public interface TokenUserContextMap {
/**
* Registers that a user has just logged in with the specified authToken and
* UserContext.
*
* @param authToken The authentication token for the logged in user.
* @param userContext The UserContext for the logged in user.
*/
public void put(String authToken, UserContext userContext);
/**
* Get the UserContext for a logged in user. If the auth token does not
* represent a user who is currently logged in, returns null.
*
* @param authToken The authentication token for the logged in user.
* @return The UserContext for the given auth token, if the auth token
* represents a currently logged in user, null otherwise.
*/
public UserContext get(String authToken);
}