mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
More renaming
This commit is contained in:
57
guacamole-common/pom.xml
Normal file
57
guacamole-common/pom.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>net.sourceforge.guacamole</groupId>
|
||||||
|
<artifactId>guacamole-common</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>0.3.0rc1</version>
|
||||||
|
<name>guacamole-common</name>
|
||||||
|
<url>http://guacamole.sourceforge.net/</url>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
<extensions>
|
||||||
|
<!-- Required for SSH deploy -->
|
||||||
|
<extension>
|
||||||
|
<groupId>org.apache.maven.wagon</groupId>
|
||||||
|
<artifactId>wagon-ssh-external</artifactId>
|
||||||
|
</extension>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>servlet-api</artifactId>
|
||||||
|
<version>2.5</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>guac-dev</id>
|
||||||
|
<url>http://guac-dev.org/repo</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>guac-dev</id>
|
||||||
|
<url>scpexe://guac-dev.org/var/www/repo</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
</project>
|
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public abstract class Client {
|
||||||
|
|
||||||
|
public abstract void write(char[] chunk, int off, int len) throws GuacamoleException;
|
||||||
|
public abstract char[] read() throws GuacamoleException;
|
||||||
|
public abstract void disconnect() throws GuacamoleException;
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public class GuacamoleClient extends Client {
|
||||||
|
|
||||||
|
private Socket sock;
|
||||||
|
private Reader input;
|
||||||
|
private Writer output;
|
||||||
|
|
||||||
|
public GuacamoleClient(String hostname, int port) throws GuacamoleException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
sock = new Socket(InetAddress.getByName(hostname), port);
|
||||||
|
input = new InputStreamReader(sock.getInputStream());
|
||||||
|
output = new OutputStreamWriter(sock.getOutputStream());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(char[] chunk, int off, int len) throws GuacamoleException {
|
||||||
|
try {
|
||||||
|
output.write(chunk, off, len);
|
||||||
|
output.flush();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() throws GuacamoleException {
|
||||||
|
try {
|
||||||
|
sock.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int usedLength = 0;
|
||||||
|
private char[] buffer = new char[20000];
|
||||||
|
|
||||||
|
public char[] read() throws GuacamoleException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// While we're blocking, or input is available
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
// If past threshold, resize buffer before reading
|
||||||
|
if (usedLength > buffer.length/2) {
|
||||||
|
char[] biggerBuffer = new char[buffer.length*2];
|
||||||
|
System.arraycopy(buffer, 0, biggerBuffer, 0, usedLength);
|
||||||
|
buffer = biggerBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to fill buffer
|
||||||
|
int numRead = input.read(buffer, usedLength, buffer.length - usedLength);
|
||||||
|
if (numRead == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int prevLength = usedLength;
|
||||||
|
usedLength += numRead;
|
||||||
|
|
||||||
|
for (int i=usedLength-1; i>=prevLength; i--) {
|
||||||
|
|
||||||
|
char readChar = buffer[i];
|
||||||
|
|
||||||
|
// If end of instruction, return it.
|
||||||
|
if (readChar == ';') {
|
||||||
|
|
||||||
|
// Get instruction
|
||||||
|
char[] chunk = new char[i+1];
|
||||||
|
System.arraycopy(buffer, 0, chunk, 0, i+1);
|
||||||
|
|
||||||
|
// Reset buffer
|
||||||
|
usedLength -= i+1;
|
||||||
|
System.arraycopy(buffer, i+1, buffer, 0, usedLength);
|
||||||
|
|
||||||
|
// Return instruction string
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End read loop
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class GuacamoleException extends Exception {
|
||||||
|
|
||||||
|
public GuacamoleException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuacamoleException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuacamoleException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public abstract class Configuration {
|
||||||
|
|
||||||
|
protected String humanReadableList(Object... values) {
|
||||||
|
|
||||||
|
String list = "";
|
||||||
|
for (int i=0; i<values.length; i++) {
|
||||||
|
|
||||||
|
if (i >= 1)
|
||||||
|
list += ", ";
|
||||||
|
|
||||||
|
if (i == values.length -1)
|
||||||
|
list += " or ";
|
||||||
|
|
||||||
|
list += "\"" + values[i] + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String readParameter(String name) throws GuacamoleException {
|
||||||
|
String value = GuacamoleProperties.getProperty(name);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String readParameter(String name, String defaultValue, String... allowedValues) throws GuacamoleException {
|
||||||
|
|
||||||
|
String value = GuacamoleProperties.getProperty(name);
|
||||||
|
|
||||||
|
// Use default if not specified
|
||||||
|
if (value == null) {
|
||||||
|
if (defaultValue == null)
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not restricted to certain values, just return whatever is given.
|
||||||
|
if (allowedValues.length == 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
// If restricted, only return value within given list
|
||||||
|
for (String allowedValue : allowedValues)
|
||||||
|
if (value.equals(allowedValue))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" must be " + humanReadableList((Object) allowedValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean readBooleanParameter(String name, Boolean defaultValue) throws GuacamoleException {
|
||||||
|
|
||||||
|
String value = GuacamoleProperties.getProperty(name);
|
||||||
|
|
||||||
|
// Use default if not specified
|
||||||
|
if (value == null) {
|
||||||
|
if (defaultValue == null)
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.trim();
|
||||||
|
if (value.equals("true"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (value.equals("false"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" must be \"true\" or \"false\".");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int readIntParameter(String name, Integer defaultValue, Integer... allowedValues) throws GuacamoleException {
|
||||||
|
|
||||||
|
String parmString = GuacamoleProperties.getProperty(name);
|
||||||
|
|
||||||
|
// Use default if not specified
|
||||||
|
if (parmString== null) {
|
||||||
|
if (defaultValue == null)
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int value = Integer.parseInt(parmString);
|
||||||
|
|
||||||
|
// If not restricted to certain values, just return whatever is given.
|
||||||
|
if (allowedValues.length == 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
// If restricted, only return value within given list
|
||||||
|
for (int allowedValue : allowedValues)
|
||||||
|
if (value == allowedValue)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" must be " + humanReadableList((Object) allowedValues));
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
throw new GuacamoleException("Parameter \"" + name + "\" must be an integer.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.net.authentication.GuacamoleSessionProvider;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public class GuacamoleConfiguration extends Configuration {
|
||||||
|
|
||||||
|
private String guacd_hostname;
|
||||||
|
private int guacd_port;
|
||||||
|
private GuacamoleSessionProvider sessionProvider;
|
||||||
|
|
||||||
|
public GuacamoleConfiguration() throws GuacamoleException {
|
||||||
|
|
||||||
|
guacd_hostname = readParameter("guacd-hostname");
|
||||||
|
guacd_port = readIntParameter("guacd-port", null);
|
||||||
|
|
||||||
|
// Get session provider instance
|
||||||
|
try {
|
||||||
|
String sessionProviderClassName = readParameter("session-provider");
|
||||||
|
Object obj = Class.forName(sessionProviderClassName).getConstructor().newInstance();
|
||||||
|
if (!(obj instanceof GuacamoleSessionProvider))
|
||||||
|
throw new GuacamoleException("Specified session provider class is not a GuacamoleSessionProvider");
|
||||||
|
|
||||||
|
sessionProvider = (GuacamoleSessionProvider) obj;
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new GuacamoleException("Session provider class not found", e);
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new GuacamoleException("Default constructor for session provider not present", e);
|
||||||
|
}
|
||||||
|
catch (SecurityException e) {
|
||||||
|
throw new GuacamoleException("Creation of session provider disallowed; check your security settings", e);
|
||||||
|
}
|
||||||
|
catch (InstantiationException e) {
|
||||||
|
throw new GuacamoleException("Unable to instantiate session provider", e);
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e) {
|
||||||
|
throw new GuacamoleException("Unable to access default constructor of session provider", e);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
throw new GuacamoleException("Internal error in constructor of session provider", e.getTargetException());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getProxyPort() {
|
||||||
|
return guacd_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProxyHostname() {
|
||||||
|
return guacd_hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuacamoleSession createSession(HttpSession session) throws GuacamoleException {
|
||||||
|
return sessionProvider.createSession(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public class GuacamoleProperties {
|
||||||
|
|
||||||
|
private static final Properties properties;
|
||||||
|
private static GuacamoleException exception;
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
properties = new Properties();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
InputStream stream = GuacamoleProperties.class.getResourceAsStream("/guacamole.properties");
|
||||||
|
if (stream == null)
|
||||||
|
throw new IOException("Resource /guacamole.properties not found.");
|
||||||
|
|
||||||
|
properties.load(stream);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
exception = new GuacamoleException("Error reading guacamole.properties", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getProperty(String name) throws GuacamoleException {
|
||||||
|
if (exception != null) throw exception;
|
||||||
|
return properties.getProperty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.ServletConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public abstract class GuacamoleServlet extends HttpServlet {
|
||||||
|
|
||||||
|
private GuacamoleConfiguration config;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ServletException {
|
||||||
|
try {
|
||||||
|
this.config = new GuacamoleConfiguration();
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new ServletException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
try {
|
||||||
|
handleRequest(req, resp);
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new ServletException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
try {
|
||||||
|
handleRequest(req, resp);
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new ServletException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void handleRequest(HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||||
|
|
||||||
|
HttpSession httpSession = request.getSession(shouldCreateSession());
|
||||||
|
|
||||||
|
if (httpSession != null) {
|
||||||
|
GuacamoleSession session = config.createSession(httpSession);
|
||||||
|
handleRequest(session, request, response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new GuacamoleException("No session");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException;
|
||||||
|
|
||||||
|
protected boolean shouldCreateSession() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,209 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import javax.servlet.http.HttpSessionBindingEvent;
|
||||||
|
import javax.servlet.http.HttpSessionBindingListener;
|
||||||
|
import net.sourceforge.guacamole.Client;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleClient;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
public class GuacamoleSession {
|
||||||
|
|
||||||
|
private GuacamoleConfiguration config;
|
||||||
|
private final HttpSession session;
|
||||||
|
private SessionClient client;
|
||||||
|
private ReentrantLock instructionStreamLock;
|
||||||
|
|
||||||
|
private String protocol;
|
||||||
|
private String hostname;
|
||||||
|
private int port;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public class SessionClient extends Client implements HttpSessionBindingListener {
|
||||||
|
|
||||||
|
private Client client;
|
||||||
|
private ReentrantLock authorizedLock;
|
||||||
|
|
||||||
|
public SessionClient(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
authorizedLock = new ReentrantLock();
|
||||||
|
authorizedLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void authorize() {
|
||||||
|
authorizedLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitForAuthorization() {
|
||||||
|
if (authorizedLock.isLocked()) {
|
||||||
|
try {
|
||||||
|
authorizedLock.lock();
|
||||||
|
authorizedLock.unlock();
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
throw new Error("Internal error waiting for authorization", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void valueBound(HttpSessionBindingEvent event) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void valueUnbound(HttpSessionBindingEvent event) {
|
||||||
|
try {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(char[] data, int off, int len) throws GuacamoleException {
|
||||||
|
client.write(data, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] read() throws GuacamoleException {
|
||||||
|
return client.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() throws GuacamoleException {
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuacamoleSession(HttpSession session) throws GuacamoleException {
|
||||||
|
|
||||||
|
if (session == null)
|
||||||
|
throw new GuacamoleException("User has no session.");
|
||||||
|
|
||||||
|
this.session = session;
|
||||||
|
synchronized (session) {
|
||||||
|
|
||||||
|
// Read configuration parameters
|
||||||
|
config = new GuacamoleConfiguration();
|
||||||
|
|
||||||
|
client = (SessionClient) session.getAttribute("CLIENT");
|
||||||
|
instructionStreamLock = (ReentrantLock) session.getAttribute("INSTRUCTION_STREAM_LOCK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() throws GuacamoleException {
|
||||||
|
synchronized (session) {
|
||||||
|
|
||||||
|
if (client != null)
|
||||||
|
client.disconnect();
|
||||||
|
|
||||||
|
|
||||||
|
client = new SessionClient(
|
||||||
|
new GuacamoleClient (
|
||||||
|
config.getProxyHostname(),
|
||||||
|
config.getProxyPort()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
session.setAttribute("CLIENT", client);
|
||||||
|
|
||||||
|
instructionStreamLock = new ReentrantLock();
|
||||||
|
session.setAttribute("INSTRUCTION_STREAM_LOCK", instructionStreamLock);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
synchronized (session) {
|
||||||
|
return client != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuacamoleConfiguration getConfiguration() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionClient getClient() {
|
||||||
|
synchronized (session) {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidate() {
|
||||||
|
session.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() throws GuacamoleException {
|
||||||
|
if (client != null) {
|
||||||
|
client.disconnect();
|
||||||
|
|
||||||
|
session.removeAttribute("CLIENT");
|
||||||
|
client = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReentrantLock getInstructionStreamLock() {
|
||||||
|
return instructionStreamLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnection(String protocol, String hostname, int port) {
|
||||||
|
this.protocol = protocol;
|
||||||
|
this.hostname = hostname;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostname() {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConnectMessage() throws GuacamoleException {
|
||||||
|
|
||||||
|
if (getProtocol() == null)
|
||||||
|
throw new GuacamoleException("Protocol not specified");
|
||||||
|
|
||||||
|
if (getHostname() == null)
|
||||||
|
throw new GuacamoleException("Hostname not specified");
|
||||||
|
|
||||||
|
if (getPassword() == null)
|
||||||
|
return "connect:" + getProtocol() + "," + getHostname() + "," + getPort() + ";";
|
||||||
|
else
|
||||||
|
return "connect:" + getProtocol() + "," + getHostname() + "," + getPort() + "," + getPassword() + ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net.authentication;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface GuacamoleSessionProvider {
|
||||||
|
|
||||||
|
public GuacamoleSession createSession(HttpSession session) throws GuacamoleException;
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net.authentication;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class NullGuacamoleSessionProvider implements GuacamoleSessionProvider {
|
||||||
|
|
||||||
|
public GuacamoleSession createSession(HttpSession session) throws GuacamoleException {
|
||||||
|
throw new GuacamoleException("Null provider will not create sessions");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,318 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net.authentication.basic;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleProperties;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
import org.xml.sax.helpers.XMLReaderFactory;
|
||||||
|
|
||||||
|
public class BasicFileAuthenticationProvider implements BasicLogin.AuthenticationProvider {
|
||||||
|
|
||||||
|
private long mappingTime;
|
||||||
|
private Map<String, AuthInfo> mapping;
|
||||||
|
|
||||||
|
private File getUserMappingFile() throws GuacamoleException {
|
||||||
|
|
||||||
|
// Get user mapping filename
|
||||||
|
String filename = GuacamoleProperties.getProperty("basic-user-mapping");
|
||||||
|
if (filename == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new File(filename);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void init() throws GuacamoleException {
|
||||||
|
|
||||||
|
// Get user mapping file
|
||||||
|
File mapFile = getUserMappingFile();
|
||||||
|
if (mapFile == null)
|
||||||
|
throw new GuacamoleException("Missing \"basic-user-mapping\" parameter required for basic login.");
|
||||||
|
|
||||||
|
// Parse document
|
||||||
|
try {
|
||||||
|
|
||||||
|
BasicUserMappingContentHandler contentHandler = new BasicUserMappingContentHandler();
|
||||||
|
|
||||||
|
XMLReader parser = XMLReaderFactory.createXMLReader();
|
||||||
|
parser.setContentHandler(contentHandler);
|
||||||
|
parser.parse(mapFile.getAbsolutePath());
|
||||||
|
|
||||||
|
mappingTime = mapFile.lastModified();
|
||||||
|
mapping = contentHandler.getUserMapping();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException("Error reading basic user mapping file.", e);
|
||||||
|
}
|
||||||
|
catch (SAXException e) {
|
||||||
|
throw new GuacamoleException("Error parsing basic user mapping XML.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BasicLogin.AuthorizedConfiguration getAuthorizedConfiguration(String username, String password) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Check mapping file mod time
|
||||||
|
File userMappingFile = getUserMappingFile();
|
||||||
|
if (userMappingFile.exists() && mappingTime < userMappingFile.lastModified()) {
|
||||||
|
|
||||||
|
// If modified recently, gain exclusive access and recheck
|
||||||
|
synchronized (this) {
|
||||||
|
if (userMappingFile.exists() && mappingTime < userMappingFile.lastModified())
|
||||||
|
init(); // If still not up to date, re-init
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthInfo info = mapping.get(username);
|
||||||
|
if (info != null && info.validate(username, password))
|
||||||
|
return new BasicLogin.AuthorizedConfiguration(
|
||||||
|
info.getProtocol(),
|
||||||
|
info.getHostname(),
|
||||||
|
info.getPort(),
|
||||||
|
info.getPassword()
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AuthInfo {
|
||||||
|
|
||||||
|
public static enum Encoding {
|
||||||
|
PLAIN_TEXT,
|
||||||
|
MD5
|
||||||
|
}
|
||||||
|
|
||||||
|
private String auth_username;
|
||||||
|
private String auth_password;
|
||||||
|
private Encoding auth_encoding;
|
||||||
|
|
||||||
|
private String protocol;
|
||||||
|
private String hostname;
|
||||||
|
private int port;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public AuthInfo(String auth_username, String auth_password, Encoding auth_encoding) {
|
||||||
|
this.auth_username = auth_username;
|
||||||
|
this.auth_password = auth_password;
|
||||||
|
this.auth_encoding = auth_encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final char HEX_CHARS[] = {
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||||
|
};
|
||||||
|
|
||||||
|
public static String getHexString(byte[] bytes) {
|
||||||
|
|
||||||
|
if (bytes == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
StringBuilder hex = new StringBuilder(2 * bytes.length);
|
||||||
|
for (byte b : bytes) {
|
||||||
|
hex.append(HEX_CHARS[(b & 0xF0) >> 4])
|
||||||
|
.append(HEX_CHARS[(b & 0x0F) ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean validate(String username, String password) {
|
||||||
|
|
||||||
|
// If username matches
|
||||||
|
if (username != null && password != null && username.equals(auth_username)) {
|
||||||
|
|
||||||
|
switch (auth_encoding) {
|
||||||
|
|
||||||
|
case PLAIN_TEXT:
|
||||||
|
|
||||||
|
// Compare plaintext
|
||||||
|
return password.equals(auth_password);
|
||||||
|
|
||||||
|
case MD5:
|
||||||
|
|
||||||
|
// Compare hashed password
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||||
|
String hashedPassword = getHexString(digest.digest(password.getBytes()));
|
||||||
|
return hashedPassword.equals(auth_password.toUpperCase());
|
||||||
|
}
|
||||||
|
catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new UnsupportedOperationException("Unexpected lack of MD5 support.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostname() {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class BasicUserMappingContentHandler extends DefaultHandler {
|
||||||
|
|
||||||
|
private Map<String, AuthInfo> authMapping = new HashMap<String, AuthInfo>();
|
||||||
|
|
||||||
|
public Map<String, AuthInfo> getUserMapping() {
|
||||||
|
return Collections.unmodifiableMap(authMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthInfo current;
|
||||||
|
|
||||||
|
private enum AUTH_INFO_STATE {
|
||||||
|
PROTOCOL,
|
||||||
|
HOSTNAME,
|
||||||
|
PORT,
|
||||||
|
PASSWORD
|
||||||
|
};
|
||||||
|
|
||||||
|
private AUTH_INFO_STATE infoState;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||||
|
|
||||||
|
if (localName.equals("authorize")) {
|
||||||
|
|
||||||
|
// Finalize mapping for this user
|
||||||
|
authMapping.put(
|
||||||
|
current.auth_username,
|
||||||
|
current
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
infoState = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||||
|
|
||||||
|
if (localName.equals("authorize")) {
|
||||||
|
|
||||||
|
AuthInfo.Encoding encoding;
|
||||||
|
String encodingString = attributes.getValue("encoding");
|
||||||
|
if (encodingString == null)
|
||||||
|
encoding = AuthInfo.Encoding.PLAIN_TEXT;
|
||||||
|
else if (encodingString.equals("plain"))
|
||||||
|
encoding = AuthInfo.Encoding.PLAIN_TEXT;
|
||||||
|
else if (encodingString.equals("md5"))
|
||||||
|
encoding = AuthInfo.Encoding.MD5;
|
||||||
|
else
|
||||||
|
throw new SAXException("Invalid encoding type");
|
||||||
|
|
||||||
|
|
||||||
|
current = new AuthInfo(
|
||||||
|
attributes.getValue("username"),
|
||||||
|
attributes.getValue("password"),
|
||||||
|
encoding
|
||||||
|
);
|
||||||
|
|
||||||
|
infoState = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (localName.equals("protocol"))
|
||||||
|
infoState = AUTH_INFO_STATE.PROTOCOL;
|
||||||
|
|
||||||
|
else if (localName.equals("hostname"))
|
||||||
|
infoState = AUTH_INFO_STATE.HOSTNAME;
|
||||||
|
|
||||||
|
else if (localName.equals("port"))
|
||||||
|
infoState = AUTH_INFO_STATE.PORT;
|
||||||
|
|
||||||
|
else if (localName.equals("password"))
|
||||||
|
infoState = AUTH_INFO_STATE.PASSWORD;
|
||||||
|
|
||||||
|
else
|
||||||
|
infoState = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||||
|
|
||||||
|
String str = new String(ch, start, length);
|
||||||
|
|
||||||
|
if (infoState == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (infoState) {
|
||||||
|
|
||||||
|
case PROTOCOL:
|
||||||
|
current.protocol = str;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HOSTNAME:
|
||||||
|
current.hostname = str;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PORT:
|
||||||
|
current.port = Integer.parseInt(str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PASSWORD:
|
||||||
|
current.password = str;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net.authentication.basic;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
import net.sourceforge.guacamole.net.authentication.GuacamoleSessionProvider;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class BasicGuacamoleSessionProvider implements GuacamoleSessionProvider {
|
||||||
|
|
||||||
|
public GuacamoleSession createSession(HttpSession session) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Retrieve authorized config data from session
|
||||||
|
BasicLogin.AuthorizedConfiguration config = (BasicLogin.AuthorizedConfiguration)
|
||||||
|
session.getAttribute("BASIC-LOGIN-AUTH");
|
||||||
|
|
||||||
|
// If no data, not authorized
|
||||||
|
if (config == null)
|
||||||
|
throw new GuacamoleException("Unauthorized");
|
||||||
|
|
||||||
|
// Configure session from authorized config info
|
||||||
|
GuacamoleSession guacSession = new GuacamoleSession(session);
|
||||||
|
guacSession.setConnection(config.getProtocol(), config.getHostname(), config.getPort());
|
||||||
|
if (config.getPassword() != null)
|
||||||
|
guacSession.setPassword(config.getPassword());
|
||||||
|
|
||||||
|
// Return authorized session
|
||||||
|
return guacSession;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,161 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.net.authentication.basic;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.Configuration;
|
||||||
|
|
||||||
|
public class BasicLogin extends HttpServlet {
|
||||||
|
|
||||||
|
private Config config;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ServletException {
|
||||||
|
try {
|
||||||
|
config = new Config();
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new ServletException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class Config extends Configuration {
|
||||||
|
|
||||||
|
private AuthenticationProvider authProvider;
|
||||||
|
|
||||||
|
public Config() throws GuacamoleException {
|
||||||
|
|
||||||
|
// Get auth provider instance
|
||||||
|
try {
|
||||||
|
String authProviderClassName = readParameter("auth-provider");
|
||||||
|
Object obj = Class.forName(authProviderClassName).getConstructor().newInstance();
|
||||||
|
if (!(obj instanceof AuthenticationProvider))
|
||||||
|
throw new GuacamoleException("Specified session provider class is not a GuacamoleSessionProvider");
|
||||||
|
|
||||||
|
authProvider = (AuthenticationProvider) obj;
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new GuacamoleException("Session provider class not found", e);
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new GuacamoleException("Default constructor for session provider not present", e);
|
||||||
|
}
|
||||||
|
catch (SecurityException e) {
|
||||||
|
throw new GuacamoleException("Creation of session provider disallowed; check your security settings", e);
|
||||||
|
}
|
||||||
|
catch (InstantiationException e) {
|
||||||
|
throw new GuacamoleException("Unable to instantiate session provider", e);
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e) {
|
||||||
|
throw new GuacamoleException("Unable to access default constructor of session provider", e);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
throw new GuacamoleException("Internal error in constructor of session provider", e.getTargetException());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationProvider getAuthenticationProvider() {
|
||||||
|
return authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface AuthenticationProvider {
|
||||||
|
public AuthorizedConfiguration getAuthorizedConfiguration(String username, String password) throws GuacamoleException;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added to session when session validated
|
||||||
|
public static class AuthorizedConfiguration {
|
||||||
|
|
||||||
|
private String protocol;
|
||||||
|
private String hostname;
|
||||||
|
private int port;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public AuthorizedConfiguration(String protocol, String hostname, int port, String password) {
|
||||||
|
this.protocol = protocol;
|
||||||
|
this.hostname = hostname;
|
||||||
|
this.port = port;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostname() {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Retrieve username and password from parms
|
||||||
|
String username = req.getParameter("username");
|
||||||
|
String password = req.getParameter("password");
|
||||||
|
|
||||||
|
// Validate username and password
|
||||||
|
try {
|
||||||
|
|
||||||
|
AuthorizedConfiguration info = config.getAuthenticationProvider().getAuthorizedConfiguration(username, password);
|
||||||
|
if (info != null) {
|
||||||
|
|
||||||
|
// Store authorized configuration
|
||||||
|
HttpSession session = req.getSession(true);
|
||||||
|
session.setAttribute(
|
||||||
|
"BASIC-LOGIN-AUTH",
|
||||||
|
info
|
||||||
|
);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report "forbidden" on any failure
|
||||||
|
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Login invalid");
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new ServletException("Error validating credentials", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,59 @@
|
|||||||
|
package net.sourceforge.guacamole.net.tunnel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleServlet;
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
|
||||||
|
public class Connect extends GuacamoleServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldCreateSession() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Disconnect if already connected
|
||||||
|
if (session.isConnected())
|
||||||
|
session.disconnect();
|
||||||
|
|
||||||
|
// Obtain new connection
|
||||||
|
session.connect();
|
||||||
|
|
||||||
|
// Send data
|
||||||
|
try {
|
||||||
|
char[] connect = session.getConnectMessage().toCharArray();
|
||||||
|
session.getClient().write(connect, 0, connect.length);
|
||||||
|
session.getClient().authorize();
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new GuacamoleException("Error sending data to server: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,59 @@
|
|||||||
|
package net.sourceforge.guacamole.net.tunnel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleServlet;
|
||||||
|
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
|
||||||
|
public class Inbound extends GuacamoleServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||||
|
|
||||||
|
session.getClient().waitForAuthorization();
|
||||||
|
|
||||||
|
// Send data
|
||||||
|
try {
|
||||||
|
|
||||||
|
Reader input = request.getReader();
|
||||||
|
char[] buffer = new char[8192];
|
||||||
|
|
||||||
|
int length;
|
||||||
|
while ((length = input.read(buffer, 0, buffer.length)) != -1)
|
||||||
|
session.getClient().write(buffer, 0, length);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException("I/O Error sending data to server: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
throw new GuacamoleException("Error sending data to server: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,99 @@
|
|||||||
|
package net.sourceforge.guacamole.net.tunnel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import net.sourceforge.guacamole.Client;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleServlet;
|
||||||
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
|
||||||
|
|
||||||
|
public class Outbound extends GuacamoleServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||||
|
|
||||||
|
session.getClient().waitForAuthorization();
|
||||||
|
|
||||||
|
ReentrantLock instructionStreamLock = session.getInstructionStreamLock();
|
||||||
|
instructionStreamLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
Writer out = response.getWriter();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Query new update from server
|
||||||
|
Client client = session.getClient();
|
||||||
|
|
||||||
|
// For all messages, until another stream is ready (we send at least one message)
|
||||||
|
char[] message;
|
||||||
|
while ((message = client.read()) != null) {
|
||||||
|
|
||||||
|
// Get message output bytes
|
||||||
|
out.write(message, 0, message.length);
|
||||||
|
out.flush();
|
||||||
|
response.flushBuffer();
|
||||||
|
|
||||||
|
// No more messages another stream can take over
|
||||||
|
if (instructionStreamLock.hasQueuedThreads())
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message == null) {
|
||||||
|
session.disconnect();
|
||||||
|
throw new GuacamoleException("Disconnected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (GuacamoleException e) {
|
||||||
|
out.write("error:" + e.getMessage() + ";");
|
||||||
|
out.flush();
|
||||||
|
response.flushBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// End-of-instructions marker
|
||||||
|
out.write(';');
|
||||||
|
out.flush();
|
||||||
|
response.flushBuffer();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException e) {
|
||||||
|
throw new GuacamoleException("UTF-8 not supported by Java.", e);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleException("I/O error writing to servlet output stream.", e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
instructionStreamLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user