mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-990: Fire auth success/failure events only after authentication has absolutely succeeded or failed, including the details of any failure.
Previously, these events were fired only after the user's identity had been determined (or failed to be determined). If we don't wait until after the user contexts have also been successfully obtained (or failed to be obtained), then things like MFA will not be taken into account for auth events.
This commit is contained in:
@@ -19,28 +19,91 @@
|
||||
|
||||
package org.apache.guacamole.net.event;
|
||||
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.event.listener.Listener;
|
||||
|
||||
/**
|
||||
* An event which is triggered whenever a user's credentials fail to be
|
||||
* authenticated. The credentials that failed to be authenticated are included
|
||||
* within this event, and can be retrieved using getCredentials().
|
||||
*/
|
||||
public class AuthenticationFailureEvent implements CredentialEvent {
|
||||
public class AuthenticationFailureEvent implements AuthenticationProviderEvent,
|
||||
CredentialEvent, FailureEvent {
|
||||
|
||||
/**
|
||||
* The credentials which failed authentication.
|
||||
*/
|
||||
private Credentials credentials;
|
||||
private final Credentials credentials;
|
||||
|
||||
/**
|
||||
* Creates a new AuthenticationFailureEvent which represents the failure
|
||||
* to authenticate the given credentials.
|
||||
* The AuthenticationProvider that encountered the failure. This may be
|
||||
* null if the AuthenticationProvider is not known, such as if the failure
|
||||
* is caused by every AuthenticationProvider passively refusing to
|
||||
* authenticate the user but without explicitly rejecting the user
|
||||
* (returning null for calls to {@link AuthenticationProvider#authenticateUser(org.apache.guacamole.net.auth.Credentials)}),
|
||||
* or if the failure is external to any installed AuthenticationProvider
|
||||
* (such as within a {@link Listener}.
|
||||
*/
|
||||
private final AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* The Throwable that was thrown resulting in the failure, if any. This
|
||||
* may be null if authentication failed without a known error, such as if
|
||||
* the failure is caused by every AuthenticationProvider passively refusing
|
||||
* to authenticate the user but without explicitly rejecting the user
|
||||
* (returning null for calls to {@link AuthenticationProvider#authenticateUser(org.apache.guacamole.net.auth.Credentials)}).
|
||||
*/
|
||||
private final Throwable failure;
|
||||
|
||||
/**
|
||||
* Creates a new AuthenticationFailureEvent which represents a failure
|
||||
* to authenticate the given credentials where there is no specific
|
||||
* AuthenticationProvider nor Throwable associated with the failure.
|
||||
*
|
||||
* @param credentials The credentials which failed authentication.
|
||||
* @param credentials
|
||||
* The credentials which failed authentication.
|
||||
*/
|
||||
public AuthenticationFailureEvent(Credentials credentials) {
|
||||
this(credentials, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AuthenticationFailureEvent which represents a failure
|
||||
* to authenticate the given credentials where there is no specific
|
||||
* AuthenticationProvider causing the failure.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials which failed authentication.
|
||||
*
|
||||
* @param failure
|
||||
* The Throwable that was thrown resulting in the failure, or null if
|
||||
* there is no such Throwable.
|
||||
*/
|
||||
public AuthenticationFailureEvent(Credentials credentials, Throwable failure) {
|
||||
this(credentials, null, failure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AuthenticationFailureEvent which represents a failure
|
||||
* to authenticate the given credentials.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials which failed authentication.
|
||||
*
|
||||
* @param authProvider
|
||||
* The AuthenticationProvider that caused the failure, or null if there
|
||||
* is no such AuthenticationProvider.
|
||||
*
|
||||
* @param failure
|
||||
* The Throwable that was thrown resulting in the failure, or null if
|
||||
* there is no such Throwable.
|
||||
*/
|
||||
public AuthenticationFailureEvent(Credentials credentials,
|
||||
AuthenticationProvider authProvider, Throwable failure) {
|
||||
this.credentials = credentials;
|
||||
this.authProvider = authProvider;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,4 +111,35 @@ public class AuthenticationFailureEvent implements CredentialEvent {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>NOTE: In the case of an authentication failure, cases where this may
|
||||
* be null include if authentication failed without a definite single
|
||||
* AuthenticationProvider causing that failure, such as if the failure is
|
||||
* caused by every AuthenticationProvider passively refusing to
|
||||
* authenticate the user but without explicitly rejecting the user
|
||||
* (returning null for calls to {@link AuthenticationProvider#authenticateUser(org.apache.guacamole.net.auth.Credentials)}),
|
||||
* or if the failure is external to any installed AuthenticationProvider
|
||||
* (such as within a {@link Listener}.
|
||||
*/
|
||||
@Override
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>NOTE: In the case of an authentication failure, cases where this may
|
||||
* be null include if authentication failed without a known error, such as
|
||||
* if the failure is caused by every AuthenticationProvider passively
|
||||
* refusing to authenticate the user but without explicitly rejecting the
|
||||
* user (returning null for calls to {@link AuthenticationProvider#authenticateUser(org.apache.guacamole.net.auth.Credentials)}).
|
||||
*/
|
||||
@Override
|
||||
public Throwable getFailure() {
|
||||
return failure;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.net.event;
|
||||
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
|
||||
/**
|
||||
* An event which may be dispatched due to a specific AuthenticationProvider.
|
||||
*/
|
||||
public interface AuthenticationProviderEvent {
|
||||
|
||||
/**
|
||||
* Returns the AuthenticationProvider that resulted in the event, if any.
|
||||
* If the event occurred without any definite causing
|
||||
* AuthenticationProvider, this may be null.
|
||||
*
|
||||
* @return
|
||||
* The AuthenticationProvider that resulted in the event, or null if no
|
||||
* such AuthenticationProvider is known.
|
||||
*/
|
||||
AuthenticationProvider getAuthenticationProvider();
|
||||
|
||||
}
|
@@ -20,6 +20,7 @@
|
||||
package org.apache.guacamole.net.event;
|
||||
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,8 @@ import org.apache.guacamole.net.auth.Credentials;
|
||||
* is effectively <em>vetoed</em> and will be subsequently processed as though the
|
||||
* authentication failed.
|
||||
*/
|
||||
public class AuthenticationSuccessEvent implements UserEvent, CredentialEvent {
|
||||
public class AuthenticationSuccessEvent implements UserEvent, CredentialEvent,
|
||||
AuthenticationProviderEvent {
|
||||
|
||||
/**
|
||||
* The AuthenticatedUser identifying the user that successfully
|
||||
@@ -60,7 +62,12 @@ public class AuthenticationSuccessEvent implements UserEvent, CredentialEvent {
|
||||
|
||||
@Override
|
||||
public Credentials getCredentials() {
|
||||
return authenticatedUser.getCredentials();
|
||||
return getAuthenticatedUser().getCredentials();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return getAuthenticatedUser().getAuthenticationProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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.net.event;
|
||||
|
||||
/**
|
||||
* An event which represents failure of an operation, where that failure may
|
||||
* be associated with a particular Throwable.
|
||||
*/
|
||||
public interface FailureEvent {
|
||||
|
||||
/**
|
||||
* Returns the Throwable that represents the failure that occurred, if any.
|
||||
* If the failure was recognized but without a definite known error, this
|
||||
* may be null.
|
||||
*
|
||||
* @return
|
||||
* The Throwable that represents the failure that occurred, or null if
|
||||
* no such Throwable is known.
|
||||
*/
|
||||
Throwable getFailure();
|
||||
|
||||
}
|
@@ -34,7 +34,6 @@ import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.auth.UserContext;
|
||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
@@ -169,14 +168,15 @@ public class AuthenticationService {
|
||||
* The AuthenticatedUser given by the highest-priority
|
||||
* AuthenticationProvider for which the given credentials are valid.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If the given credentials are not valid for any
|
||||
* AuthenticationProvider, or if an error occurs while authenticating
|
||||
* the user.
|
||||
*/
|
||||
private AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
AuthenticationProvider failedAuthProvider = null;
|
||||
GuacamoleCredentialsException authFailure = null;
|
||||
|
||||
// Attempt authentication against each AuthenticationProvider
|
||||
@@ -191,27 +191,29 @@ public class AuthenticationService {
|
||||
|
||||
// Insufficient credentials should take precedence
|
||||
catch (GuacamoleInsufficientCredentialsException e) {
|
||||
if (authFailure == null || authFailure instanceof GuacamoleInvalidCredentialsException)
|
||||
if (authFailure == null || authFailure instanceof GuacamoleInvalidCredentialsException) {
|
||||
failedAuthProvider = authProvider;
|
||||
authFailure = e;
|
||||
}
|
||||
}
|
||||
|
||||
// Catch other credentials exceptions and assign the first one
|
||||
catch (GuacamoleCredentialsException e) {
|
||||
if (authFailure == null)
|
||||
if (authFailure == null) {
|
||||
failedAuthProvider = authProvider;
|
||||
authFailure = e;
|
||||
}
|
||||
}
|
||||
|
||||
catch (GuacamoleException | RuntimeException | Error e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User "
|
||||
+ "authentication was aborted.", authProvider, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If a specific failure occured, rethrow that
|
||||
if (authFailure != null)
|
||||
throw authFailure;
|
||||
|
||||
// Otherwise, request standard username/password
|
||||
throw new GuacamoleInvalidCredentialsException(
|
||||
"Permission Denied.",
|
||||
CredentialsInfo.USERNAME_PASSWORD
|
||||
);
|
||||
throw new GuacamoleAuthenticationProcessException("User authentication "
|
||||
+ "failed.", failedAuthProvider, authFailure);
|
||||
|
||||
}
|
||||
|
||||
@@ -230,15 +232,17 @@ public class AuthenticationService {
|
||||
* A AuthenticatedUser which may have been updated due to re-
|
||||
* authentication.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If an error prevents the user from being re-authenticated.
|
||||
*/
|
||||
private AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Get original AuthenticationProvider
|
||||
AuthenticationProvider authProvider = authenticatedUser.getAuthenticationProvider();
|
||||
|
||||
try {
|
||||
|
||||
// Re-authenticate the AuthenticatedUser against the original AuthenticationProvider only
|
||||
authenticatedUser = authProvider.updateAuthenticatedUser(authenticatedUser, credentials);
|
||||
if (authenticatedUser == null)
|
||||
@@ -247,34 +251,10 @@ public class AuthenticationService {
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all bound listeners that a successful authentication
|
||||
* has occurred.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The user that was successfully authenticated.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If thrown by a listener.
|
||||
*/
|
||||
private void fireAuthenticationSuccessEvent(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
listenerService.handleEvent(new AuthenticationSuccessEvent(authenticatedUser));
|
||||
catch (GuacamoleException | RuntimeException | Error e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User re-authentication failed.", authProvider, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all bound listeners that an authentication attempt has failed.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials that failed to authenticate.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If thrown by a listener.
|
||||
*/
|
||||
private void fireAuthenticationFailedEvent(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
listenerService.handleEvent(new AuthenticationFailureEvent(credentials));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,64 +272,26 @@ public class AuthenticationService {
|
||||
* The AuthenticatedUser associated with the given session and
|
||||
* credentials.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If an error occurs while authenticating or re-authenticating the
|
||||
* user.
|
||||
*/
|
||||
private AuthenticatedUser getAuthenticatedUser(GuacamoleSession existingSession,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
try {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Re-authenticate user if session exists
|
||||
if (existingSession != null) {
|
||||
AuthenticatedUser updatedUser = updateAuthenticatedUser(
|
||||
existingSession.getAuthenticatedUser(), credentials);
|
||||
fireAuthenticationSuccessEvent(updatedUser);
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
// Otherwise, attempt authentication as a new user
|
||||
AuthenticatedUser authenticatedUser = AuthenticationService.this.authenticateUser(credentials);
|
||||
fireAuthenticationSuccessEvent(authenticatedUser);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("User \"{}\" successfully authenticated from {}.",
|
||||
authenticatedUser.getIdentifier(),
|
||||
getLoggableAddress(credentials.getRequest()));
|
||||
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
// Log and rethrow any authentication errors
|
||||
catch (GuacamoleException e) {
|
||||
|
||||
fireAuthenticationFailedEvent(credentials);
|
||||
|
||||
// Get request and username for sake of logging
|
||||
HttpServletRequest request = credentials.getRequest();
|
||||
String username = credentials.getUsername();
|
||||
|
||||
// Log authentication failures with associated usernames
|
||||
if (username != null) {
|
||||
if (logger.isWarnEnabled())
|
||||
logger.warn("Authentication attempt from {} for user \"{}\" failed.",
|
||||
getLoggableAddress(request), username);
|
||||
}
|
||||
|
||||
// Log anonymous authentication failures
|
||||
else if (logger.isDebugEnabled())
|
||||
logger.debug("Anonymous authentication attempt from {} failed.",
|
||||
getLoggableAddress(request));
|
||||
|
||||
// Rethrow exception
|
||||
throw e;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all UserContexts associated with the given AuthenticatedUser,
|
||||
* updating existing UserContexts, if any. If no UserContexts are yet
|
||||
@@ -371,15 +313,14 @@ public class AuthenticationService {
|
||||
* A List of all UserContexts associated with the given
|
||||
* AuthenticatedUser.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If an error occurs while creating or updating any UserContext.
|
||||
*/
|
||||
private List<DecoratedUserContext> getUserContexts(GuacamoleSession existingSession,
|
||||
AuthenticatedUser authenticatedUser, Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
List<DecoratedUserContext> userContexts =
|
||||
new ArrayList<DecoratedUserContext>(authProviders.size());
|
||||
List<DecoratedUserContext> userContexts = new ArrayList<>(authProviders.size());
|
||||
|
||||
// If UserContexts already exist, update them and add to the list
|
||||
if (existingSession != null) {
|
||||
@@ -392,7 +333,15 @@ public class AuthenticationService {
|
||||
|
||||
// Update existing UserContext
|
||||
AuthenticationProvider authProvider = oldUserContext.getAuthenticationProvider();
|
||||
UserContext updatedUserContext = authProvider.updateUserContext(oldUserContext, authenticatedUser, credentials);
|
||||
UserContext updatedUserContext;
|
||||
try {
|
||||
updatedUserContext = authProvider.updateUserContext(oldUserContext, authenticatedUser, credentials);
|
||||
}
|
||||
catch (GuacamoleException | RuntimeException | Error e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User "
|
||||
+ "authentication aborted during UserContext update.",
|
||||
authProvider, e);
|
||||
}
|
||||
|
||||
// Add to available data, if successful
|
||||
if (updatedUserContext != null)
|
||||
@@ -415,7 +364,15 @@ public class AuthenticationService {
|
||||
for (AuthenticationProvider authProvider : authProviders) {
|
||||
|
||||
// Generate new UserContext
|
||||
UserContext userContext = authProvider.getUserContext(authenticatedUser);
|
||||
UserContext userContext;
|
||||
try {
|
||||
userContext = authProvider.getUserContext(authenticatedUser);
|
||||
}
|
||||
catch (GuacamoleException | RuntimeException | Error e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User "
|
||||
+ "authentication aborted during initial "
|
||||
+ "UserContext creation.", authProvider, e);
|
||||
}
|
||||
|
||||
// Add to available data, if successful
|
||||
if (userContext != null)
|
||||
@@ -462,12 +419,16 @@ public class AuthenticationService {
|
||||
else
|
||||
existingSession = null;
|
||||
|
||||
AuthenticatedUser authenticatedUser;
|
||||
String authToken;
|
||||
|
||||
try {
|
||||
|
||||
// Get up-to-date AuthenticatedUser and associated UserContexts
|
||||
AuthenticatedUser authenticatedUser = getAuthenticatedUser(existingSession, credentials);
|
||||
authenticatedUser = getAuthenticatedUser(existingSession, credentials);
|
||||
List<DecoratedUserContext> userContexts = getUserContexts(existingSession, authenticatedUser, credentials);
|
||||
|
||||
// Update existing session, if it exists
|
||||
String authToken;
|
||||
if (existingSession != null) {
|
||||
authToken = token;
|
||||
existingSession.setAuthenticatedUser(authenticatedUser);
|
||||
@@ -481,6 +442,49 @@ public class AuthenticationService {
|
||||
logger.debug("Login was successful for user \"{}\".", authenticatedUser.getIdentifier());
|
||||
}
|
||||
|
||||
// Report authentication success
|
||||
try {
|
||||
listenerService.handleEvent(new AuthenticationSuccessEvent(authenticatedUser));
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User "
|
||||
+ "authentication aborted by event listener.", null, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Log and rethrow any authentication errors
|
||||
catch (GuacamoleAuthenticationProcessException e) {
|
||||
|
||||
// Get request and username for sake of logging
|
||||
HttpServletRequest request = credentials.getRequest();
|
||||
String username = credentials.getUsername();
|
||||
|
||||
listenerService.handleEvent(new AuthenticationFailureEvent(credentials,
|
||||
e.getAuthenticationProvider(), e.getCause()));
|
||||
|
||||
// Log authentication failures with associated usernames
|
||||
if (username != null) {
|
||||
if (logger.isWarnEnabled())
|
||||
logger.warn("Authentication attempt from {} for user \"{}\" failed.",
|
||||
getLoggableAddress(request), username);
|
||||
}
|
||||
|
||||
// Log anonymous authentication failures
|
||||
else if (logger.isDebugEnabled())
|
||||
logger.debug("Anonymous authentication attempt from {} failed.",
|
||||
getLoggableAddress(request));
|
||||
|
||||
// Rethrow exception
|
||||
throw e.getCauseAsGuacamoleException();
|
||||
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("User \"{}\" successfully authenticated from {}.",
|
||||
authenticatedUser.getIdentifier(),
|
||||
getLoggableAddress(credentials.getRequest()));
|
||||
|
||||
return authToken;
|
||||
|
||||
}
|
||||
|
@@ -76,21 +76,29 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
* given AuthenticationProvider, or the original UserContext if the
|
||||
* given AuthenticationProvider originated the UserContext.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If the given AuthenticationProvider fails while decorating the
|
||||
* UserContext.
|
||||
*/
|
||||
private static UserContext decorate(AuthenticationProvider authProvider,
|
||||
UserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Skip the AuthenticationProvider which produced the UserContext
|
||||
// being decorated
|
||||
if (authProvider != userContext.getAuthenticationProvider()) {
|
||||
|
||||
// Apply layer of wrapping around UserContext
|
||||
UserContext decorated = authProvider.decorate(userContext,
|
||||
UserContext decorated;
|
||||
try {
|
||||
decorated = authProvider.decorate(userContext,
|
||||
authenticatedUser, credentials);
|
||||
}
|
||||
catch (GuacamoleException | RuntimeException | Error e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User "
|
||||
+ "authentication aborted by decorating UserContext.",
|
||||
authProvider, e);
|
||||
}
|
||||
|
||||
// Do not allow misbehaving extensions to wipe out the
|
||||
// UserContext entirely
|
||||
@@ -130,13 +138,13 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
* given AuthenticationProvider, or the original UserContext if the
|
||||
* given AuthenticationProvider originated the UserContext.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If the given AuthenticationProvider fails while decorating the
|
||||
* UserContext.
|
||||
*/
|
||||
private static UserContext redecorate(DecoratedUserContext decorated,
|
||||
UserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
AuthenticationProvider authProvider = decorated.getDecoratingAuthenticationProvider();
|
||||
|
||||
@@ -145,8 +153,16 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
if (authProvider != userContext.getAuthenticationProvider()) {
|
||||
|
||||
// Apply next layer of wrapping around UserContext
|
||||
UserContext redecorated = authProvider.redecorate(decorated.getDelegateUserContext(),
|
||||
UserContext redecorated;
|
||||
try {
|
||||
redecorated = authProvider.redecorate(decorated.getDelegateUserContext(),
|
||||
userContext, authenticatedUser, credentials);
|
||||
}
|
||||
catch (GuacamoleException | RuntimeException | Error e) {
|
||||
throw new GuacamoleAuthenticationProcessException("User "
|
||||
+ "authentication aborted by redecorating UserContext.",
|
||||
authProvider, e);
|
||||
}
|
||||
|
||||
// Do not allow misbehaving extensions to wipe out the
|
||||
// UserContext entirely
|
||||
@@ -181,13 +197,13 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
* The credentials associated with the request which produced the given
|
||||
* UserContext.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If any of the given AuthenticationProviders fails while decorating
|
||||
* the UserContext.
|
||||
*/
|
||||
public DecoratedUserContext(AuthenticationProvider authProvider,
|
||||
UserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Wrap the result of invoking decorate() on the given AuthenticationProvider
|
||||
super(decorate(authProvider, userContext, authenticatedUser, credentials));
|
||||
@@ -221,13 +237,13 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
* The credentials associated with the request which produced the given
|
||||
* UserContext.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If any of the given AuthenticationProviders fails while decorating
|
||||
* the UserContext.
|
||||
*/
|
||||
public DecoratedUserContext(AuthenticationProvider authProvider,
|
||||
DecoratedUserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Wrap the result of invoking decorate() on the given AuthenticationProvider
|
||||
super(decorate(authProvider, userContext, authenticatedUser, credentials));
|
||||
@@ -261,13 +277,13 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
* The credentials associated with the request which produced the given
|
||||
* UserContext.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If any of the given AuthenticationProviders fails while decorating
|
||||
* the UserContext.
|
||||
*/
|
||||
public DecoratedUserContext(DecoratedUserContext decorated,
|
||||
UserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Wrap the result of invoking redecorate() on the given AuthenticationProvider
|
||||
super(redecorate(decorated, userContext, authenticatedUser, credentials));
|
||||
@@ -303,13 +319,13 @@ public class DecoratedUserContext extends DelegatingUserContext {
|
||||
* The credentials associated with the request which produced the given
|
||||
* UserContext.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If any of the given AuthenticationProviders fails while decorating
|
||||
* the UserContext.
|
||||
*/
|
||||
public DecoratedUserContext(DecoratedUserContext decorated,
|
||||
DecoratedUserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Wrap the result of invoking redecorate() on the given AuthenticationProvider
|
||||
super(redecorate(decorated, userContext, authenticatedUser, credentials));
|
||||
|
@@ -23,7 +23,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
@@ -65,12 +64,12 @@ public class DecorationService {
|
||||
* A new DecoratedUserContext which has been decorated by all
|
||||
* AuthenticationProviders.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If any AuthenticationProvider fails while decorating the UserContext.
|
||||
*/
|
||||
public DecoratedUserContext decorate(UserContext userContext,
|
||||
AuthenticatedUser authenticatedUser, Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// Get first AuthenticationProvider in list
|
||||
Iterator<AuthenticationProvider> current = authProviders.iterator();
|
||||
@@ -119,12 +118,12 @@ public class DecorationService {
|
||||
* A new DecoratedUserContext which has been decorated by all
|
||||
* AuthenticationProviders.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* @throws GuacamoleAuthenticationProcessException
|
||||
* If any AuthenticationProvider fails while decorating the UserContext.
|
||||
*/
|
||||
public DecoratedUserContext redecorate(DecoratedUserContext decorated,
|
||||
UserContext userContext, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
Credentials credentials) throws GuacamoleAuthenticationProcessException {
|
||||
|
||||
// If the given DecoratedUserContext contains further decorated layers,
|
||||
// redecorate those first
|
||||
|
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleServerException;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.apache.guacamole.protocol.GuacamoleStatus;
|
||||
|
||||
/**
|
||||
* An exception that occurs during Guacamole's authentication and authorization
|
||||
* process, possibly associated with a specific AuthenticationProvider.
|
||||
*/
|
||||
public class GuacamoleAuthenticationProcessException extends GuacamoleException {
|
||||
|
||||
/**
|
||||
* Internal identifier unique to this version of
|
||||
* GuacamoleAuthenticationProcessException, as required by Java's
|
||||
* {@link Serializable} interface.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider that caused the failure, or null if there is
|
||||
* no such specific AuthenticationProvider involved in this failure.
|
||||
*/
|
||||
private final transient AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* A GuacamoleException representation of the failure that occurred. If
|
||||
* the cause provided when this GuacamoleAuthenticationProcessException
|
||||
* was created was a GuacamoleException, this will just be that exception.
|
||||
* Otherwise, this will be a GuacamoleServerException wrapping the cause
|
||||
* or a generic GuacamoleInvalidCredentialsException requesting a
|
||||
* username/password if there is no specific cause at all.
|
||||
*/
|
||||
private final GuacamoleException guacCause;
|
||||
|
||||
/**
|
||||
* Converts the given Throwable to a GuacamoleException representing the
|
||||
* failure that occurred. If the Throwable already is a GuacamoleException,
|
||||
* this will just be that Throwable. For all other cases, a new
|
||||
* GuacamoleException will be created that best represents the provided
|
||||
* failure. If no failure is provided at all, a generic
|
||||
* GuacamoleInvalidCredentialsException requesting a username/password is
|
||||
* created.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the failure that occurred.
|
||||
*
|
||||
* @param cause
|
||||
* The Throwable cause of the failure that occurred, if any, or null if
|
||||
* the cause is not known to be a specific Throwable.
|
||||
*
|
||||
* @return
|
||||
* A GuacamoleException representation of the message and cause
|
||||
* provided.
|
||||
*/
|
||||
private static GuacamoleException toGuacamoleException(String message,
|
||||
Throwable cause) {
|
||||
|
||||
// Create generic invalid username/password exception if we have no
|
||||
// specific cause
|
||||
if (cause == null)
|
||||
return new GuacamoleInvalidCredentialsException(
|
||||
"Permission Denied.",
|
||||
CredentialsInfo.USERNAME_PASSWORD
|
||||
);
|
||||
|
||||
// If the specific cause is already a GuacamoleException, there's
|
||||
// nothing for us to do here
|
||||
if (cause instanceof GuacamoleException)
|
||||
return (GuacamoleException) cause;
|
||||
|
||||
// Wrap all other Throwables as generic internal errors
|
||||
return new GuacamoleServerException(message, cause);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleAuthenticationProcessException with the given
|
||||
* message, associated AuthenticationProvider, and cause.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param authProvider
|
||||
* The AuthenticationProvider that caused the failure, or null if there
|
||||
* is no such specific AuthenticationProvider involved in this failure.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception, or null if the cause is unknown or
|
||||
* there is no such cause.
|
||||
*/
|
||||
public GuacamoleAuthenticationProcessException(String message,
|
||||
AuthenticationProvider authProvider, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.authProvider = authProvider;
|
||||
this.guacCause = toGuacamoleException(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AuthenticationProvider that caused the failure, if any. If
|
||||
* there is no specific AuthenticationProvider involved in this failure,
|
||||
* including if the failure is due to multiple AuthenticationProviders,
|
||||
* this will be null.
|
||||
*
|
||||
* @return
|
||||
* The AuthenticationProvider that caused the failure, or null if there
|
||||
* is no such specific AuthenticationProvider involved in this failure.
|
||||
*/
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a GuacamoleException that represents the user-facing cause of
|
||||
* this exception. A GuacamoleException will be returned by this function
|
||||
* in all cases, including if no specific cause was given.
|
||||
*
|
||||
* @return
|
||||
* A GuacamoleException that represents the user-facing cause of this
|
||||
* exception.
|
||||
*/
|
||||
public GuacamoleException getCauseAsGuacamoleException() {
|
||||
return guacCause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleStatus getStatus() {
|
||||
return getCauseAsGuacamoleException().getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHttpStatusCode() {
|
||||
return getCauseAsGuacamoleException().getHttpStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWebSocketCode() {
|
||||
return getCauseAsGuacamoleException().getWebSocketCode();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user