mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
Working login page and user auth configuration
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
|
||||||
|
|
||||||
<tomcat-users>
|
|
||||||
<role rolename="guacamole"/>
|
|
||||||
<user username="guacamole" password="changeme" roles="guacamole"/>
|
|
||||||
</tomcat-users>
|
|
@@ -18,12 +18,16 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Context antiJARLocking="true" path="/guacamole" docBase="/var/lib/guacamole/guacamole.war">
|
<Context antiJARLocking="true" path="/guacamole" docBase="/var/lib/guacamole/guacamole.war">
|
||||||
|
|
||||||
<!-- Change the lines below to match your Guacamole proxy -->
|
<!-- Change the lines below to match your Guacamole proxy -->
|
||||||
<Parameter name="hostname" value="localhost"/>
|
<Parameter name="guacd-hostname" value="localhost"/>
|
||||||
<Parameter name="port" value="1234"/>
|
<Parameter name="guacd-port" value="4822"/>
|
||||||
|
|
||||||
|
<!-- Session provider class (provides and configured guacamole session based on authentication information) -->
|
||||||
|
<Parameter name="session-provider" value="net.sourceforge.guacamole.basic.BasicGuacamoleSessionProvider"/>
|
||||||
|
<Parameter name="basic-user-mapping" value="/path/to/user-mapping.xml"/>
|
||||||
|
|
||||||
<Realm className="org.apache.catalina.realm.MemoryRealm" pathname="conf/guacamole-users.xml"/>
|
|
||||||
</Context>
|
</Context>
|
||||||
|
|
||||||
|
11
guacamole/web-client/doc/example/user-mapping.xml
Normal file
11
guacamole/web-client/doc/example/user-mapping.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<user-mapping>
|
||||||
|
|
||||||
|
<!-- Per-user authentication and config information -->
|
||||||
|
<authorize username="USERNAME" password="PASSWORD">
|
||||||
|
<protocol>vnc</protocol>
|
||||||
|
<hostname>localhost</hostname>
|
||||||
|
<port>5900</port>
|
||||||
|
<password>VNCPASS</password>
|
||||||
|
</authorize>
|
||||||
|
|
||||||
|
</user-mapping>
|
@@ -1,8 +1,10 @@
|
|||||||
|
|
||||||
package net.sourceforge.guacamole.net;
|
package net.sourceforge.guacamole.basic;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import net.sourceforge.guacamole.GuacamoleException;
|
import net.sourceforge.guacamole.GuacamoleException;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||||
|
import net.sourceforge.guacamole.net.GuacamoleSessionProvider;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Guacamole - Clientless Remote Desktop
|
* Guacamole - Clientless Remote Desktop
|
||||||
@@ -26,11 +28,21 @@ public class BasicGuacamoleSessionProvider implements GuacamoleSessionProvider {
|
|||||||
|
|
||||||
public GuacamoleSession createSession(HttpSession session) throws GuacamoleException {
|
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);
|
GuacamoleSession guacSession = new GuacamoleSession(session);
|
||||||
|
guacSession.setConnection(config.getProtocol(), config.getHostname(), config.getPort());
|
||||||
|
if (config.getPassword() != null)
|
||||||
|
guacSession.setPassword(config.getPassword());
|
||||||
|
|
||||||
guacSession.setConnection("vnc", "localhost", 5901);
|
// Return authorized session
|
||||||
guacSession.setPassword("potato");
|
|
||||||
|
|
||||||
return guacSession;
|
return guacSession;
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.basic;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
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.basic.BasicUserMappingContentHandler.AuthInfo;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
import org.xml.sax.helpers.XMLReaderFactory;
|
||||||
|
|
||||||
|
public class BasicLogin extends HttpServlet {
|
||||||
|
|
||||||
|
private Map<String, AuthInfo> mapping;
|
||||||
|
|
||||||
|
// Added to session when session validated
|
||||||
|
public 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
|
||||||
|
public void init() throws ServletException {
|
||||||
|
|
||||||
|
// Get user mapping filename
|
||||||
|
ServletContext context = getServletContext();
|
||||||
|
String filename = context.getInitParameter("basic-user-mapping");
|
||||||
|
if (filename == null)
|
||||||
|
throw new ServletException("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(filename);
|
||||||
|
|
||||||
|
mapping = contentHandler.getUserMapping();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new ServletException("Error reading basic user mapping file.", e);
|
||||||
|
}
|
||||||
|
catch (SAXException e) {
|
||||||
|
throw new ServletException("Error parsing basic user mapping XML.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@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");
|
||||||
|
|
||||||
|
// Retrieve corresponding authorization info
|
||||||
|
AuthInfo info = mapping.get(username);
|
||||||
|
if (info != null) {
|
||||||
|
|
||||||
|
// Validate username and password
|
||||||
|
if (info.getAuthorizedUsername().equals(username)
|
||||||
|
&& info.getAuthorizedPassword().equals(password)) {
|
||||||
|
|
||||||
|
// Store authorized configuration
|
||||||
|
HttpSession session = req.getSession(true);
|
||||||
|
session.setAttribute(
|
||||||
|
"BASIC-LOGIN-AUTH",
|
||||||
|
new AuthorizedConfiguration(
|
||||||
|
info.getProtocol(),
|
||||||
|
info.getHostname(),
|
||||||
|
info.getPort(),
|
||||||
|
info.getPassword()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report "forbidden" on any failure
|
||||||
|
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Login invalid");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,150 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.guacamole.basic;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
public class BasicUserMappingContentHandler extends DefaultHandler {
|
||||||
|
|
||||||
|
private Map<String, AuthInfo> authMapping = new HashMap<String, AuthInfo>();
|
||||||
|
|
||||||
|
public Map<String, AuthInfo> getUserMapping() {
|
||||||
|
return Collections.unmodifiableMap(authMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthInfo {
|
||||||
|
|
||||||
|
private String auth_username;
|
||||||
|
private String auth_password;
|
||||||
|
|
||||||
|
private String protocol;
|
||||||
|
private String hostname;
|
||||||
|
private int port;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public AuthInfo(String auth_username, String auth_password) {
|
||||||
|
this.auth_username = auth_username;
|
||||||
|
this.auth_password = auth_password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthorizedUsername() {
|
||||||
|
return auth_username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthorizedPassword() {
|
||||||
|
return auth_password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostname() {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getAuthorizedUsername(),
|
||||||
|
current
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
infoState = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||||
|
|
||||||
|
if (localName.equals("authorize")) {
|
||||||
|
|
||||||
|
current = new AuthInfo(
|
||||||
|
attributes.getValue("username"),
|
||||||
|
attributes.getValue("password")
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Context antiJARLocking="true" path="">
|
|
||||||
|
|
||||||
<!-- Hostname and port of guacamole proxy -->
|
|
||||||
<Parameter name="guacd-hostname" value="localhost"/>
|
|
||||||
<Parameter name="guacd-port" value="4822"/>
|
|
||||||
|
|
||||||
<!-- Session provider class (provides and configured guacamole session based on authentication information) -->
|
|
||||||
<Parameter name="session-provider" value="net.sourceforge.guacamole.net.BasicGuacamoleSessionProvider"/>
|
|
||||||
|
|
||||||
</Context>
|
|
@@ -19,7 +19,6 @@
|
|||||||
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||||
|
|
||||||
<!-- Basic config -->
|
<!-- Basic config -->
|
||||||
|
|
||||||
<welcome-file-list>
|
<welcome-file-list>
|
||||||
<welcome-file>index.html</welcome-file>
|
<welcome-file>index.html</welcome-file>
|
||||||
</welcome-file-list>
|
</welcome-file-list>
|
||||||
@@ -30,8 +29,7 @@
|
|||||||
</session-timeout>
|
</session-timeout>
|
||||||
</session-config>
|
</session-config>
|
||||||
|
|
||||||
<!-- Servlets -->
|
<!-- Guacamole Tunnel Servlets -->
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<description>Connect servlet.</description>
|
<description>Connect servlet.</description>
|
||||||
<servlet-name>Connect</servlet-name>
|
<servlet-name>Connect</servlet-name>
|
||||||
@@ -41,7 +39,6 @@
|
|||||||
<servlet-name>Connect</servlet-name>
|
<servlet-name>Connect</servlet-name>
|
||||||
<url-pattern>/connect</url-pattern>
|
<url-pattern>/connect</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<description>Outbound servlet.</description>
|
<description>Outbound servlet.</description>
|
||||||
<servlet-name>Outbound</servlet-name>
|
<servlet-name>Outbound</servlet-name>
|
||||||
@@ -51,7 +48,6 @@
|
|||||||
<servlet-name>Outbound</servlet-name>
|
<servlet-name>Outbound</servlet-name>
|
||||||
<url-pattern>/outbound</url-pattern>
|
<url-pattern>/outbound</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<description>Input servlet.</description>
|
<description>Input servlet.</description>
|
||||||
<servlet-name>Inbound</servlet-name>
|
<servlet-name>Inbound</servlet-name>
|
||||||
@@ -62,4 +58,14 @@
|
|||||||
<url-pattern>/inbound</url-pattern>
|
<url-pattern>/inbound</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<!-- Basic Login Servlets -->
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>BasicLogin</servlet-name>
|
||||||
|
<servlet-class>net.sourceforge.guacamole.basic.BasicLogin</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>BasicLogin</servlet-name>
|
||||||
|
<url-pattern>/login</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
</web-app>
|
</web-app>
|
||||||
|
@@ -34,6 +34,13 @@ div#login-ui {
|
|||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p#login-error {
|
||||||
|
text-align: center;
|
||||||
|
background: #FDD;
|
||||||
|
color: red;
|
||||||
|
margin: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
div#login-logo {
|
div#login-logo {
|
||||||
position: relative;
|
position: relative;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -71,19 +78,18 @@ div#login-dialog h1 {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0em;
|
margin-bottom: 0em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid silver;
|
|
||||||
padding-bottom: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div#login-dialog #buttons {
|
div#login-dialog #buttons {
|
||||||
border-top: 1px solid silver;
|
|
||||||
padding-top: 0.5em;
|
padding-top: 0.5em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#login-dialog #login-fields {
|
div#login-dialog #login-fields {
|
||||||
margin-top: 0.5em;
|
border-top: 1px solid silver;
|
||||||
margin-bottom: 0.5em;
|
border-bottom: 1px solid silver;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.errorDialogOuter {
|
div.errorDialogOuter {
|
||||||
|
@@ -40,6 +40,9 @@
|
|||||||
<div id="login-dialog">
|
<div id="login-dialog">
|
||||||
|
|
||||||
<h1>Guacamole Login</h1>
|
<h1>Guacamole Login</h1>
|
||||||
|
|
||||||
|
<p id="login-error"></p>
|
||||||
|
|
||||||
<form id="login-form" action="#">
|
<form id="login-form" action="#">
|
||||||
<table id="login-fields">
|
<table id="login-fields">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -124,10 +127,33 @@
|
|||||||
|
|
||||||
loginForm.onsubmit = function() {
|
loginForm.onsubmit = function() {
|
||||||
|
|
||||||
// FIXME: Do ACTUAL login here
|
var username = document.getElementById("username");
|
||||||
|
var password = document.getElementById("password");
|
||||||
|
|
||||||
loginUI.style.display = "none";
|
var data =
|
||||||
startGuacamole();
|
"username=" + encodeURIComponent(username.value)
|
||||||
|
+ "&password=" + encodeURIComponent(password.value)
|
||||||
|
|
||||||
|
var xmlhttprequest = new XMLHttpRequest();
|
||||||
|
xmlhttprequest.open("POST", "login", false);
|
||||||
|
xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
xmlhttprequest.setRequestHeader("Content-length", data.length);
|
||||||
|
xmlhttprequest.send(data);
|
||||||
|
|
||||||
|
if (xmlhttprequest.status == 200) {
|
||||||
|
loginUI.style.display = "none";
|
||||||
|
startGuacamole();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
var loginError = document.getElementById("login-error");
|
||||||
|
|
||||||
|
// Display error, reset and refocus password field
|
||||||
|
loginError.textContent = "Invalid login. Please try again.";
|
||||||
|
password.value = "";
|
||||||
|
password.focus();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user