GUACAMOLE-289: Add getResource() functions to UserContext and AuthenticationProvider, allowing extensions to expose arbitrary REST resources/services.

This commit is contained in:
Michael Jumper
2017-04-29 12:34:32 -07:00
parent 0c2bcdbd81
commit 4455cbc781
16 changed files with 254 additions and 0 deletions

View File

@@ -62,6 +62,11 @@ public class DuoAuthenticationProvider implements AuthenticationProvider {
return "duo"; return "duo";
} }
@Override
public Object getResource() {
return null;
}
@Override @Override
public AuthenticatedUser authenticateUser(Credentials credentials) public AuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException { throws GuacamoleException {

View File

@@ -63,6 +63,11 @@ public class HTTPHeaderAuthenticationProvider implements AuthenticationProvider
return "header"; return "header";
} }
@Override
public Object getResource() {
return null;
}
@Override @Override
public AuthenticatedUser authenticateUser(Credentials credentials) public AuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException { throws GuacamoleException {

View File

@@ -70,6 +70,11 @@ public abstract class InjectedAuthenticationProvider implements AuthenticationPr
} }
@Override
public Object getResource() throws GuacamoleException {
return null;
}
@Override @Override
public AuthenticatedUser authenticateUser(Credentials credentials) public AuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException { throws GuacamoleException {

View File

@@ -136,6 +136,11 @@ public class SharedUserContext implements UserContext {
return self; return self;
} }
@Override
public Object getResource() throws GuacamoleException {
return null;
}
@Override @Override
public AuthenticationProvider getAuthenticationProvider() { public AuthenticationProvider getAuthenticationProvider() {
return authProvider; return authProvider;

View File

@@ -116,6 +116,11 @@ public class ModeledUserContext extends RestrictedObject
return getCurrentUser().getUser(); return getCurrentUser().getUser();
} }
@Override
public Object getResource() throws GuacamoleException {
return null;
}
@Override @Override
public AuthenticationProvider getAuthenticationProvider() { public AuthenticationProvider getAuthenticationProvider() {
return getCurrentUser().getModelAuthenticationProvider(); return getCurrentUser().getModelAuthenticationProvider();

View File

@@ -68,6 +68,11 @@ public class LDAPAuthenticationProvider implements AuthenticationProvider {
return "ldap"; return "ldap";
} }
@Override
public String getResource() {
return null;
}
@Override @Override
public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException {

View File

@@ -159,6 +159,11 @@ public class UserContext implements org.apache.guacamole.net.auth.UserContext {
return self; return self;
} }
@Override
public String getResource() {
return null;
}
@Override @Override
public AuthenticationProvider getAuthenticationProvider() { public AuthenticationProvider getAuthenticationProvider() {
return authProvider; return authProvider;

View File

@@ -40,6 +40,26 @@ public interface AuthenticationProvider {
*/ */
String getIdentifier(); 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 * Returns an AuthenticatedUser representing the user authenticated by the
* given credentials, if any. * given credentials, if any.

View File

@@ -38,6 +38,26 @@ public interface UserContext {
*/ */
User self(); 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 * Returns the AuthenticationProvider which created this UserContext, which
* may not be the same AuthenticationProvider that authenticated the user * may not be the same AuthenticationProvider that authenticated the user

View File

@@ -203,6 +203,11 @@ public abstract class SimpleAuthenticationProvider
} }
@Override
public Object getResource() throws GuacamoleException {
return null;
}
@Override @Override
public AuthenticatedUser authenticateUser(final Credentials credentials) public AuthenticatedUser authenticateUser(final Credentials credentials)
throws GuacamoleException { throws GuacamoleException {

View File

@@ -163,6 +163,11 @@ public class SimpleUserContext implements UserContext {
return self; return self;
} }
@Override
public Object getResource() throws GuacamoleException {
return null;
}
@Override @Override
public AuthenticationProvider getAuthenticationProvider() { public AuthenticationProvider getAuthenticationProvider() {
return authProvider; return authProvider;

View File

@@ -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 @Override
public AuthenticatedUser authenticateUser(Credentials credentials) public AuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException { throws GuacamoleException {

View File

@@ -36,6 +36,7 @@ import org.apache.guacamole.rest.auth.SecureRandomAuthTokenGenerator;
import org.apache.guacamole.rest.auth.TokenSessionMap; import org.apache.guacamole.rest.auth.TokenSessionMap;
import org.apache.guacamole.rest.connection.ConnectionModule; import org.apache.guacamole.rest.connection.ConnectionModule;
import org.apache.guacamole.rest.connectiongroup.ConnectionGroupModule; 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.language.LanguageRESTService;
import org.apache.guacamole.rest.patch.PatchRESTService; import org.apache.guacamole.rest.patch.PatchRESTService;
import org.apache.guacamole.rest.session.SessionResourceFactory; import org.apache.guacamole.rest.session.SessionResourceFactory;
@@ -84,6 +85,7 @@ public class RESTServiceModule extends ServletModule {
bindInterceptor(Matchers.any(), new RESTMethodMatcher(), interceptor); bindInterceptor(Matchers.any(), new RESTMethodMatcher(), interceptor);
// Set up the API endpoints // Set up the API endpoints
bind(ExtensionRESTService.class);
bind(LanguageRESTService.class); bind(LanguageRESTService.class);
bind(PatchRESTService.class); bind(PatchRESTService.class);
bind(TokenRESTService.class); bind(TokenRESTService.class);

View File

@@ -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<AuthenticationProvider> 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.");
}
}

View File

@@ -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;

View File

@@ -29,6 +29,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
@@ -253,4 +254,29 @@ public class UserContextResource {
return new SchemaResource(userContext); 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.");
}
} }