* Abstract servlet which provides an authenticatedService() function that
* is only called if the HTTP request is authenticated, or the current
* HTTP session has already been authenticated.
- *
+ *
* Authorized configurations are retrieved using the authentication provider
* defined in guacamole.properties. The authentication provider has access
* to the request and session, in addition to any submitted username and
* password, in order to authenticate the user.
- *
+ *
* All authorized configurations will be stored in the current HttpSession.
- *
+ *
* Success and failure are logged.
- *
+ *
* @author Michael Jumper
*/
public abstract class AuthenticatingHttpServlet extends HttpServlet {
private Logger logger = LoggerFactory.getLogger(AuthenticatingHttpServlet.class);
-
+
+ /**
+ * The session attribute holding the map of configurations.
+ */
+ private static final String CONFIGURATIONS_ATTRIBUTE = "GUAC_CONFIGS";
+
/**
- * The error message to be provided to the client user if authentication
- * fails for ANY REASON.
+ * The session attribute holding the credentials authorizing this session.
*/
- private static final String AUTH_ERROR_MESSAGE =
- "User not logged in or authentication failed.";
-
+ private static final String CREDENTIALS_ATTRIBUTE = "GUAC_CREDS";
+
/**
* The AuthenticationProvider to use to authenticate all requests.
*/
/**
* Notifies all listeners in the given collection that authentication has
* failed.
- *
+ *
* @param listeners A collection of all listeners that should be notified.
* @param credentials The credentials associated with the authentication
* request that failed.
*/
private void notifyFailed(Collection listeners, Credentials credentials) {
-
+
// Build event for auth failure
AuthenticationFailureEvent event = new AuthenticationFailureEvent(credentials);
-
+
// Notify all listeners
for (Object listener : listeners) {
try {
logger.error("Error notifying AuthenticationFailureListener.", e);
}
}
-
+
}
/**
* Notifies all listeners in the given collection that authentication was
* successful.
- *
+ *
* @param listeners A collection of all listeners that should be notified.
* @param credentials The credentials associated with the authentication
* request that succeeded.
*/
private boolean notifySuccess(Collection listeners, Credentials credentials)
throws GuacamoleException {
-
+
// Build event for auth success
AuthenticationSuccessEvent event = new AuthenticationSuccessEvent(credentials);
-
+
// Notify all listeners
for (Object listener : listeners) {
if (listener instanceof AuthenticationSuccessListener) {
// Cancel immediately if hook returns false
if (!((AuthenticationSuccessListener) listener).authenticationSucceeded(event))
return false;
-
+
}
}
return true;
-
+
}
-
+
/**
* Sends a predefined, generic error message to the user, along with a
* "403 - Forbidden" HTTP status code in the response.
- *
+ *
* @param response The response to send the error within.
* @throws IOException If an error occurs while sending the error.
*/
private void failAuthentication(HttpServletResponse response) throws IOException {
- response.setHeader("X-Guacamole-Error-Message", AUTH_ERROR_MESSAGE);
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
-
+
+ /**
+ * Returns the credentials associated with the given session.
+ *
+ * @param session The session to retrieve credentials from.
+ * @return The credentials associated with the given session.
+ */
+ protected Credentials getCredentials(HttpSession session) {
+ return (Credentials) session.getAttribute(CREDENTIALS_ATTRIBUTE);
+ }
+
+ /**
+ * Returns the configurations associated with the given session.
+ *
+ * @param session The session to retrieve configurations from.
+ * @return The configurations associated with the given session.
+ */
+ protected Map<String, GuacamoleConfiguration> getConfigurations(HttpSession session) {
+ return (Map<String, GuacamoleConfiguration>) session.getAttribute(CONFIGURATIONS_ATTRIBUTE);
+ }
+
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
HttpSession httpSession = request.getSession(true);
// Try to get configs from session
- Map<String, GuacamoleConfiguration> configs =
- (Map<String, GuacamoleConfiguration>) httpSession.getAttribute("GUAC_CONFIGS");
+ Map<String, GuacamoleConfiguration> configs = getConfigurations(httpSession);
// If no configs, try to authenticate the user to get the configs using
// this request.
failAuthentication(response);
return;
}
-
+
// Retrieve username and password from parms
String username = request.getParameter("username");
String password = request.getParameter("password");
// Build credentials object
- Credentials credentials = new Credentials ();
+ Credentials credentials = new Credentials();
credentials.setSession(httpSession);
credentials.setRequest(request);
credentials.setUsername(username);
credentials.setPassword(password);
-
+
// Get authorized configs
try {
configs = authProvider.getAuthorizedConfigurations(credentials);
/******** HANDLE FAILED AUTHENTICATION ********/
-
+
// If error retrieving configs, fail authentication, notify listeners
catch (GuacamoleException e) {
- logger.error("Error retrieving configuration(s) for user \"{}\".", username);
+ logger.error("Error retrieving configuration(s) for user \"{}\".",
+ credentials.getUsername(), e);
notifyFailed(listeners, credentials);
failAuthentication(response);
return;
}
-
+
// If no configs, fail authentication, notify listeners
if (configs == null) {
logger.warn("Authentication attempt from {} for user \"{}\" failed.",
- request.getRemoteAddr(), username);
-
+ request.getRemoteAddr(), credentials.getUsername());
+
notifyFailed(listeners, credentials);
failAuthentication(response);
return;
/******** HANDLE SUCCESSFUL AUTHENTICATION ********/
-
+
try {
// Otherwise, authentication has been succesful
logger.info("User \"{}\" successfully authenticated from {}.",
- username, request.getRemoteAddr());
+ credentials.getUsername(), request.getRemoteAddr());
// Notify of success, cancel if requested
if (!notifySuccess(listeners, credentials)) {
failAuthentication(response);
return;
}
-
+
}
catch (GuacamoleException e) {
-
+
// Cancel authentication success if hook throws exception
- logger.error("Successful authentication canceled by error in hook.");
+ logger.error("Successful authentication canceled by error in hook.", e);
failAuthentication(response);
return;
-
+
}
- // Associate configs with session
- httpSession.setAttribute("GUAC_CONFIGS", configs);
+ // Associate configs and credentials with session
+ httpSession.setAttribute(CONFIGURATIONS_ATTRIBUTE, configs);
+ httpSession.setAttribute(CREDENTIALS_ATTRIBUTE, credentials);
}