diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/PermissionList.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/PermissionList.java new file mode 100644 index 000000000..7aeee9f16 --- /dev/null +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/PermissionList.java @@ -0,0 +1,206 @@ +package net.sourceforge.guacamole.net.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 javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import net.sourceforge.guacamole.GuacamoleException; +import net.sourceforge.guacamole.GuacamoleSecurityException; +import net.sourceforge.guacamole.net.auth.PermissionDirectory; +import net.sourceforge.guacamole.net.auth.UserContext; +import net.sourceforge.guacamole.net.auth.permission.GuacamoleConfigurationDirectoryPermission; +import net.sourceforge.guacamole.net.auth.permission.GuacamoleConfigurationPermission; +import net.sourceforge.guacamole.net.auth.permission.ObjectPermission; +import net.sourceforge.guacamole.net.auth.permission.Permission; +import net.sourceforge.guacamole.net.auth.permission.SystemPermission; +import net.sourceforge.guacamole.net.auth.permission.UserDirectoryPermission; +import net.sourceforge.guacamole.net.auth.permission.UserPermission; + +/** + * Simple HttpServlet which outputs XML containing a list of all visible + * permissions of a given user. + * + * @author Michael Jumper + */ +public class PermissionList extends AuthenticatingHttpServlet { + + /** + * Returns the XML attribute value representation of the given + * SystemPermission.Type. + * + * @param type The SystemPermission.Type to translate into a String. + * @return The XML attribute value representation of the given + * SystemPermission.Type. + * + * @throws GuacamoleException If the type given is not implemented. + */ + private String toString(SystemPermission.Type type) + throws GuacamoleException { + + switch (type) { + case CREATE: return "read"; + } + + throw new GuacamoleException("Unknown permission type: " + type); + + } + + /** + * Returns the XML attribute value representation of the given + * ObjectPermission.Type. + * + * @param type The ObjectPermission.Type to translate into a String. + * @return The XML attribute value representation of the given + * ObjectPermission.Type. + * + * @throws GuacamoleException If the type given is not implemented. + */ + private String toString(ObjectPermission.Type type) + throws GuacamoleException { + + switch (type) { + case READ: return "read"; + case UPDATE: return "update"; + case DELETE: return "delete"; + case ADMINISTER: return "admin"; + } + + throw new GuacamoleException("Unknown permission type: " + type); + + } + + @Override + protected void authenticatedService( + UserContext context, + HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + + // Do not cache + response.setHeader("Cache-Control", "no-cache"); + + // Write actual XML + try { + + // Get permission directory + PermissionDirectory permissions = context.getPermissionDirectory(); + + // Get username + String username = request.getParameter("user"); + if (username == null) + throw new ServletException("No user specified."); + + // Write XML content type + response.setHeader("Content-Type", "text/xml"); + + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter()); + + // Begin document + xml.writeStartDocument(); + xml.writeStartElement("permissions"); + xml.writeAttribute("user", username); + + // For each entry, write corresponding user element + for (Permission permission : permissions.getPermissions(username)) { + + // Config directory permission + if (permission instanceof GuacamoleConfigurationDirectoryPermission) { + + // Get permission + GuacamoleConfigurationDirectoryPermission gcdp = + (GuacamoleConfigurationDirectoryPermission) permission; + + // Write permission + xml.writeEmptyElement("configs"); + xml.writeAttribute("type", toString(gcdp.getType())); + + } + + // Config permission + else if (permission instanceof GuacamoleConfigurationPermission) { + + // Get permission + GuacamoleConfigurationPermission gcp = + (GuacamoleConfigurationPermission) permission; + + // Write permission + xml.writeEmptyElement("config"); + xml.writeAttribute("type", toString(gcp.getType())); + xml.writeAttribute("name", gcp.getObjectIdentifier()); + + } + + // User directory permission + else if (permission instanceof UserDirectoryPermission) { + + // Get permission + UserDirectoryPermission udp = + (UserDirectoryPermission) permission; + + // Write permission + xml.writeEmptyElement("users"); + xml.writeAttribute("type", toString(udp.getType())); + + } + + // User permission + else if (permission instanceof UserPermission) { + + // Get permission + UserPermission up = (UserPermission) permission; + + // Write permission + xml.writeEmptyElement("users"); + xml.writeAttribute("type", toString(up.getType())); + xml.writeAttribute("name", up.getObjectIdentifier()); + + } + + else + throw new ServletException("Unsupported permission type."); + + } + + // End document + xml.writeEndElement(); + xml.writeEndDocument(); + + } + catch (XMLStreamException e) { + throw new IOException("Unable to write permission list XML.", e); + } + catch (GuacamoleSecurityException e) { + + // If cannot read permissions, return error + response.sendError(HttpServletResponse.SC_FORBIDDEN, + "Permission denied."); + + } + catch (GuacamoleException e) { + throw new ServletException("Unable to read permissions.", e); + } + + } + +} diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/UserList.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/UserList.java new file mode 100644 index 000000000..7f478c227 --- /dev/null +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/UserList.java @@ -0,0 +1,210 @@ +package net.sourceforge.guacamole.net.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.util.Set; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import net.sourceforge.guacamole.GuacamoleException; +import net.sourceforge.guacamole.GuacamoleSecurityException; +import net.sourceforge.guacamole.net.auth.PermissionDirectory; +import net.sourceforge.guacamole.net.auth.User; +import net.sourceforge.guacamole.net.auth.UserContext; +import net.sourceforge.guacamole.net.auth.UserDirectory; +import net.sourceforge.guacamole.net.auth.permission.ObjectPermission; +import net.sourceforge.guacamole.net.auth.permission.Permission; +import net.sourceforge.guacamole.net.auth.permission.SystemPermission; +import net.sourceforge.guacamole.net.auth.permission.UserDirectoryPermission; +import net.sourceforge.guacamole.net.auth.permission.UserPermission; + +/** + * Simple HttpServlet which outputs XML containing a list of all visible users. + * + * @author Michael Jumper + */ +public class UserList extends AuthenticatingHttpServlet { + + /** + * Checks whether the given user has permission to perform the given + * system operation. Security exceptions are handled appropriately - only + * non-security exceptions pass through. + * + * @param permissions The PermissionsDirectory to check. + * @param user The user whose permissions should be verified. + * @param type The type of operation to check for permission for. + * @return true if permission is granted, false otherwise. + * + * @throws GuacamoleException If an error occurs while checking permissions. + */ + private boolean hasUserPermission(PermissionDirectory permissions, + String user, SystemPermission.Type type) + throws GuacamoleException { + + // Build permission + Permission permission = new UserDirectoryPermission(type); + + try { + // Return result of permission check, if possible + return permissions.hasPermission(user, permission); + } + catch (GuacamoleSecurityException e) { + // If cannot check due to security restrictions, no permission + return false; + } + + } + + /** + * Checks whether the given user has permission to perform the given + * object operation. Security exceptions are handled appropriately - only + * non-security exceptions pass through. + * + * @param permissions The PermissionsDirectory to check. + * @param user The user whose permissions should be verified. + * @param type The type of operation to check for permission for. + * @param identifier The identifier of the user the operation would be + * performed upon. + * @return true if permission is granted, false otherwise. + * + * @throws GuacamoleException If an error occurs while checking permissions. + */ + private boolean hasUserPermission(PermissionDirectory permissions, + String user, ObjectPermission.Type type, String identifier) + throws GuacamoleException { + + // Build permission + Permission permission = new UserPermission(type, identifier); + + try { + // Return result of permission check, if possible + return permissions.hasPermission(user, permission); + } + catch (GuacamoleSecurityException e) { + // If cannot check due to security restrictions, no permission + return false; + } + + } + + @Override + protected void authenticatedService( + UserContext context, + HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + + // Do not cache + response.setHeader("Cache-Control", "no-cache"); + + // Write XML content type + response.setHeader("Content-Type", "text/xml"); + + // Try to get permission directory + PermissionDirectory permissions = null; + try { + permissions = context.getPermissionDirectory(); + } + catch (GuacamoleSecurityException e) { + // Soft fail - can't check permissions ... assume have READ and + // nothing else + } + catch (GuacamoleException e) { + throw new ServletException("Unable to retrieve permissions.", e); + } + + // Write actual XML + try { + + // Get user directory + UserDirectory directory = context.getUserDirectory(); + + // Get users + Set users = directory.getUsers(); + + // Get username + String username = context.self().getUsername(); + + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter()); + + // Begin document + xml.writeStartDocument(); + xml.writeStartElement("users"); + + // Save user create permission attribute + if (hasUserPermission(permissions, username, + SystemPermission.Type.CREATE)) + xml.writeAttribute("create", "yes"); + + // For each entry, write corresponding user element + for (User user : users) { + + // Write user + xml.writeEmptyElement("user"); + xml.writeAttribute("name", user.getUsername()); + + // Check permissions and set attributes appropriately + if (permissions != null) { + + // Save update permission attribute + if (hasUserPermission(permissions, username, + ObjectPermission.Type.UPDATE, user.getUsername())) + xml.writeAttribute("update", "yes"); + + // Save admin permission attribute + if (hasUserPermission(permissions, username, + ObjectPermission.Type.ADMINISTER, user.getUsername())) + xml.writeAttribute("admin", "yes"); + + // Save delete permission attribute + if (hasUserPermission(permissions, username, + ObjectPermission.Type.DELETE, user.getUsername())) + xml.writeAttribute("delete", "yes"); + + } + + } + + // End document + xml.writeEndElement(); + xml.writeEndDocument(); + + } + catch (XMLStreamException e) { + throw new IOException("Unable to write user list XML.", e); + } + catch (GuacamoleSecurityException e) { + + // If cannot read permissions, return error + response.sendError(HttpServletResponse.SC_FORBIDDEN, + "Permission denied."); + + } + catch (GuacamoleException e) { + throw new ServletException("Unable to read users.", e); + } + + } + +} + diff --git a/guacamole/src/main/webapp/WEB-INF/web.xml b/guacamole/src/main/webapp/WEB-INF/web.xml index ce87d3406..051b96c44 100644 --- a/guacamole/src/main/webapp/WEB-INF/web.xml +++ b/guacamole/src/main/webapp/WEB-INF/web.xml @@ -66,6 +66,28 @@ /configs + + + User list servlet. + Users + net.sourceforge.guacamole.net.basic.UserList + + + Users + /users + + + + + Permission list servlet. + Permissions + net.sourceforge.guacamole.net.basic.PermissionList + + + Permissions + /permissions + + Tunnel servlet.