Merge branch 'unstable' of ssh://guacamole.git.sourceforge.net/gitroot/guacamole/guacamole into unstable

This commit is contained in:
James Muehlner
2011-12-20 11:48:13 -08:00
13 changed files with 319 additions and 56 deletions

23
guacamole/ChangeLog Normal file
View File

@@ -0,0 +1,23 @@
2011-12-11 Michael Jumper <zhangmaike@users.sourceforge.net>
* Improved UI usability
* Support for multiple connections per user
* Real support for authentication providers
* Logout button
* Connection type icons (thanks to Tango Desktop Project)
* Fixed Ctrl-Alt-Delete bug (ticket #57)
* Fixed arrow key rendering (Chrome-specific issue)
* Fixed exception in XMLReader.parse() (ticket #66)
2011-07-13 Michael Jumper <zhangmaike@users.sourceforge.net>
* Migrated to new tunnel API
* Major cleanup of UI
* Fixed corrupt mouse cursor image
* Improved JavaScript style
* Logging (via SLF4J)
2011-03-02 Michael Jumper <zhangmaike@users.sourceforge.net>
* Initial release of modern 0.3.0+ series

70
guacamole/README Normal file
View File

@@ -0,0 +1,70 @@
------------------------------------------------------------
About this README
------------------------------------------------------------
This README is intended to provide quick and to-the-point documentation for
technical users intending to compile parts of Guacamole themselves.
Distribution-specific packages are available from the files section of the main
project page:
http://sourceforge.net/projects/guacamole/files/
Distribution-specific documentation is provided on the Guacamole wiki:
http://guac-dev.org/
------------------------------------------------------------
What is Guacamole?
------------------------------------------------------------
Guacamole is an HTML5 web application that provides access to your desktop using
remote desktop protocols. A centralized server acts as a tunnel and proxy,
allowing access to multiple desktops through a web browser; no plugins needed.
The client requires nothing more than a web browser supporting HTML5 and AJAX.
The Guacamole project maintains this web application and the Java and C
libraries and programs it depends on. These libraries and programs are
separate in order to enable others to implement other applications using the
same underlying technology.
All components and dependencies of Guacamole are free and open source.
------------------------------------------------------------
Compiling and installing Guacamole
------------------------------------------------------------
Guacamole is built using Maven. Building Guacamole compiles all classes and
packages them into a deployable .war file. This .war file can be installed
and deployed under servlet containers like Apache Tomcat or Jetty.
1) Run mvn package
$ mvn package
Maven will download any needed dependencies for building the .jar file.
Once all dependencies have been downloaded, the .war file will be
created in the target/ subdirectory of the current directory.
2) Copy the .war file as directed in the instructions provided with
your servlet container.
Apache Tomcat, Jetty, and other servlet containers have specific and
varying locations that .war files must be placed for the web
application to be deployed.
You will likely need to do this as root.
------------------------------------------------------------
Reporting problems
------------------------------------------------------------
Please report any bugs encountered by opening a new ticket at the Trac system
hosted at:
http://guac-dev.org/trac/

View File

