diff --git a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProvider.java b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProvider.java index ccb1c40a1..f9989965d 100644 --- a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProvider.java +++ b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProvider.java @@ -62,6 +62,11 @@ public class DuoAuthenticationProvider implements AuthenticationProvider { return "duo"; } + @Override + public Object getResource() { + return null; + } + @Override public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { diff --git a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProvider.java b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProvider.java index 8729b0835..1721f16ce 100644 --- a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProvider.java +++ b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProvider.java @@ -63,6 +63,11 @@ public class HTTPHeaderAuthenticationProvider implements AuthenticationProvider return "header"; } + @Override + public Object getResource() { + return null; + } + @Override public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java index 4c5918b1c..d06d6edad 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java @@ -70,6 +70,11 @@ public abstract class InjectedAuthenticationProvider implements AuthenticationPr } + @Override + public Object getResource() throws GuacamoleException { + return null; + } + @Override public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java index 21f97e31d..cad1bab7f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java @@ -136,6 +136,11 @@ public class SharedUserContext implements UserContext { return self; } + @Override + public Object getResource() throws GuacamoleException { + return null; + } + @Override public AuthenticationProvider getAuthenticationProvider() { return authProvider; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java index fdeb64d5d..d43c3c1c3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java @@ -116,6 +116,11 @@ public class ModeledUserContext extends RestrictedObject return getCurrentUser().getUser(); } + @Override + public Object getResource() throws GuacamoleException { + return null; + } + @Override public AuthenticationProvider getAuthenticationProvider() { return getCurrentUser().getModelAuthenticationProvider(); diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProvider.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProvider.java index 001f2c6ec..1db4ee915 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProvider.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProvider.java @@ -68,6 +68,11 @@ public class LDAPAuthenticationProvider implements AuthenticationProvider { return "ldap"; } + @Override + public String getResource() { + return null; + } + @Override public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserContext.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserContext.java index 0f693fb34..2c4703c70 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserContext.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserContext.java @@ -159,6 +159,11 @@ public class UserContext implements org.apache.guacamole.net.auth.UserContext { return self; } + @Override + public String getResource() { + return null; + } + @Override public AuthenticationProvider getAuthenticationProvider() { return authProvider; diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AuthenticationProvider.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AuthenticationProvider.java index 977b3b620..401754d25 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AuthenticationProvider.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AuthenticationProvider.java @@ -40,6 +40,26 @@ public interface AuthenticationProvider { */ String getIdentifier(); + /** + * Returns an arbitrary REST resource. The REST resource returned must be + * properly annotated with JSR-311 annotations, and may serve as the root + * resource for any number of extension-specific REST resources which are + * unrelated to an authenticated user's session. The returned resource is + * ultimately exposed at ".../api/ext/IDENTIFIER/", where IDENTIFIER is the + * identifier of the AuthenticationProvider. + * + * REST resources which ARE related to an authenticated user's session + * should instead be returned from UserContext.getResource(). + * + * @return + * An arbitrary REST resource, annotated with JSR-311 annotations, or + * null if no such resource is defined. + * + * @throws GuacamoleException + * If the REST resource cannot be returned due to an error. + */ + Object getResource() throws GuacamoleException; + /** * Returns an AuthenticatedUser representing the user authenticated by the * given credentials, if any. diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java index 42f2a37ab..7c483376a 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java @@ -38,6 +38,26 @@ public interface UserContext { */ User self(); + /** + * Returns an arbitrary REST resource. The REST resource returned must be + * properly annotated with JSR-311 annotations, and may serve as the root + * resource for any number of extension-specific REST resources related to + * an authenticated user's session. The returned resource is ultimately + * exposed at ".../api/session/data/IDENTIFIER/ext/", where IDENTIFIER is + * the identifier of the AuthenticationProvider. + * + * REST resources which are NOT related to an authenticated user's session + * should instead be returned from AuthenticationProvider.getResource(). + * + * @return + * An arbitrary REST resource, annotated with JSR-311 annotations, or + * null if no such resource is defined. + * + * @throws GuacamoleException + * If the REST resource cannot be returned due to an error. + */ + Object getResource() throws GuacamoleException; + /** * Returns the AuthenticationProvider which created this UserContext, which * may not be the same AuthenticationProvider that authenticated the user diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java index db7065173..96766cb31 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java @@ -203,6 +203,11 @@ public abstract class SimpleAuthenticationProvider } + @Override + public Object getResource() throws GuacamoleException { + return null; + } + @Override public AuthenticatedUser authenticateUser(final Credentials credentials) throws GuacamoleException { diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserContext.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserContext.java index c2d512be7..1e55db92f 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserContext.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserContext.java @@ -163,6 +163,11 @@ public class SimpleUserContext implements UserContext { return self; } + @Override + public Object getResource() throws GuacamoleException { + return null; + } + @Override public AuthenticationProvider getAuthenticationProvider() { return authProvider; diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java index b1c671c0c..e1ed5ff68 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java @@ -134,6 +134,20 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { } + @Override + public Object getResource() throws GuacamoleException { + + // Ignore auth attempts if no auth provider could be loaded + if (authProvider == null) { + logger.warn("The authentication system could not be loaded. Please check for errors earlier in the logs."); + return null; + } + + // Delegate to underlying auth provider + return authProvider.getResource(); + + } + @Override public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java index 95be583f8..cab4d973b 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java @@ -36,6 +36,7 @@ import org.apache.guacamole.rest.auth.SecureRandomAuthTokenGenerator; import org.apache.guacamole.rest.auth.TokenSessionMap; import org.apache.guacamole.rest.connection.ConnectionModule; import org.apache.guacamole.rest.connectiongroup.ConnectionGroupModule; +import org.apache.guacamole.rest.extension.ExtensionRESTService; import org.apache.guacamole.rest.language.LanguageRESTService; import org.apache.guacamole.rest.patch.PatchRESTService; import org.apache.guacamole.rest.session.SessionResourceFactory; @@ -84,6 +85,7 @@ public class RESTServiceModule extends ServletModule { bindInterceptor(Matchers.any(), new RESTMethodMatcher(), interceptor); // Set up the API endpoints + bind(ExtensionRESTService.class); bind(LanguageRESTService.class); bind(PatchRESTService.class); bind(TokenRESTService.class); diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/extension/ExtensionRESTService.java b/guacamole/src/main/java/org/apache/guacamole/rest/extension/ExtensionRESTService.java new file mode 100644 index 000000000..487bb7c11 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/extension/ExtensionRESTService.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.rest.extension; + +import com.google.inject.Inject; +import java.util.List; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleResourceNotFoundException; +import org.apache.guacamole.net.auth.AuthenticationProvider; + +/** + * A REST service which provides access to extension-specific REST resources, + * each exposed by the identifier of that extension's AuthenticationProvider. + */ +@Path("/ext") +public class ExtensionRESTService { + + /** + * All configured authentication providers. + */ + @Inject + private List authProviders; + + /** + * Returns the AuthenticationProvider having the given identifier. If no + * such AuthenticationProvider has been loaded, null is returned. + * + * @param identifier + * The identifier of the AuthenticationProvider to locate. + * + * @return + * The AuthenticationProvider having the given identifier, or null if + * no such AuthenticationProvider is loaded. + */ + private AuthenticationProvider getAuthenticationProvider(String identifier) { + + // Iterate through all installed AuthenticationProviders, searching for + // the given identifier + for (AuthenticationProvider authProvider : authProviders) { + if (authProvider.getIdentifier().equals(identifier)) + return authProvider; + } + + // No such AuthenticationProvider found + return null; + + } + + /** + * Returns the arbitrary REST resource exposed by the AuthenticationProvider + * having the given identifier. + * + * @param identifier + * The identifier of the AuthenticationProvider whose REST resource + * should be retrieved. + * + * @return + * The arbitrary REST resource exposed by the AuthenticationProvider + * having the given identifier. + * + * @throws GuacamoleException + * If no such resource could be found, or if an error occurs while + * retrieving that resource. + */ + @Path("{identifier}") + public Object getExtensionResource(@PathParam("identifier") String identifier) + throws GuacamoleException { + + // Retrieve authentication provider having given identifier + AuthenticationProvider authProvider = getAuthenticationProvider(identifier); + if (authProvider != null) { + + // Pull resource from authentication provider + Object resource = authProvider.getResource(); + if (resource != null) + return resource; + + } + + // AuthenticationProvider-specific resource could not be found + throw new GuacamoleResourceNotFoundException("No such resource."); + + } + +} diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/extension/package-info.java b/guacamole/src/main/java/org/apache/guacamole/rest/extension/package-info.java new file mode 100644 index 000000000..4e86a4cc2 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/extension/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Classes related to the arbitrary REST services exposed by extensions. + */ +package org.apache.guacamole.rest.extension; diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java index 29b443f16..b2e5eaade 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java @@ -29,6 +29,7 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.ConnectionGroup; @@ -253,4 +254,29 @@ public class UserContextResource { return new SchemaResource(userContext); } + /** + * Returns the arbitrary REST resource exposed by the UserContext exposed + * by this UserContextResource. + * + * @return + * The arbitrary REST resource exposed by the UserContext exposed by + * this UserContextresource. + * + * @throws GuacamoleException + * If no such resource could be found, or if an error occurs while + * retrieving that resource. + */ + @Path("ext") + public Object getExtensionResource() throws GuacamoleException { + + // Pull resource from user context + Object resource = userContext.getResource(); + if (resource != null) + return resource; + + // UserContext-specific resource could not be found + throw new GuacamoleResourceNotFoundException("No such resource."); + + } + }