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);
+ }
}
}