GUACAMOLE-364: notify authentication listeners in AuthenticationService

This commit is contained in:
Carl Harris
2017-08-16 06:58:18 -04:00
parent cfb879b763
commit 5a232f6825
2 changed files with 100 additions and 4 deletions

View File

@@ -0,0 +1,34 @@
/*
* 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");
}
}

View File

@@ -24,9 +24,11 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.guacamole.GuacamoleAuthenticationRejectedException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnauthorizedException; import org.apache.guacamole.GuacamoleUnauthorizedException;
import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.environment.Environment; import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
@@ -35,7 +37,9 @@ import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo; import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
import org.apache.guacamole.GuacamoleSession; import org.apache.guacamole.net.event.AuthenticationFailureEvent;
import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
import org.apache.guacamole.rest.event.ListenerService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -74,6 +78,12 @@ public class AuthenticationService {
@Inject @Inject
private AuthTokenGenerator authTokenGenerator; private AuthTokenGenerator authTokenGenerator;
/**
* The service to use to notify registered authentication listeners
*/
@Inject
private ListenerService listenerService;
/** /**
* Regular expression which matches any IPv4 address. * Regular expression which matches any IPv4 address.
*/ */
@@ -207,6 +217,50 @@ 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.
*
* @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
*/
private void notifyAuthenticationSuccessListeners(
AuthenticatedUser authenticatedUser, GuacamoleSession session)
throws GuacamoleException {
UserContext userContext = null;
if (session != null) {
userContext = session.getUserContext(
authenticatedUser.getAuthenticationProvider().getIdentifier());
}
AuthenticationSuccessEvent event = new AuthenticationSuccessEvent(
userContext, authenticatedUser.getCredentials());
boolean ok = listenerService.authenticationSucceeded(event);
if (!ok) {
throw new GuacamoleAuthenticationRejectedException();
}
}
/**
* Notify all bound AuthenticationFailureListeners that an authentication has failed.
*
* @param credentials
* The credentials that failed to authenticate
* @throws GuacamoleException
* If a filter throws an exception
*/
private void notifyAuthenticationFailureListeners(Credentials credentials)
throws GuacamoleException {
listenerService.authenticationFailed(new AuthenticationFailureEvent(credentials));
}
/** /**
* Returns the AuthenticatedUser associated with the given session and * Returns the AuthenticatedUser associated with the given session and
* credentials, performing a fresh authentication and creating a new * credentials, performing a fresh authentication and creating a new
@@ -232,11 +286,17 @@ public class AuthenticationService {
try { try {
// Re-authenticate user if session exists // Re-authenticate user if session exists
if (existingSession != null) if (existingSession != null) {
return updateAuthenticatedUser(existingSession.getAuthenticatedUser(), credentials); AuthenticatedUser updatedUser = updateAuthenticatedUser(
existingSession.getAuthenticatedUser(), credentials);
notifyAuthenticationSuccessListeners(updatedUser, existingSession);
return updatedUser;
}
// Otherwise, attempt authentication as a new user // Otherwise, attempt authentication as a new user
AuthenticatedUser authenticatedUser = AuthenticationService.this.authenticateUser(credentials); AuthenticatedUser authenticatedUser = authenticateUser(credentials);
notifyAuthenticationSuccessListeners(authenticatedUser, null);
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
logger.info("User \"{}\" successfully authenticated from {}.", logger.info("User \"{}\" successfully authenticated from {}.",
authenticatedUser.getIdentifier(), authenticatedUser.getIdentifier(),
@@ -249,6 +309,8 @@ public class AuthenticationService {
// Log and rethrow any authentication errors // Log and rethrow any authentication errors
catch (GuacamoleException e) { catch (GuacamoleException e) {
notifyAuthenticationFailureListeners(credentials);
// Get request and username for sake of logging // Get request and username for sake of logging
HttpServletRequest request = credentials.getRequest(); HttpServletRequest request = credentials.getRequest();
String username = credentials.getUsername(); String username = credentials.getUsername();