mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-364: declare and implement new listener API
This commit also deprecates the existing listener API and includes support for adapting existing listener implementations to the new API.
This commit is contained in:
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An exception thrown when a successful authentication is rejected by a
|
||||
* AuthenticationSuccessListener in an extension.
|
||||
*/
|
||||
public class GuacamoleAuthenticationRejectedException
|
||||
extends GuacamoleSecurityException {
|
||||
|
||||
public GuacamoleAuthenticationRejectedException() {
|
||||
super("authentication rejected by listener extension");
|
||||
}
|
||||
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An exception thrown when a request to close a tunnel is vetoed by a
|
||||
* TunnelCloseListener in an extension.
|
||||
*/
|
||||
public class GuacamoleTunnelConnectedException extends GuacamoleClientException {
|
||||
|
||||
public GuacamoleTunnelConnectedException() {
|
||||
super("tunnel close vetoed by listener extension");
|
||||
}
|
||||
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An exception thrown when a successful tunnel connection is rejected by a
|
||||
* TunnelConnectListener in an extension.
|
||||
*/
|
||||
public class GuacamoleTunnelRejectedException extends GuacamoleClientException {
|
||||
|
||||
public GuacamoleTunnelRejectedException() {
|
||||
super("tunnel connection rejected by listener extension");
|
||||
}
|
||||
|
||||
}
|
@@ -26,6 +26,11 @@ import org.apache.guacamole.net.auth.UserContext;
|
||||
* An event which is triggered whenever a user's credentials pass
|
||||
* authentication. The credentials that passed authentication are included
|
||||
* within this event, and can be retrieved using getCredentials().
|
||||
* <p>
|
||||
* If a {@link org.apache.guacamole.net.event.listener.Listener} throws
|
||||
* a GuacamoleException when handling an event of this type, successful authentication
|
||||
* is effectively <em>vetoed</em> and will be subsequently processed as though the
|
||||
* authentication failed.
|
||||
*/
|
||||
public class AuthenticationSuccessEvent implements UserEvent, CredentialEvent {
|
||||
|
||||
|
@@ -28,6 +28,10 @@ import org.apache.guacamole.net.auth.UserContext;
|
||||
* being closed can be accessed through getTunnel(), and the UserContext
|
||||
* associated with the request which is closing the tunnel can be retrieved
|
||||
* with getUserContext().
|
||||
* <p>
|
||||
* If a {@link org.apache.guacamole.net.event.listener.Listener} throws
|
||||
* a GuacamoleException when handling an event of this type, the request to close
|
||||
* the tunnel is effectively <em>vetoed</em> and will remain connected.
|
||||
*/
|
||||
public class TunnelCloseEvent implements UserEvent, CredentialEvent, TunnelEvent {
|
||||
|
||||
|
@@ -28,6 +28,10 @@ import org.apache.guacamole.net.auth.UserContext;
|
||||
* being connected can be accessed through getTunnel(), and the UserContext
|
||||
* associated with the request which is connecting the tunnel can be retrieved
|
||||
* with getUserContext().
|
||||
* <p>
|
||||
* If a {@link org.apache.guacamole.net.event.listener.Listener} throws
|
||||
* a GuacamoleException when handling an event of this type, the tunnel connection
|
||||
* is effectively <em>vetoed</em> and will be subsequently closed.
|
||||
*/
|
||||
public class TunnelConnectEvent implements UserEvent, CredentialEvent, TunnelEvent {
|
||||
|
||||
|
@@ -26,8 +26,12 @@ import org.apache.guacamole.net.event.AuthenticationFailureEvent;
|
||||
* A listener whose authenticationFailed() hook will fire immediately
|
||||
* after a user's authentication attempt fails. Note that this hook cannot
|
||||
* be used to cancel the authentication failure.
|
||||
*
|
||||
* @deprecated
|
||||
* Listeners should instead implement the {@link Listener} interface
|
||||
*/
|
||||
public interface AuthenticationFailureListener extends Listener {
|
||||
@Deprecated
|
||||
public interface AuthenticationFailureListener {
|
||||
|
||||
/**
|
||||
* Event hook which fires immediately after a user's authentication attempt
|
||||
|
@@ -27,8 +27,12 @@ import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
|
||||
* authentication attempt succeeds. If a user successfully authenticates,
|
||||
* the authenticationSucceeded() hook has the opportunity to cancel the
|
||||
* authentication and force it to fail.
|
||||
*
|
||||
* @deprecated
|
||||
* Listeners should instead implement the {@link Listener} interface
|
||||
*/
|
||||
public interface AuthenticationSuccessListener extends Listener {
|
||||
@Deprecated
|
||||
public interface AuthenticationSuccessListener {
|
||||
|
||||
/**
|
||||
* Event hook which fires immediately after a user's authentication attempt
|
||||
|
@@ -19,10 +19,33 @@
|
||||
|
||||
package org.apache.guacamole.net.event.listener;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
|
||||
/**
|
||||
* A marker interface extended by all listener types. This interface is used
|
||||
* simply to validate that a listener class identified in an extension
|
||||
* actually implements some listener interface.
|
||||
* A listener for events that occur in handing various Guacamole requests
|
||||
* such as authentication, tunnel connect/close, etc. Listeners are registered
|
||||
* through the extension manifest mechanism. When an event occurs, listeners
|
||||
* are notified in the order in which they are declared in the manifest and
|
||||
* continues until either all listeners have been notified or with the first
|
||||
* listener that throws a GuacamoleException or other runtime exception.
|
||||
*/
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Notifies the recipient that an event has occurred.
|
||||
* <p>
|
||||
* Throwing an exception from an event listener can act to veto an action in
|
||||
* progress for some event types. See the Javadoc for specific event types for
|
||||
* details.
|
||||
*
|
||||
* @param event
|
||||
* an object that describes the subject event
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the listener wishes to stop notification of the event to subsequent
|
||||
* listeners. For some event types, this acts to veto an action in progress;
|
||||
* e.g. treating a successful authentication as though it failed
|
||||
*/
|
||||
void handleEvent(Object event) throws GuacamoleException;
|
||||
|
||||
}
|
||||
|
@@ -25,8 +25,12 @@ import org.apache.guacamole.net.event.TunnelCloseEvent;
|
||||
/**
|
||||
* A listener whose tunnelClosed() hook will fire immediately after an
|
||||
* existing tunnel is closed.
|
||||
*
|
||||
* @deprecated
|
||||
* Listeners should instead implement the {@link Listener} interface
|
||||
*/
|
||||
public interface TunnelCloseListener extends Listener {
|
||||
@Deprecated
|
||||
public interface TunnelCloseListener {
|
||||
|
||||
/**
|
||||
* Event hook which fires immediately before an existing tunnel is closed.
|
||||
|
@@ -25,8 +25,12 @@ import org.apache.guacamole.net.event.TunnelConnectEvent;
|
||||
/**
|
||||
* A listener whose tunnelConnected() hook will fire immediately after a new
|
||||
* tunnel is connected.
|
||||
*
|
||||
* @deprecated
|
||||
* Listeners should instead implement the {@link Listener} interface
|
||||
*/
|
||||
public interface TunnelConnectListener extends Listener {
|
||||
@Deprecated
|
||||
public interface TunnelConnectListener {
|
||||
|
||||
/**
|
||||
* Event hook which fires immediately after a new tunnel is connected.
|
||||
|
@@ -113,7 +113,7 @@ public class Extension {
|
||||
/**
|
||||
* The collection of all Listener classes defined within the extension.
|
||||
*/
|
||||
private final Collection<Class<Listener>> listenerClasses;
|
||||
private final Collection<Class<?>> listenerClasses;
|
||||
|
||||
/**
|
||||
* The resource for the small favicon for the extension. If provided, this
|
||||
@@ -328,15 +328,15 @@ public class Extension {
|
||||
* If any given class does not exist, or if any given class is not a
|
||||
* subclass of AuthenticationProvider.
|
||||
*/
|
||||
private Collection<Class<Listener>> getListenerClasses(Collection<String> names)
|
||||
private Collection<Class<?>> getListenerClasses(Collection<String> names)
|
||||
throws GuacamoleException {
|
||||
|
||||
// If no classnames are provided, just return an empty list
|
||||
if (names == null)
|
||||
return Collections.<Class<Listener>>emptyList();
|
||||
return Collections.<Class<?>>emptyList();
|
||||
|
||||
// Define all auth provider classes
|
||||
Collection<Class<Listener>> classes = new ArrayList<Class<Listener>>(names.size());
|
||||
Collection<Class<?>> classes = new ArrayList<Class<?>>(names.size());
|
||||
for (String name : names)
|
||||
classes.add(getListenerClass(name));
|
||||
|
||||
@@ -578,7 +578,7 @@ public class Extension {
|
||||
* @return
|
||||
* All declared listener classes with this extension.
|
||||
*/
|
||||
public Collection<Class<Listener>> getListenerClasses() {
|
||||
public Collection<Class<?>> getListenerClasses() {
|
||||
return listenerClasses;
|
||||
}
|
||||
|
||||
|
@@ -95,8 +95,8 @@ public class ExtensionModule extends ServletModule {
|
||||
/**
|
||||
* All currently-bound authentication providers, if any.
|
||||
*/
|
||||
private final List<ListenerProvider> boundListenerProviders =
|
||||
new ArrayList<ListenerProvider>();
|
||||
private final List<Listener> boundListners =
|
||||
new ArrayList<Listener>();
|
||||
|
||||
/**
|
||||
* Service for adding and retrieving language resources.
|
||||
@@ -195,19 +195,19 @@ public class ExtensionModule extends ServletModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given Listener class such that any service
|
||||
* requiring access to the Listener can obtain it via
|
||||
* injection, along with any other bound Listener.
|
||||
*
|
||||
* @param listenerClass
|
||||
* The Listener class to bind.
|
||||
* Binds the given provider class such that a listener is bound for each
|
||||
* listener interface implemented by the provider and such that all bound
|
||||
* listener instances can be obtained via injection.
|
||||
* *
|
||||
* @param providerClass
|
||||
* The listener provider class to bind
|
||||
*/
|
||||
private void bindListenerProvider(Class<? extends Listener> listenerClass) {
|
||||
private void bindListeners(Class<?> providerClass) {
|
||||
|
||||
logger.debug("[{}] Binding listeners \"{}\".",
|
||||
boundListners.size(), providerClass.getName());
|
||||
boundListners.addAll(ListenerFactory.createListeners(providerClass));
|
||||
|
||||
// Bind listener
|
||||
logger.debug("[{}] Binding Listener \"{}\".",
|
||||
boundListenerProviders.size(), listenerClass.getName());
|
||||
boundListenerProviders.add(new ListenerFacade(listenerClass));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,23 +218,23 @@ public class ExtensionModule extends ServletModule {
|
||||
* @param listeners
|
||||
* The Listener classes to bind.
|
||||
*/
|
||||
private void bindListenerProviders(Collection<Class<Listener>> listeners) {
|
||||
private void bindListeners(Collection<Class<?>> listeners) {
|
||||
|
||||
// Bind each listener within extension
|
||||
for (Class<Listener> listener : listeners)
|
||||
bindListenerProvider(listener);
|
||||
for (Class<?> listener : listeners)
|
||||
bindListeners(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all currently-bound ListenerProvider instances.
|
||||
* Returns a list of all currently-bound Listener instances.
|
||||
*
|
||||
* @return
|
||||
* A List of all currently-bound ListenerProvider instances. The List is
|
||||
* A List of all currently-bound Listener instances. The List is
|
||||
* not modifiable.
|
||||
*/
|
||||
@Provides
|
||||
public List<ListenerProvider> getListenerProviders() {
|
||||
return Collections.unmodifiableList(boundListenerProviders);
|
||||
public List<Listener> getListeners() {
|
||||
return Collections.unmodifiableList(boundListners);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,7 +378,7 @@ public class ExtensionModule extends ServletModule {
|
||||
bindAuthenticationProviders(extension.getAuthenticationProviderClasses());
|
||||
|
||||
// Attempt to load all listeners
|
||||
bindListenerProviders(extension.getListenerClasses());
|
||||
bindListeners(extension.getListenerClasses());
|
||||
|
||||
// Add any translation resources
|
||||
serveLanguageResources(extension.getTranslationResources());
|
||||
|
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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.extension;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.event.AuthenticationFailureEvent;
|
||||
import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
|
||||
import org.apache.guacamole.net.event.TunnelCloseEvent;
|
||||
import org.apache.guacamole.net.event.TunnelConnectEvent;
|
||||
import org.apache.guacamole.net.event.listener.*;
|
||||
|
||||
/**
|
||||
* Provides a wrapper around a Listener subclass, allowing listener
|
||||
* extensions to be bound without regard for which specific listener interfaces
|
||||
* are implemented.
|
||||
*/
|
||||
class ListenerFacade implements ListenerProvider {
|
||||
|
||||
private final Listener delegate;
|
||||
|
||||
/**
|
||||
* Creates a new ListenerFacade which delegates all listener methods
|
||||
* calls to an instance of the given Listener subclass. If
|
||||
* an instance of the given class cannot be created, creation of this
|
||||
* facade will still succeed. Errors will be logged at the time listener
|
||||
* creation fails, but subsequent events directed to the listener will be
|
||||
* silently dropped.
|
||||
*
|
||||
* @param listenerClass
|
||||
* The Listener subclass to instantiate.
|
||||
*/
|
||||
public ListenerFacade(Class<? extends Listener> listenerClass) {
|
||||
delegate = ProviderFactory.newInstance("listener", listenerClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the delegate listener of an authentication success event, if the
|
||||
* listener implements the AuthenticationSuccessListener interface.
|
||||
*
|
||||
* @param
|
||||
* event The AuthenticationSuccessEvent describing the authentication
|
||||
* success that just occurred.
|
||||
* @return
|
||||
* false if the delegate listener rejects the successful authentication,
|
||||
* else true
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if the delegate listener throws this exception
|
||||
*/
|
||||
@Override
|
||||
public boolean authenticationSucceeded(AuthenticationSuccessEvent event)
|
||||
throws GuacamoleException {
|
||||
return !(delegate instanceof AuthenticationSuccessListener)
|
||||
|| ((AuthenticationSuccessListener) delegate).authenticationSucceeded(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the delegate listener of an authentication failure event, if the
|
||||
* listener implements the AuthenticationSuccessListener interface.
|
||||
*
|
||||
* @param
|
||||
* event The AuthenticationFailureEvent describing the authentication
|
||||
* failure that just occurred.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if the delegate listener throws this exception
|
||||
*/
|
||||
@Override
|
||||
public void authenticationFailed(AuthenticationFailureEvent event)
|
||||
throws GuacamoleException {
|
||||
if (delegate instanceof AuthenticationFailureListener) {
|
||||
((AuthenticationFailureListener) delegate).authenticationFailed(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the delegate listener of a tunnel connected event, if the
|
||||
* listener implements the TunnelConnectListener interface.
|
||||
*
|
||||
* @param
|
||||
* event The TunnelConnectEvent describing the tunnel that was just connected
|
||||
|
||||
* @return
|
||||
* false if the delegate listener rejects the tunnel connection,
|
||||
* else true
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if the delegate listener throws this exception
|
||||
*/
|
||||
@Override
|
||||
public boolean tunnelConnected(TunnelConnectEvent event)
|
||||
throws GuacamoleException {
|
||||
return !(delegate instanceof TunnelConnectListener)
|
||||
|| ((TunnelConnectListener) delegate).tunnelConnected(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the delegate listener of a tunnel close event, if the
|
||||
* listener implements the TunnelCloseListener interface.
|
||||
*
|
||||
* @param
|
||||
* event The TunnelCloseEvent describing the tunnel that is to be close
|
||||
|
||||
* @return
|
||||
* false if the delegate listener rejects the tunnel close request,
|
||||
* else true
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if the delegate listener throws this exception
|
||||
*/
|
||||
@Override
|
||||
public boolean tunnelClosed(TunnelCloseEvent event) throws GuacamoleException {
|
||||
return !(delegate instanceof TunnelCloseListener)
|
||||
|| ((TunnelCloseListener) delegate).tunnelClosed(event);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.extension;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.net.event.AuthenticationFailureEvent;
|
||||
import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
|
||||
import org.apache.guacamole.net.event.TunnelCloseEvent;
|
||||
import org.apache.guacamole.net.event.TunnelConnectEvent;
|
||||
import org.apache.guacamole.net.event.listener.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A factory that reflectively instantiates Listener objects for a given
|
||||
* provider class.
|
||||
*/
|
||||
class ListenerFactory {
|
||||
|
||||
/**
|
||||
* Creates all listeners represented by an instance of the given provider class.
|
||||
* <p>
|
||||
* If a provider class implements the simple Listener interface, that is the
|
||||
* only listener type that will be returned. Otherwise, a list of Listener
|
||||
* objects that adapt the legacy listener interfaces will be returned.
|
||||
*
|
||||
* @param providerClass
|
||||
* a class that represents a listener provider
|
||||
*
|
||||
* @return
|
||||
* list of listeners represented by the given provider class
|
||||
*/
|
||||
static List<Listener> createListeners(Class<?> providerClass) {
|
||||
|
||||
Object provider = ProviderFactory.newInstance("listener", providerClass);
|
||||
|
||||
if (provider instanceof Listener) {
|
||||
return Collections.singletonList((Listener) provider);
|
||||
}
|
||||
|
||||
return createListenerAdapters(provider);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static List<Listener> createListenerAdapters(Object provider) {
|
||||
|
||||
final List<Listener> listeners = new ArrayList<Listener>();
|
||||
|
||||
if (provider instanceof AuthenticationSuccessListener) {
|
||||
listeners.add(new AuthenticationSuccessListenerAdapter(
|
||||
(AuthenticationSuccessListener) provider));
|
||||
}
|
||||
|
||||
if (provider instanceof AuthenticationFailureListener) {
|
||||
listeners.add(new AuthenticationFailureListenerAdapter(
|
||||
(AuthenticationFailureListener) provider));
|
||||
}
|
||||
|
||||
if (provider instanceof TunnelConnectListener) {
|
||||
listeners.add(new TunnelConnectListenerAdapter(
|
||||
(TunnelConnectListener) provider));
|
||||
}
|
||||
|
||||
if (provider instanceof TunnelCloseListener) {
|
||||
listeners.add(new TunnelCloseListenerAdapter(
|
||||
(TunnelCloseListener) provider));
|
||||
}
|
||||
|
||||
return listeners;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An adapter the allows an AuthenticationSuccessListener to be used
|
||||
* as an ordinary Listener.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class AuthenticationSuccessListenerAdapter implements Listener {
|
||||
|
||||
private final AuthenticationSuccessListener delegate;
|
||||
|
||||
/**
|
||||
* Constructs a new adapter.
|
||||
*
|
||||
* @param delegate
|
||||
* the delegate listener
|
||||
*/
|
||||
AuthenticationSuccessListenerAdapter(AuthenticationSuccessListener delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an AuthenticationSuccessEvent by passing the event to the delegate
|
||||
* listener. If the delegate returns false, the adapter throws a GuacamoleException
|
||||
* to veto the authentication success event. All other event types are ignored.
|
||||
*
|
||||
* @param event
|
||||
* an object that describes the subject event
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if thrown by the delegate listener
|
||||
*/
|
||||
@Override
|
||||
public void handleEvent(Object event) throws GuacamoleException {
|
||||
if (event instanceof AuthenticationSuccessEvent) {
|
||||
if (!delegate.authenticationSucceeded((AuthenticationSuccessEvent) event)) {
|
||||
throw new GuacamoleSecurityException(
|
||||
"listener vetoed successful authentication");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An adapter the allows an AuthenticationFailureListener to be used
|
||||
* as an ordinary Listener.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class AuthenticationFailureListenerAdapter implements Listener {
|
||||
|
||||
private final AuthenticationFailureListener delegate;
|
||||
|
||||
/**
|
||||
* Constructs a new adapter.
|
||||
*
|
||||
* @param delegate
|
||||
* the delegate listener
|
||||
*/
|
||||
AuthenticationFailureListenerAdapter(AuthenticationFailureListener delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an AuthenticationFailureEvent by passing the event to the delegate
|
||||
* listener. All other event types are ignored.
|
||||
*
|
||||
* @param event
|
||||
* an object that describes the subject event
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if thrown by the delegate listener
|
||||
*/
|
||||
@Override
|
||||
public void handleEvent(Object event) throws GuacamoleException {
|
||||
if (event instanceof AuthenticationFailureEvent) {
|
||||
delegate.authenticationFailed((AuthenticationFailureEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An adapter the allows a TunnelConnectListener to be used as an ordinary
|
||||
* Listener.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class TunnelConnectListenerAdapter implements Listener {
|
||||
|
||||
private final TunnelConnectListener delegate;
|
||||
|
||||
/**
|
||||
* Constructs a new adapter.
|
||||
*
|
||||
* @param delegate
|
||||
* the delegate listener
|
||||
*/
|
||||
TunnelConnectListenerAdapter(TunnelConnectListener delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a TunnelConnectEvent by passing the event to the delegate listener.
|
||||
* If the delegate returns false, the adapter throws a GuacamoleException
|
||||
* to veto the tunnel connect event. All other event types are ignored.
|
||||
*
|
||||
* @param event
|
||||
* an object that describes the subject event
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if thrown by the delegate listener
|
||||
*/
|
||||
@Override
|
||||
public void handleEvent(Object event) throws GuacamoleException {
|
||||
if (event instanceof TunnelConnectEvent) {
|
||||
if (!delegate.tunnelConnected((TunnelConnectEvent) event)) {
|
||||
throw new GuacamoleException("listener vetoed tunnel connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An adapter the allows a TunnelCloseListener to be used as an ordinary
|
||||
* Listener.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class TunnelCloseListenerAdapter implements Listener {
|
||||
|
||||
private final TunnelCloseListener delegate;
|
||||
|
||||
/**
|
||||
* Constructs a new adapter.
|
||||
*
|
||||
* @param delegate
|
||||
* the delegate listener
|
||||
*/
|
||||
TunnelCloseListenerAdapter(TunnelCloseListener delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a TunnelCloseEvent by passing the event to the delegate listener.
|
||||
* If the delegate returns false, the adapter throws a GuacamoleException
|
||||
* to veto the tunnel connect event. All other event types are ignored.
|
||||
*
|
||||
* @param event
|
||||
* an object that describes the subject event
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* if thrown by the delegate listener
|
||||
*/
|
||||
@Override
|
||||
public void handleEvent(Object event) throws GuacamoleException {
|
||||
if (event instanceof TunnelCloseEvent) {
|
||||
if (!delegate.tunnelClosed((TunnelCloseEvent) event)) {
|
||||
throw new GuacamoleException("listener vetoed tunnel close request");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -24,7 +24,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.guacamole.GuacamoleAuthenticationRejectedException;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.GuacamoleUnauthorizedException;
|
||||
@@ -218,19 +218,17 @@ public class AuthenticationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all bound AuthenticationSuccessListeners that a successful authentication
|
||||
* has occurred. If any of the bound listeners returns false (indicating that the
|
||||
* authentication should be rejected) a GuacamoleRejectedAuthenticationException is
|
||||
* thrown.
|
||||
* Notify all bound listeners that a successful authentication
|
||||
* has occurred.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The user that was successfully authenticated
|
||||
* @param session
|
||||
* Existing session for the user (if any)
|
||||
* @throws GuacamoleException
|
||||
* If a filter throws an exception or if any filter rejects the authentication
|
||||
* If thrown by a listener
|
||||
*/
|
||||
private void notifyAuthenticationSuccessListeners(
|
||||
private void fireAuthenticationSuccessEvent(
|
||||
AuthenticatedUser authenticatedUser, GuacamoleSession session)
|
||||
throws GuacamoleException {
|
||||
|
||||
@@ -240,26 +238,21 @@ public class AuthenticationService {
|
||||
authenticatedUser.getAuthenticationProvider().getIdentifier());
|
||||
}
|
||||
|
||||
AuthenticationSuccessEvent event = new AuthenticationSuccessEvent(
|
||||
userContext, authenticatedUser.getCredentials());
|
||||
|
||||
if (!listenerService.authenticationSucceeded(event)) {
|
||||
throw new GuacamoleAuthenticationRejectedException();
|
||||
}
|
||||
listenerService.handleEvent(new AuthenticationSuccessEvent(
|
||||
userContext, authenticatedUser.getCredentials()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all bound AuthenticationFailureListeners that an authentication has failed.
|
||||
* Notify all bound listeners that an authentication attempt has failed.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials that failed to authenticate
|
||||
* @throws GuacamoleException
|
||||
* If a filter throws an exception
|
||||
* If thrown by a listener
|
||||
*/
|
||||
private void notifyAuthenticationFailureListeners(Credentials credentials)
|
||||
private void fireAuthenticationFailedEvent(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
listenerService.authenticationFailed(new AuthenticationFailureEvent(credentials));
|
||||
listenerService.handleEvent(new AuthenticationFailureEvent(credentials));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,13 +283,13 @@ public class AuthenticationService {
|
||||
if (existingSession != null) {
|
||||
AuthenticatedUser updatedUser = updateAuthenticatedUser(
|
||||
existingSession.getAuthenticatedUser(), credentials);
|
||||
notifyAuthenticationSuccessListeners(updatedUser, existingSession);
|
||||
fireAuthenticationSuccessEvent(updatedUser, existingSession);
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
// Otherwise, attempt authentication as a new user
|
||||
AuthenticatedUser authenticatedUser = AuthenticationService.this.authenticateUser(credentials);
|
||||
notifyAuthenticationSuccessListeners(authenticatedUser, null);
|
||||
fireAuthenticationSuccessEvent(authenticatedUser, null);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("User \"{}\" successfully authenticated from {}.",
|
||||
@@ -310,7 +303,7 @@ public class AuthenticationService {
|
||||
// Log and rethrow any authentication errors
|
||||
catch (GuacamoleException e) {
|
||||
|
||||
notifyAuthenticationFailureListeners(credentials);
|
||||
fireAuthenticationFailedEvent(credentials);
|
||||
|
||||
// Get request and username for sake of logging
|
||||
HttpServletRequest request = credentials.getRequest();
|
||||
|
@@ -22,118 +22,32 @@ package org.apache.guacamole.rest.event;
|
||||
import java.util.List;
|
||||
import com.google.inject.Inject;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.extension.ListenerProvider;
|
||||
import org.apache.guacamole.net.event.AuthenticationFailureEvent;
|
||||
import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
|
||||
import org.apache.guacamole.net.event.TunnelConnectEvent;
|
||||
import org.apache.guacamole.net.event.TunnelCloseEvent;
|
||||
import org.apache.guacamole.net.event.listener.AuthenticationFailureListener;
|
||||
import org.apache.guacamole.net.event.listener.AuthenticationSuccessListener;
|
||||
import org.apache.guacamole.net.event.listener.TunnelCloseListener;
|
||||
import org.apache.guacamole.net.event.listener.TunnelConnectListener;
|
||||
import org.apache.guacamole.net.event.listener.Listener;
|
||||
|
||||
/**
|
||||
* A service used to notify listeners registered by extensions when events of
|
||||
* interest occur.
|
||||
*/
|
||||
public class ListenerService implements ListenerProvider {
|
||||
public class ListenerService implements Listener {
|
||||
|
||||
@Inject
|
||||
private List<ListenerProvider> listeners;
|
||||
private List<Listener> listeners;
|
||||
|
||||
/**
|
||||
* Notifies all bound listeners of an authentication success event. Listeners
|
||||
* are allowed to veto a successful authentication by returning false from the
|
||||
* listener method. Regardless of whether a particular listener rejects the
|
||||
* successful authentication, all listeners are notified.
|
||||
* Notifies registered listeners than an event has occurred. Notification continues
|
||||
* until a given listener throws a GuacamoleException or other runtime exception, or
|
||||
* until all listeners have been notified.
|
||||
*
|
||||
* @param event
|
||||
* The AuthenticationSuccessEvent describing the successful authentication
|
||||
* that just occurred.
|
||||
* an object that describes the subject event
|
||||
*
|
||||
* @return
|
||||
* false if any bound listener returns false, else true
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If any bound listener throws this exception. If a listener throws an exception
|
||||
* some listeners may not receive the authentication success event notification.
|
||||
* @throws GuacamoleException if a registered listener throws a GuacamoleException
|
||||
*/
|
||||
@Override
|
||||
public boolean authenticationSucceeded(AuthenticationSuccessEvent event)
|
||||
throws GuacamoleException {
|
||||
boolean result = true;
|
||||
for (AuthenticationSuccessListener listener : listeners) {
|
||||
result = result && listener.authenticationSucceeded(event);
|
||||
public void handleEvent(Object event) throws GuacamoleException {
|
||||
for (final Listener listener : listeners) {
|
||||
listener.handleEvent(event);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all bound listeners of an authentication failure event.
|
||||
*
|
||||
* @param event
|
||||
* The AuthenticationSuccessEvent describing the authentication failure
|
||||
* that just occurred.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If any bound listener throws this exception. If a listener throws an exception
|
||||
* some listeners may not receive the authentication failure event notification.
|
||||
*/
|
||||
@Override
|
||||
public void authenticationFailed(AuthenticationFailureEvent event)
|
||||
throws GuacamoleException {
|
||||
for (AuthenticationFailureListener listener : listeners) {
|
||||
listener.authenticationFailed(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all bound listeners of an tunnel connected event. Listeners
|
||||
* are allowed to veto a tunnel connection by returning false from the
|
||||
* listener method. Regardless of whether a particular listener rejects the
|
||||
* tunnel connection, all listeners are notified.
|
||||
* @param event
|
||||
* The TunnelConnectedEvent describing the tunnel that was just connected
|
||||
*
|
||||
* @return
|
||||
* false if any bound listener returns false, else true
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If any bound listener throws this exception. If a listener throws an exception
|
||||
* some listeners may not receive the tunnel connected event notification.
|
||||
*/
|
||||
@Override
|
||||
public boolean tunnelConnected(TunnelConnectEvent event)
|
||||
throws GuacamoleException {
|
||||
boolean result = true;
|
||||
for (TunnelConnectListener listener : listeners) {
|
||||
result = result && listener.tunnelConnected(event);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all bound listeners of an tunnel close event. Listeners
|
||||
* are allowed to veto the request to close a tunnel by returning false from
|
||||
* the listener method. Regardless of whether a particular listener rejects the
|
||||
* tunnel close request, all listeners are notified.
|
||||
* @param event
|
||||
* The TunnelCloseEvent describing the tunnel that is to be closed
|
||||
*
|
||||
* @return
|
||||
* false if any bound listener returns false, else true
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If any bound listener throws this exception. If a listener throws an exception
|
||||
* some listeners may not receive the tunnel close event notification.
|
||||
*/
|
||||
@Override
|
||||
public boolean tunnelClosed(TunnelCloseEvent event) throws GuacamoleException {
|
||||
boolean result = true;
|
||||
for (TunnelCloseListener listener : listeners) {
|
||||
result = result && listener.tunnelClosed(event);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,8 +25,6 @@ import java.util.List;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.GuacamoleSession;
|
||||
import org.apache.guacamole.GuacamoleTunnelConnectedException;
|
||||
import org.apache.guacamole.GuacamoleTunnelRejectedException;
|
||||
import org.apache.guacamole.GuacamoleUnauthorizedException;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.Connection;
|
||||
@@ -70,10 +68,8 @@ public class TunnelRequestService {
|
||||
private ListenerService listenerService;
|
||||
|
||||
/**
|
||||
* Notifies bound TunnelConnectListeners that a new tunnel has been connected.
|
||||
* Listeners are allowed to veto a connected tunnel by returning false from the
|
||||
* listener method. If the ListenerService indicates that any listener rejected
|
||||
* the tunnel, the tunnel is closed an GuacamoleTunnelRejectedException is thrown.
|
||||
* Notifies bound listeners that a new tunnel has been connected.
|
||||
* Listeners may veto a connected tunnel by throwing any GuacamoleException.
|
||||
*
|
||||
* @param userContext
|
||||
* The UserContext associated with the user for whom the tunnel is
|
||||
@@ -88,25 +84,15 @@ public class TunnelRequestService {
|
||||
* @throws GuacamoleException
|
||||
* If thrown by a listener or if any listener vetoes the connected tunnel
|
||||
*/
|
||||
private void notifyTunnelConnectListeners(UserContext userContext,
|
||||
private void fireTunnelConnectEvent(UserContext userContext,
|
||||
Credentials credentials, GuacamoleTunnel tunnel) throws GuacamoleException {
|
||||
TunnelConnectEvent event = new TunnelConnectEvent(userContext, credentials, tunnel);
|
||||
if (!listenerService.tunnelConnected(event)) {
|
||||
try {
|
||||
tunnel.close();
|
||||
}
|
||||
catch (GuacamoleException closeEx) {
|
||||
logger.warn("Error closing rejected tunnel connection: {}", closeEx.getMessage());
|
||||
}
|
||||
throw new GuacamoleTunnelRejectedException();
|
||||
}
|
||||
listenerService.handleEvent(new TunnelConnectEvent(userContext, credentials, tunnel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies bound TunnelCloseListeners that a tunnel is to be closed.
|
||||
* Listeners are allowed to veto a request to close a tunnel by returning false from
|
||||
* the listener method. If the ListenerService indicates that any listener vetoed the
|
||||
* request to the close the tunnel, a GuacamoleTunnelConnectedException is thrown.
|
||||
* Notifies bound listeners that a tunnel is to be closed.
|
||||
* Listeners are allowed to veto a request to close a tunnel by throwing any
|
||||
* GuacamoleException.
|
||||
*
|
||||
* @param userContext
|
||||
* The UserContext associated with the user for whom the tunnel is
|
||||
@@ -119,15 +105,12 @@ public class TunnelRequestService {
|
||||
* The tunnel that was connected
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If thrown by a listener or if any listener vetoes the request to close the tunnel
|
||||
* If thrown by a listener.
|
||||
*/
|
||||
private void notifyTunnelCloseListeners(UserContext userContext,
|
||||
private void fireTunnelClosedEvent(UserContext userContext,
|
||||
Credentials credentials, GuacamoleTunnel tunnel)
|
||||
throws GuacamoleException {
|
||||
TunnelCloseEvent event = new TunnelCloseEvent(userContext, credentials, tunnel);
|
||||
if (listenerService.tunnelClosed(event)) {
|
||||
throw new GuacamoleTunnelConnectedException();
|
||||
}
|
||||
listenerService.handleEvent(new TunnelCloseEvent(userContext, credentials, tunnel));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,7 +300,7 @@ public class TunnelRequestService {
|
||||
public void close() throws GuacamoleException {
|
||||
|
||||
// notify listeners to allow close request to be vetoed
|
||||
notifyTunnelCloseListeners(context,
|
||||
fireTunnelClosedEvent(context,
|
||||
session.getAuthenticatedUser().getCredentials(), tunnel);
|
||||
|
||||
long connectionEndTime = System.currentTimeMillis();
|
||||
@@ -406,7 +389,7 @@ public class TunnelRequestService {
|
||||
GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
|
||||
|
||||
// Notify listeners to allow connection to be vetoed
|
||||
notifyTunnelConnectListeners(userContext,
|
||||
fireTunnelConnectEvent(userContext,
|
||||
session.getAuthenticatedUser().getCredentials(), tunnel);
|
||||
|
||||
// Associate tunnel with session
|
||||
|
Reference in New Issue
Block a user