@@ -32,7 +32,7 @@ import java.util.HashMap;
import java.util.Map;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.auth.UsernamePassword;
import net.sourceforge.guacamole.net.basic.properties.BasicGuacamoleProperties;
import net.sourceforge.guacamole.properties.FileGuacamoleProperty;
import net.sourceforge.guacamole.properties.GuacamoleProperties;
import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
import org.slf4j.Logger;
@@ -44,6 +44,13 @@ import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* Authenticates users against a static list of username/password pairs.
* Each username/password may be associated with exactly one configuration.
* This list is stored in an XML file which is reread if modified.
*
* @author Michael Jumper
*/
public class BasicFileAuthenticationProvider implements AuthenticationProvider<UsernamePassword> {
private Logger logger = LoggerFactory.getLogger(BasicFileAuthenticationProvider.class);
@@ -51,10 +58,20 @@ public class BasicFileAuthenticationProvider implements AuthenticationProvider<U
private long mappingTime;
private Map<String, AuthInfo> mapping;
/**
* The filename of the XML file to read the user mapping from.
*/
public static final FileGuacamoleProperty BASIC_USER_MAPPING = new FileGuacamoleProperty() {
@Override
public String getName() { return "basic-user-mapping"; }
};
private File getUserMappingFile() throws GuacamoleException {
// Get user mapping file
return GuacamoleProperties.getProperty(BasicGuacamoleProperties.BASIC_USER_MAPPING);
return GuacamoleProperties.getProperty(BASIC_USER_MAPPING);
}

View File

@@ -33,6 +33,12 @@ import net.sourceforge.guacamole.servlet.GuacamoleHTTPTunnelServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Connects users to a tunnel associated with the authorized configuration
* having the given ID.
*
* @author Michael Jumper
*/
public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
private Logger logger = LoggerFactory.getLogger(BasicGuacamoleTunnelServlet.class);
@@ -51,7 +57,7 @@ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
// If no configs in session, not authorized
if (configs == null)
throw new GuacamoleException("No authorized configurations.");
throw new GuacamoleException("Cannot connect - user not logged in.");
// Get authorized config
GuacamoleConfiguration config = configs.get(id);

View File

@@ -34,6 +34,17 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Retrieves the authorized configurations associated with a given
* username/password pair using the authentication provider defined in
* guacamole.properties.
*
* All authorized configurations will be stored in the current HttpSession.
*
* Success and failure are logged.
*
* @author Michael Jumper
*/
public class BasicLogin extends HttpServlet {
private Logger logger = LoggerFactory.getLogger(BasicLogin.class);

View File

@@ -24,6 +24,12 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Logs out the current user by invalidating the associated HttpSession and
* redirecting the user to the login page.
*
* @author Michael Jumper
*/
public class BasicLogout extends HttpServlet {
@Override

View File

@@ -27,13 +27,15 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple HttpServlet which outputs XML containing a list of all authorized
* configurations for the current user.
*
* @author Michael Jumper
*/
public class ConfigurationList extends HttpServlet {
private Logger logger = LoggerFactory.getLogger(ConfigurationList.class);
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws IOException {

View File

@@ -1,6 +1,42 @@
package net.sourceforge.guacamole.net.basic;
/* ***** 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-common.
*
* 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 java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
@@ -12,24 +48,12 @@ import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.basic.properties.BasicGuacamoleProperties;
import net.sourceforge.guacamole.properties.GuacamoleProperties;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* A ClassLoader implementation which finds classes within a configurable
* directory. This directory is set within guacamole.properties.
*
* @author Michael Jumper
*/
public class GuacamoleClassLoader extends ClassLoader {
private URLClassLoader classLoader = null;
@@ -106,6 +130,14 @@ public class GuacamoleClassLoader extends ClassLoader {
}
/**
* Returns an instance of a GuacamoleClassLoader which finds classes
* within the directory configured in guacamole.properties.
*
* @return An instance of a GuacamoleClassLoader.
* @throws GuacamoleException If no instance could be returned due to an
* error.
*/
public static GuacamoleClassLoader getInstance() throws GuacamoleException {
// If instance could not be created, rethrow original exception

View File

@@ -24,6 +24,12 @@ import net.sourceforge.guacamole.net.auth.AuthenticationProvider;
import net.sourceforge.guacamole.net.basic.GuacamoleClassLoader;
import net.sourceforge.guacamole.properties.GuacamoleProperty;
/**
* A GuacamoleProperty whose value is the name of a class to use to
* authenticate users. This class must implement AuthenticationProvider.
*
* @author Michael Jumper
*/
public abstract class AuthenticationProviderProperty implements GuacamoleProperty<AuthenticationProvider> {
@Override

View File

@@ -1,8 +1,6 @@
package net.sourceforge.guacamole.net.basic.properties;
import net.sourceforge.guacamole.properties.FileGuacamoleProperty;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
@@ -21,17 +19,24 @@ import net.sourceforge.guacamole.properties.FileGuacamoleProperty;
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import net.sourceforge.guacamole.properties.FileGuacamoleProperty;
/**
* Properties used by the default Guacamole web application.
*
* @author Michael Jumper
*/
public class BasicGuacamoleProperties {
/**
* This class should not be instantiated.
*/
private BasicGuacamoleProperties() {}
public static final FileGuacamoleProperty BASIC_USER_MAPPING = new FileGuacamoleProperty() {
@Override
public String getName() { return "basic-user-mapping"; }
};
/**
* The authentication provider to user when retrieving the authorized
* configurations of a user.
*/
public static final AuthenticationProviderProperty AUTH_PROVIDER = new AuthenticationProviderProperty() {
@Override
@@ -39,6 +44,9 @@ public class BasicGuacamoleProperties {
};
/**
* The directory to search for authentication provider classes.
*/
public static final FileGuacamoleProperty LIB_DIRECTORY = new FileGuacamoleProperty() {
@Override

View File

@@ -56,10 +56,14 @@
<!-- Display -->
<div id="display" class="guac-display guac-loading">
<!-- Menu trigger -->
<div id="menuControl"></div>
<!-- On-screen keyboard -->
<div id="keyboardContainer"></div>
</div>
</div>
<!-- Error Dialog-->
<div id="errorDialog" class="errorDialogOuter">

View File

@@ -2,10 +2,11 @@
// UI Definition
var GuacamoleUI = {
"display": document.getElementById("display"),
"menu" : document.getElementById("menu"),
"logo" : document.getElementById("status-logo"),
"state" : document.getElementById("state"),
"display" : document.getElementById("display"),
"menu" : document.getElementById("menu"),
"menuControl" : document.getElementById("menuControl"),
"logo" : document.getElementById("status-logo"),
"state" : document.getElementById("state"),
"buttons": {
@@ -55,7 +56,7 @@ var GuacamoleUI = {
if (!menu_shaded) {
var step = Math.floor(GuacamoleUI.menu.offsetHeight / 5) + 1;
var step = Math.floor(GuacamoleUI.menu.offsetHeight / 10) + 1;
var offset = 0;
menu_shaded = true;
@@ -137,13 +138,85 @@ var GuacamoleUI = {
window.location.href = "logout";
};
GuacamoleUI.display.onmouseout = function() {
GuacamoleUI.showMenu();
};
// Timeouts for detecting if users wants menu to open or close
var detectMenuOpenTimeout = null;
var detectMenuCloseTimeout = null;
GuacamoleUI.display.onmouseover = function() {
GuacamoleUI.shadeMenu();
};
// Clear detection timeouts
function resetMenuDetect() {
if (detectMenuOpenTimeout != null) {
window.clearTimeout(detectMenuOpenTimeout);
detectMenuOpenTimeout = null;
}
if (detectMenuCloseTimeout != null) {
window.clearTimeout(detectMenuCloseTimeout);
detectMenuCloseTimeout = null;
}
}
// Initiate detection of menu open action. If not canceled through some
// user event, menu will open.
function startMenuOpenDetect() {
// Clear detection state
resetMenuDetect();
// Wait and then show menu
detectMenuOpenTimeout = window.setTimeout(function() {
GuacamoleUI.showMenu();
detectMenuOpenTimeout = null;
}, 325);
}
// Initiate detection of menu close action. If not canceled through some
// user event, menu will close.
function startMenuCloseDetect() {
// Clear detection state
resetMenuDetect();
// Wait and then shade menu
detectMenuCloseTimeout = window.setTimeout(function() {
GuacamoleUI.shadeMenu();
detectMenuCloseTimeout = null;
}, 500);
}
// Show menu if mouseover any part of menu
GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true);
// Stop detecting menu state change intents if mouse is over menu
GuacamoleUI.menu.addEventListener('mouseover', resetMenuDetect, true);
// When mouse hovers over top of screen, start detection of intent to open menu
GuacamoleUI.menuControl.addEventListener('mousemove', startMenuOpenDetect, true);
// When mouse enters display, start detection of intent to close menu
GuacamoleUI.display.addEventListener('mouseover', startMenuCloseDetect, true);
// Show menu if mouse leaves document
document.addEventListener('mouseout', function(e) {
// Get parent of the element the mouse pointer is leaving
if (!e) e = window.event;
var target = e.relatedTarget || e.toElement;
// Ensure target is not document nor child of document
var targetParent = target;
while (targetParent != null) {
if (targetParent == document) return;
targetParent = targetParent.parentNode;
}
// Start detection of intent to open menu
startMenuOpenDetect();
}, true);
// Reconnect button
GuacamoleUI.buttons.reconnect.onclick = function() {
@@ -163,10 +236,6 @@ GuacamoleUI.attach = function(guac) {
var mouse = new Guacamole.Mouse(GuacamoleUI.display);
mouse.onmousedown = mouse.onmouseup = mouse.onmousemove =
function(mouseState) {
if (mouseState.y <= 5)
GuacamoleUI.showMenu();
guac.sendMouseState(mouseState);
};

View File

@@ -73,17 +73,14 @@ div.errorDialog p {
#menu {
margin-left: auto;
margin-right: auto;
margin-bottom: 1em;
font-size: 0.8em;
background: #FEA;
border: 1px solid black;
position: fixed;
left: 0;
top: 0;
width: 100%;
z-index: 1;
z-index: 4;
background: #FEA;
border-bottom: 1px solid black;
font-size: 0.8em;
}
#menu.error {
@@ -127,6 +124,7 @@ div#clipboardDiv {
border: 1px solid black;
width: 50em;
z-index: 2;
opacity: 0.5;
}
@@ -161,3 +159,14 @@ div#clipboardDiv textarea {
cursor: url('../images/mouse/dot.gif'),url('../images/mouse/blank.cur'),default;
}
div#menuControl {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: none;
z-index: 3;
}