Programmatic Login to Vaadin application with JAAS utilizing JavaEE6 features and Spring injection

Programmatic Logging in to Vaadin application with JAAS utilizing Java EE 6 features and Spring injection#

Java EE 6 provides an easy way to perform logging into the Vaadin application with HttpServletRequest object’s login(String username, String password) method which validates the provided username and password in the password validation realm used by the web container login mechanism configured for the ServletContext. What this actually means is that with virtually zero configuration you can provide new application level users to JBoss7 or Glassfish 3 and they’re available with configured roles for your application without need for writing custom code for logging in process. The realm that web container uses for authentication is of course changeable to any other implementation that uses LDAP or any database based functionality. This way you can provide one clean implementation for your application and configure it to use any authentication implementation you wish.

Security Context#

One of the key features of logging in this way is the propagation of security context. Propagation means that you could write for example Vaadin application that logs the users in and during the same session would allow them to access for example different URLs in your server protected by the security constraints. When logging in with the HttpServletRequest’s login method, the security context will also be bound to current session and will be propagated for example to EJB calls in which you can use role based security checks implemented by annotations such as @RolesAllowed. Same security context is available through the EJBContext interface from which you can call the isCallerInRole(String role) method for programmatic security check in the backend side to allow certain business operations.

Fetching the HttpServletRequest#

HttpServletRequest can easily be fetched in Vaadin application by implementing the HttpServletRequestListener in the Application class. This is handy but comes with a problem the HttpServletRequest object not being the latest instance as it of course changes during every request made to the Vaadin application. To resolve this issue we use Spring’s RequestContextListener that provides us a way to access the request from current thread easily. RequestContextListener used with the @Autowired injection mechanism allows us to get the required object referenced by any controller or presenter that governs the login process of the Vaadin application.

Defining the Spring context #

xml namespaces omitted

#!xml

<beans>
	<context:annotation-config />
	<context:component-scan base-package="com.vaadin.example" />
</beans>

Defining web.xml deployment descriptor #

Two most important things are the definition of RequestContextListener that allows injecting proper instance of HttpServletRequest object and the security-constraint that secures our resources from users which have not logged in. Servlet definition and mapping omitted.

#!xml

<web-app id="WebApp_ID" version="2.4">
	<display-name>SpringProject</display-name>

	<!-- Spring global context initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- RequestContextListener allows Spring to inject HttpServletRequest so 
		that the current request object is always accessible -->
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>

...

	<!-- Define security constraint that protectes the application -->
	<security-constraint>
		<display-name>SecureApplicationConstraint</display-name>
		<web-resource-collection>
			<web-resource-name>Vaadin application</web-resource-name>
			<description>The entire Vaadin application is protected</description>
			<url-pattern>/app/*</url-pattern>
		</web-resource-collection>
	</security-constraint>


</web-app>

LoginBean #

LoginBean is an example Spring Bean that performs the actual login process with the HttpServletRequest.

#!java
@Component
@Scope("prototype")
public class LoginBean {

	@Autowired
	private HttpServletRequest request;

	/**
	 * Logs the user in with given username and password.
	 * 
	 * @param username
	 * @param password
	 * @return principal name if login is successful
	 * @throws ServletException
	 *             if login fails
	 */
	public String performLogin(String username, String password)
			throws ServletException {

		// If login fails, we throw exception. Otherwise return the principal
		// name of logged in user.
		request.login(username, password);
		return request.getUserPrincipal().getName();
	}

	/**
	 * Logs out the current user.
	 * 
	 * @throws ServletException
	 *             if logout fails
	 */
	public void performLogout() throws ServletException {
		request.logout();
	}
}

Using LoginBean from Vaadin application #

#!java

public class VaadinApplication extends Application {

   @Autowired
   private LoginBean loginBean;

...

   private final Button.ClickListener loginButtonListener = new Button.ClickListener() {

      public void buttonClick(ClickEvent event) {
         try {
            String name = loginBean.performLogin(username.getValue().toString(), password.getValue().toString());
            loginSucceeded(name);
         } catch (ServletException e) {
            loginFailed(e.getMessage());
         }
      }
   };

...

}

Summary#

Logging into the application with HttpServletRequest.login allows easy binding of security context to the current session which will be propagated also to EJB calls. As HttpServletRequest object changes during each different request to server we use Spring to access the thread bound request and allow injecting it to our own UI control logic. With just couple of code lines we're able to reference the required instance and allow signing in to the application. Springs RequestContextListener is used under the hood to get the actual reference.

In the web.xml deployment descriptor we've defined our security-constraint that is used to protect the application from unauthorized access. It's also required for the login method in the HttpServletRequest to perform the actual login

If the security domain to which the security realm is bound within the application server must be changed, this can be done with application server specific deployment descriptor. For example in JBoss7 following jboss-web.xml definition can be given

#!xml
<jboss-web>
	<security-domain>other</security-domain>
</jboss-web>

Given 'other' domain is the default domain for username and password validation if no other configuration is given. If for example LDAP configuration is required, application server must be configured with proper security domain and it must be referenced by it's name from the jboss-web.xml file. This way configuring the security domain is easy and will not affect the actual application code.

Attached is fully working Maven based example that should work also with JBoss7 and Glassfish3 without any additional configuration.

source code

1 Adjunto
7552 Accesos
Promedio (0 Votos)
Comentarios
Is using Spring the only way to integrate Vaadin 7 with JAAS? Is there a non-spring way?

Publicado el día 17/03/14 19:46.

Arriba