From a13d371d555578e36c248dcfede44a01c49b1453 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 8 Dec 2010 23:42:34 -0800 Subject: [PATCH] Moved basic auth into default webapp --- .../BasicFileAuthenticationProvider.java | 318 ------------------ .../basic/BasicGuacamoleSessionProvider.java | 50 --- .../net/authentication/basic/BasicLogin.java | 161 --------- 3 files changed, 529 deletions(-) delete mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicFileAuthenticationProvider.java delete mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicGuacamoleSessionProvider.java delete mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicLogin.java diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicFileAuthenticationProvider.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicFileAuthenticationProvider.java deleted file mode 100644 index 83fcfd34c..000000000 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicFileAuthenticationProvider.java +++ /dev/null @@ -1,318 +0,0 @@ - -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 . - */ - -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 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 authMapping = new HashMap(); - - public Map 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; - - } - - } - - - } - - -} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicGuacamoleSessionProvider.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicGuacamoleSessionProvider.java deleted file mode 100644 index 959bf0e6e..000000000 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicGuacamoleSessionProvider.java +++ /dev/null @@ -1,50 +0,0 @@ - -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 . - */ - -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; - - } - -} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicLogin.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicLogin.java deleted file mode 100644 index 43e8721d9..000000000 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/authentication/basic/BasicLogin.java +++ /dev/null @@ -1,161 +0,0 @@ - -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 . - */ - -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); - } - - } - - -}