From 064802a9fbc4d3e8e024ed362fe306d691cde99b Mon Sep 17 00:00:00 2001 From: James Muehlner Date: Fri, 6 Sep 2013 21:25:03 -0700 Subject: [PATCH] Ticket #362: Authentication working. --- guacamole/pom.xml | 14 +++ .../guacamole/net/basic/rest/RESTModule.java | 69 +++++++++++ .../rest/RESTServletContextListener.java | 16 +-- .../net/basic/rest/RESTServletModule.java | 42 +++++++ .../basic/rest/auth/AuthTokenGenerator.java | 34 ++++++ .../rest/auth/BasicTokenUserContextMap.java | 30 +++++ .../net/basic/rest/auth/LoginService.java | 107 ++++++++++++++++++ .../auth/SecureRandomAuthTokenGenerator.java | 30 +++++ .../basic/rest/auth/TokenUserContextMap.java | 30 +++++ .../rest/connection/ConnectionService.java | 53 ++++++++- 10 files changed, 407 insertions(+), 18 deletions(-) create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/AuthTokenGenerator.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/BasicTokenUserContextMap.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/LoginService.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/SecureRandomAuthTokenGenerator.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenUserContextMap.java diff --git a/guacamole/pom.xml b/guacamole/pom.xml index 1fba0a374..b76f8b088 100644 --- a/guacamole/pom.xml +++ b/guacamole/pom.xml @@ -138,6 +138,20 @@ jersey-guice 1.7 + + + + javax.annotation + jsr250-api + 1.0 + + + + + commons-codec + commons-codec + 1.4 + diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java new file mode 100644 index 000000000..1ac01a6e7 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java @@ -0,0 +1,69 @@ +package org.glyptodon.guacamole.net.basic.rest; + +/* + * 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 com.google.inject.AbstractModule; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.AuthenticationProvider; +import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties; +import org.glyptodon.guacamole.net.basic.rest.auth.AuthTokenGenerator; +import org.glyptodon.guacamole.net.basic.rest.auth.BasicTokenUserContextMap; +import org.glyptodon.guacamole.net.basic.rest.auth.SecureRandomAuthTokenGenerator; +import org.glyptodon.guacamole.net.basic.rest.auth.TokenUserContextMap; +import org.glyptodon.guacamole.properties.GuacamoleProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A Guice Module for setting up dependency injection for the + * Guacamole REST API. + * + * @author James Muehlner + */ +public class RESTModule extends AbstractModule { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(RESTModule.class); + + /** + * The AuthenticationProvider to use to authenticate all requests. + */ + private AuthenticationProvider authProvider; + + @Override + protected void configure() { + + // Get auth provider instance + try { + authProvider = GuacamoleProperties.getRequiredProperty(BasicGuacamoleProperties.AUTH_PROVIDER); + } + catch (GuacamoleException e) { + logger.error("Error getting authentication provider from properties.", e); + throw new RuntimeException(e); + } + + bind(AuthenticationProvider.class).toInstance(authProvider); + bind(TokenUserContextMap.class).toInstance(new BasicTokenUserContextMap()); + + bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletContextListener.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletContextListener.java index ea59621ca..50e1783f8 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletContextListener.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletContextListener.java @@ -19,11 +19,8 @@ package org.glyptodon.guacamole.net.basic.rest; */ import com.google.inject.Guice; -import com.google.inject.servlet.ServletModule; -import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService; /** * A ServletContextListenr to listen for initialization of the servlet context @@ -35,15 +32,10 @@ public class RESTServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { - Guice.createInjector(new ServletModule() { - @Override - protected void configureServlets() { - - bind(ConnectionService.class); - - serve("*").with(GuiceContainer.class); - } - }); + Guice.createInjector( + new RESTServletModule(), + new RESTModule() + ); } @Override diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java new file mode 100644 index 000000000..00627e59d --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java @@ -0,0 +1,42 @@ +package org.glyptodon.guacamole.net.basic.rest; + +/* + * 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 com.google.inject.servlet.ServletModule; +import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; +import org.glyptodon.guacamole.net.basic.rest.auth.LoginService; +import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService; + +/** + * A Guice Module to set up the servlet mappings for the Guacamole REST API. + * + * @author James Muehlner + */ +public class RESTServletModule extends ServletModule { + + @Override + protected void configureServlets() { + + bind(ConnectionService.class); + bind(LoginService.class); + + serve("*").with(GuiceContainer.class); + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/AuthTokenGenerator.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/AuthTokenGenerator.java new file mode 100644 index 000000000..2842fe673 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/AuthTokenGenerator.java @@ -0,0 +1,34 @@ +package org.glyptodon.guacamole.net.basic.rest.auth; + +/* + * 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 . + */ + +/** + * Generates an auth token for an authenticated user. + * + * @author James Muehlner + */ +public interface AuthTokenGenerator { + + /** + * Get a new auth token. + * + * @return A new auth token. + */ + public String getToken(); +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/BasicTokenUserContextMap.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/BasicTokenUserContextMap.java new file mode 100644 index 000000000..b6ba99882 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/BasicTokenUserContextMap.java @@ -0,0 +1,30 @@ +package org.glyptodon.guacamole.net.basic.rest.auth; + +/* + * 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.util.HashMap; +import org.glyptodon.guacamole.net.auth.UserContext; + +/** + * A Basic, HashMap-based implementation of the TokenUserContextMap. + * + * @author James Muehlner + */ +public class BasicTokenUserContextMap extends HashMap + implements TokenUserContextMap {} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/LoginService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/LoginService.java new file mode 100644 index 000000000..19e97392e --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/LoginService.java @@ -0,0 +1,107 @@ +package org.glyptodon.guacamole.net.basic.rest.auth; + +import com.google.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.AuthenticationProvider; +import org.glyptodon.guacamole.net.auth.Credentials; +import org.glyptodon.guacamole.net.auth.UserContext; +import org.glyptodon.guacamole.net.basic.rest.RESTModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * 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 . + */ + +/** + * A service for authenticating to the Guacamole REST API. Given valid + * credentials, the service will return an auth token. Invalid credentials will + * result in a permission error. + * + * @author James Muehlner + */ + + +@Path("/api/login") +public class LoginService { + + /** + * The authentication provider used to authenticate this user. + */ + @Inject + private AuthenticationProvider authProvider; + + /** + * The map of auth tokens to users for the REST endpoints. + */ + @Inject + private TokenUserContextMap tokenUserMap; + + /** + * A generator for creating new auth tokens. + */ + @Inject + private AuthTokenGenerator authTokenGenerator; + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(LoginService.class); + + /** + * Authenticates a user, generates an auth token, associates that auth token + * with the user's UserContext for use by further requests. + * + * @param username The username of the user who is to be authenticated. + * @param password The password of the user who is to be authenticated. + * @return The auth token for the newly logged-in user. + */ + @POST + @Path("/") + public String login(@QueryParam("username") String username, + @QueryParam("password") String password) { + + Credentials credentials = new Credentials(); + credentials.setUsername(username); + credentials.setPassword(password); + + UserContext userContext; + + try { + userContext = authProvider.getUserContext(credentials); + } catch(GuacamoleException e) { + logger.error("Exception caught while authenticating user.", e); + throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); + } + + // authentication failed. + if(userContext == null) + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + + String authToken = authTokenGenerator.getToken(); + + tokenUserMap.put(authToken, userContext); + + return authToken; + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/SecureRandomAuthTokenGenerator.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/SecureRandomAuthTokenGenerator.java new file mode 100644 index 000000000..89fc01b4f --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/SecureRandomAuthTokenGenerator.java @@ -0,0 +1,30 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.glyptodon.guacamole.net.basic.rest.auth; + +import java.security.SecureRandom; +import org.apache.commons.codec.binary.Hex; + +/** + * An implementation of the AuthTokenGenerator based around SecureRandom. + * + * @author James Muehlner + */ +public class SecureRandomAuthTokenGenerator implements AuthTokenGenerator { + + /** + * Instance of SecureRandom for generating the auth token. + */ + private SecureRandom secureRandom = new SecureRandom(); + + @Override + public String getToken() { + byte[] bytes = new byte[32]; + secureRandom.nextBytes(bytes); + + return Hex.encodeHexString(bytes); + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenUserContextMap.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenUserContextMap.java new file mode 100644 index 000000000..0f106ecfc --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenUserContextMap.java @@ -0,0 +1,30 @@ +package org.glyptodon.guacamole.net.basic.rest.auth; + +/* + * 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.util.Map; +import org.glyptodon.guacamole.net.auth.UserContext; + +/** + * Represents a mapping of auth token to user context for the REST + * authentication system. + * + * @author James Muehlner + */ +public interface TokenUserContextMap extends Map {} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java index f784113d0..3f4125787 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java @@ -1,11 +1,33 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package org.glyptodon.guacamole.net.basic.rest.connection; +/* + * 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 com.google.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.net.auth.UserContext; +import org.glyptodon.guacamole.net.basic.rest.auth.TokenUserContextMap; /** * A REST Service for handling connection CRUD operations. @@ -15,10 +37,29 @@ import javax.ws.rs.Path; @Path("/api/connection") public class ConnectionService { + /** + * The map of auth tokens to users for the REST endpoints. + */ + @Inject + private TokenUserContextMap tokenUserMap; + @Path("/") @GET - public String getConnections() { - return "goo"; + public String getConnections(@QueryParam("token") String authToken) { + UserContext userContext = tokenUserMap.get(authToken); + + // authentication failed. + if(userContext == null) + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + + try { + //TODO: Make this work for realzies + return userContext.getRootConnectionGroup().getConnectionDirectory().getIdentifiers().toString(); + } catch(GuacamoleSecurityException e) { + throw new WebApplicationException(e, Response.Status.UNAUTHORIZED); + } catch(GuacamoleException e) { + throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); + } } }