mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
GUACAMOLE-1224: Add a default, global event listener providing logging.
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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.event;
|
||||||
|
|
||||||
|
import org.apache.guacamole.net.auth.Nameable;
|
||||||
|
import org.apache.guacamole.net.event.DirectoryEvent;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loggable representation of the object affected by an operation.
|
||||||
|
*/
|
||||||
|
public class AffectedObject implements LoggableDetail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for this class.
|
||||||
|
*/
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AffectedObject.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event representing the requested operation.
|
||||||
|
*/
|
||||||
|
private final DirectoryEvent<?> event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new AffectedObject representing the object affected by the
|
||||||
|
* operation described by the given event.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The event representing the operation.
|
||||||
|
*/
|
||||||
|
public AffectedObject(DirectoryEvent<?> event) {
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
Object object = event.getObject();
|
||||||
|
String identifier = event.getObjectIdentifier();
|
||||||
|
|
||||||
|
String objectType;
|
||||||
|
String name = null; // Not all objects have names
|
||||||
|
|
||||||
|
// Obtain name of object (if applicable and available)
|
||||||
|
if (object instanceof Nameable) {
|
||||||
|
try {
|
||||||
|
name = ((Nameable) object).getName();
|
||||||
|
}
|
||||||
|
catch (RuntimeException | Error e) {
|
||||||
|
logger.debug("Name of object \"{}\" could not be retrieved.", identifier, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine type of object
|
||||||
|
switch (event.getDirectoryType()) {
|
||||||
|
|
||||||
|
// Active connections
|
||||||
|
case ACTIVE_CONNECTION:
|
||||||
|
objectType = "active connection";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
case CONNECTION:
|
||||||
|
objectType = "connection";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Connection groups
|
||||||
|
case CONNECTION_GROUP:
|
||||||
|
objectType = "connection group";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Sharing profiles
|
||||||
|
case SHARING_PROFILE:
|
||||||
|
objectType = "sharing profile";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Users
|
||||||
|
case USER:
|
||||||
|
objectType = "user";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// User groups
|
||||||
|
case USER_GROUP:
|
||||||
|
objectType = "user group";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown
|
||||||
|
default:
|
||||||
|
objectType = (object != null) ? object.getClass().toString() : "an unknown object";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe at least the type of the object and its identifier,
|
||||||
|
// including the name of the object, as well, if available
|
||||||
|
if (identifier != null) {
|
||||||
|
if (name != null)
|
||||||
|
return objectType + " \"" + identifier + "\" (currently named \"" + name + "\")";
|
||||||
|
else
|
||||||
|
return objectType + " \"" + identifier + "\"";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return objectType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* 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.event;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.GuacamoleResourceNotFoundException;
|
||||||
|
import org.apache.guacamole.net.event.DirectoryEvent;
|
||||||
|
import org.apache.guacamole.net.event.DirectoryFailureEvent;
|
||||||
|
import org.apache.guacamole.net.event.DirectorySuccessEvent;
|
||||||
|
import org.apache.guacamole.net.event.listener.Listener;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that records each event that occurs in the logs, such as changes
|
||||||
|
* made to objects via the REST API.
|
||||||
|
*/
|
||||||
|
public class EventLoggingListener implements Listener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for this class.
|
||||||
|
*/
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(EventLoggingListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs that an operation was performed on an object within a Directory
|
||||||
|
* successfully.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The event describing the operation successfully performed on the
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
private void logSuccess(DirectorySuccessEvent<?> event) {
|
||||||
|
DirectoryEvent.Operation op = event.getOperation();
|
||||||
|
switch (op) {
|
||||||
|
|
||||||
|
case GET:
|
||||||
|
logger.debug("{} successfully accessed/retrieved {}", new RequestingUser(event), new AffectedObject(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADD:
|
||||||
|
logger.info("{} successfully created {}", new RequestingUser(event), new AffectedObject(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPDATE:
|
||||||
|
logger.info("{} successfully updated {}", new RequestingUser(event), new AffectedObject(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMOVE:
|
||||||
|
logger.info("{} successfully deleted {}", new RequestingUser(event), new AffectedObject(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.warn("DirectoryEvent operation type has no corresponding log message implemented: {}", op);
|
||||||
|
logger.info("{} successfully performed an unknown action on {} {}", new RequestingUser(event), new AffectedObject(event));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs that an operation failed to be performed on an object within a
|
||||||
|
* Directory.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The event describing the operation that failed.
|
||||||
|
*/
|
||||||
|
private void logFailure(DirectoryFailureEvent<?> event) {
|
||||||
|
DirectoryEvent.Operation op = event.getOperation();
|
||||||
|
switch (op) {
|
||||||
|
|
||||||
|
case GET:
|
||||||
|
if (event.getFailure() instanceof GuacamoleResourceNotFoundException)
|
||||||
|
logger.debug("{} failed to access/retrieve {}: {}", new RequestingUser(event), new AffectedObject(event), new Failure(event));
|
||||||
|
else
|
||||||
|
logger.info("{} failed to access/retrieve {}: {}", new RequestingUser(event), new AffectedObject(event), new Failure(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADD:
|
||||||
|
logger.info("{} failed to create {}: {}", new RequestingUser(event), new AffectedObject(event), new Failure(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPDATE:
|
||||||
|
logger.info("{} failed to update {}: {}", new RequestingUser(event), new AffectedObject(event), new Failure(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMOVE:
|
||||||
|
logger.info("{} failed to delete {}: {}", new RequestingUser(event), new AffectedObject(event), new Failure(event));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.warn("DirectoryEvent operation type has no corresponding log message implemented: {}", op);
|
||||||
|
logger.info("{} failed to perform an unknown action on {}: {}", new RequestingUser(event), new AffectedObject(event), new Failure(event));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleEvent(@Nonnull Object event) throws GuacamoleException {
|
||||||
|
|
||||||
|
if (event instanceof DirectorySuccessEvent)
|
||||||
|
logSuccess((DirectorySuccessEvent<?>) event);
|
||||||
|
|
||||||
|
else if (event instanceof DirectoryFailureEvent)
|
||||||
|
logFailure((DirectoryFailureEvent<?>) event);
|
||||||
|
|
||||||
|
else
|
||||||
|
logger.debug("Ignoring unknown/unimplemented event type: {}",
|
||||||
|
event.getClass());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.event;
|
||||||
|
|
||||||
|
import org.apache.guacamole.net.event.FailureEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loggable representation of a failure that occurred.
|
||||||
|
*/
|
||||||
|
public class Failure implements LoggableDetail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event representing the failure.
|
||||||
|
*/
|
||||||
|
private final FailureEvent event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Failure representing the failure described by the given
|
||||||
|
* event.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The event representing the failure.
|
||||||
|
*/
|
||||||
|
public Failure(FailureEvent event) {
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
Throwable failure = event.getFailure();
|
||||||
|
if (failure == null)
|
||||||
|
return "unknown error (no specific failure recorded)";
|
||||||
|
|
||||||
|
return failure.getMessage();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a {@link #toString()} implementation that returns a human-readable
|
||||||
|
* string that is intended to be logged and which describes a particular detail
|
||||||
|
* of an event.
|
||||||
|
*/
|
||||||
|
public interface LoggableDetail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>
|
||||||
|
* A LoggableDetail implementation of toString() is required to return a
|
||||||
|
* string that is human-readable, describes a detail of a provided event,
|
||||||
|
* and that is intended to be logged.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
String toString();
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.event;
|
||||||
|
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
|
import org.apache.guacamole.net.event.DirectoryEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loggable representation of the user that requested an operation.
|
||||||
|
*/
|
||||||
|
public class RequestingUser implements LoggableDetail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event representing the requested operation.
|
||||||
|
*/
|
||||||
|
private final DirectoryEvent<?> event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new RequestingUser that represents the user that requested the
|
||||||
|
* operation described by the given event.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The event representing the requested operation.
|
||||||
|
*/
|
||||||
|
public RequestingUser(DirectoryEvent<?> event) {
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
|
||||||
|
AuthenticatedUser user = event.getAuthenticatedUser();
|
||||||
|
String identifier = user.getIdentifier();
|
||||||
|
|
||||||
|
if (AuthenticatedUser.ANONYMOUS_IDENTIFIER.equals(identifier))
|
||||||
|
return "Anonymous user (authenticated by \"" + user.getAuthenticationProvider().getIdentifier() + "\")";
|
||||||
|
|
||||||
|
return "User \"" + identifier + "\" (authenticated by \"" + user.getAuthenticationProvider().getIdentifier() + "\")";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -35,6 +35,7 @@ import org.apache.guacamole.auth.file.FileAuthenticationProvider;
|
|||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
import org.apache.guacamole.GuacamoleServerException;
|
||||||
import org.apache.guacamole.environment.Environment;
|
import org.apache.guacamole.environment.Environment;
|
||||||
|
import org.apache.guacamole.event.EventLoggingListener;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.apache.guacamole.net.event.listener.Listener;
|
import org.apache.guacamole.net.event.listener.Listener;
|
||||||
import org.apache.guacamole.properties.StringSetProperty;
|
import org.apache.guacamole.properties.StringSetProperty;
|
||||||
@@ -628,8 +629,9 @@ public class ExtensionModule extends ServletModule {
|
|||||||
final Set<String> toleratedAuthProviders = getToleratedAuthenticationProviders();
|
final Set<String> toleratedAuthProviders = getToleratedAuthenticationProviders();
|
||||||
loadExtensions(javaScriptResources, cssResources, toleratedAuthProviders);
|
loadExtensions(javaScriptResources, cssResources, toleratedAuthProviders);
|
||||||
|
|
||||||
// Always bind default file-driven auth last
|
// Always bind default file-driven auth and event logging last
|
||||||
bindAuthenticationProvider(FileAuthenticationProvider.class, toleratedAuthProviders);
|
bindAuthenticationProvider(FileAuthenticationProvider.class, toleratedAuthProviders);
|
||||||
|
bindListener(EventLoggingListener.class);
|
||||||
|
|
||||||
// Dynamically generate app.js and app.css from extensions
|
// Dynamically generate app.js and app.css from extensions
|
||||||
serve("/app.js").with(new ResourceServlet(new SequenceResource(javaScriptResources)));
|
serve("/app.js").with(new ResourceServlet(new SequenceResource(javaScriptResources)));
|
||||||
|
Reference in New Issue
Block a user