mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +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.GuacamoleServerException;
|
||||
import org.apache.guacamole.environment.Environment;
|
||||
import org.apache.guacamole.event.EventLoggingListener;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.event.listener.Listener;
|
||||
import org.apache.guacamole.properties.StringSetProperty;
|
||||
@@ -628,8 +629,9 @@ public class ExtensionModule extends ServletModule {
|
||||
final Set<String> toleratedAuthProviders = getToleratedAuthenticationProviders();
|
||||
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);
|
||||
bindListener(EventLoggingListener.class);
|
||||
|
||||
// Dynamically generate app.js and app.css from extensions
|
||||
serve("/app.js").with(new ResourceServlet(new SequenceResource(javaScriptResources)));
|
||||
|
Reference in New Issue
Block a user