Chapter 3. Kernel

Security FAQ

This document answers frequently-asked questions about Red Hat Web Application Framework security mechanisms and API.

How do I determine whether the user is logged in?

KernelHelper.getKernelRequestContext(request).getUserContext().isLoggedIn() returns true if the user is logged in, false otherwise.

How do I get the ID for the current user?

KernelHelper.getKernelRequestContext(request).getUserContext().getUserID() returns the current user's ID. This method throws an exception if the user is not logged in, so check with isLoggedIn() first. If the calling code needs a User object for the current user, it should call getUser() instead.

How do I get the User object for the current user?

KernelHelper.getKernelRequestContext(request).getUserContext().getUser() returns a User object for the current user. This method throws an exception if the user is not logged in, so check with isLoggedIn() first. This method throws DataObjectNotFoundException if the user doesn't exist; calling code should catch this exception and handle it appropriately. The User object provided by this method is cached for the current thread, so multiple calls to getUser() incur at most one database hit.

KernelHelper.getCurrentUser(request) is a convenience method that returns the current User object if available, returns null if the user is not logged in, or throws a RuntimeException if the user is logged in but does not exist.

How can a user be logged in but not exist in the database?

Red Hat Web Application Framework logs users in automatically using cookies (or other mechanisms), so it is possible for a client to present a valid cookie for a user that doesn't exist. This might happen if the user is deleted, the database is cleared, or an attacker spoofs a non-existent user's cookie. Red Hat Web Application Framework uses cryptographic mechanisms to make the last case unlikely.

How do I require that a user is logged in for a given page?

com.arsdigita.ui.login.UserAuthenticationListener is a RequestListener that requires that the user is logged in and that the user exists. This listener should be added to any bebop Page that requires login using Page.addRequestListener(). If the user is not logged in or doesn't exist, the client is redirected to the login page with return_url set to the original request URL. This ensures that the client will return to the original page after logging in. If the user is logged in, this listener provides the methods isLoggedIn() and getUser(). Note that these methods differ from those in UserContext since they also ensure that the user exists.

How do I require that a user is securely authenticated (using SSL or similar) for a given page?

This is not yet provided in a single API, but this can be accomplished using a UserAuthenticationListener and then calling com.arsdigita.kernel.Initializer.getSecurityHelper.isSecure(request) to check whether the current request is secure. In the current implementation of Red Hat Web Application Framework, a user must be logged in securely to access a page over SSL. This restriction will be loosened in the future, and an API for checking secure authentication will be provided.

How do I get the HttpSession object for the current request?

Red Hat Web Application Framework does not currently wrap session retrieval, so request.getSession() will return the current HttpSession object. Note that session management is independent of user authentication, so a session will always exist, whether or not the user is logged in.

How do I log in a user using a username and password?

KernelHelper.getKernelRequestContext(request).getUserContext().login(username, password, forever), where forever should be true if the user should be granted a permanent login cookie, false if the cookie should only last for the current session. See com.arsdigita.ui.login.UserRegistrationForm for an example. Note that there are several subtle security issues in managing passwords safely, so developers are encouraged to use the provided UI code rather than creating their own. This ensures that developers automatically benefit from fixes in future releases.

How do I log in as another user (Administrators only)?

Three methods allow an administrator to "become" another user:

  • KernelHelper.getKernelRequestContext(request).getUserContext().login(username)

  • KernelHelper.getKernelRequestContext(request).getUserContext().login(userID)

  • KernelHelper.getKernelRequestContext(request).getUserContext().login(User)

The first two versions of this method are convenience wrappers for the third. These methods require that the current user be an administrator. After calling any of these methods, the UserContext is updated with the target user's information; but cached user information (such as that provided by UserAuthenticationListener) will still contain the administrator's information. Immediately after calling any of these methods, the client should be redirected to a new page (such as the user workspace). See com.arsdigita.ui.admin.UserLoginPage for an example.

How do I log out a user?

KernelHelper.getKernelRequestContext(request).getUserContext().logout() logs out the current user. com.arsdigita.ui.login.UserLogoutListener is an ActionListener that logs out the user by calling this method. Developers can link to this action listener using an ActionLink. Alternately, developers can link to a com.arsdigita.ui.login.UserLogoutPage; this page logs out the user and immediately redirects the client to the registration page.

How do I get a user's email address?

Given the user's User object (the section called How do I get the User object for the current user?), user.getPrimaryEmail().getEmailAddress() returns the user's primary email address as a string. Note that getPrimaryEmail() or getEmailAddress() might return null.

com.arsdigita.ui.login.EmailInitListener is a FormInitListener that initializes a form parameter with the current user's email address, if possible. If the user is not logged in or has no email address, it leaves the parameter unchanged. See com.arsdigita.ui.login.UserRegistrationForm for an example.

How do I set a user's password?

Given the user's UserAuthentication object (the section called What is / How do I get a user's UserAuthentication object?), auth.setPassword(password) sets the user's password. Use this method carefully, as it can allow an attacker to override the user's password.

com.arsdigita.ui.login.PasswordValidationListener is a ParameterValidationListener that checks whether a form parameter value is a strong password. This listener should always be used before setting the user's password. See com.arsdigita.ui.login.ChangePasswordForm for an example.

What is / How do I get a user's UserAuthentication object?

There are four methods for retrieving a user's UserAuthentication object:

  • UserAuthentication.retrieveForLoginName(String loginName)

  • UserAuthentication.retrieveForUser(OID userOID)

  • UserAuthentication.retrieveForUser(BigDecimal userID)

  • UserAuthentication.retrieveForUser(User user)

The first is appropriate if the username is entered in a form; the last two are appropriate if the user is already logged in. The UserAuthentication object allows code to check and set a user's password and password retrieval question and answer. Access to this object is dangerous, since it can allow an attacker to compromise a user's account. If at all possible, use the provided UI components and login modules rather than access this object directly.

What is / How do I use the SecurityLogger class?

SecurityLogger wraps the Log4j category called "SECURITY". It provides static methods for appending entries to that log, and automatically inserts the current date and time and, if applicable, the current client's IP address. It is used to log security-relevant events for future auditing. Examples of such events are bad passwords, malformed cookies, and expired login page accesses. To use the class, simply call the appropriate class method, such as SecurityLogger.warn().