Several years ago I wrote a tutorial about using Acegi/Spring Security with JavaServer Faces (JSF) to create a simple authentication / Login page; however, times have changed and Java EE is back in action. I would no longer consider Spring a “requirement” when building a Java EE application. More specifically, if you are using the core Contexts and Dependency Injection (CDI) framework that serves as the backbone for the entire Java EE framework, Spring Security becomes less attractive (because it’s not compatible without using Spring itself, and Spring is a replacement for CDI).

This article will explore how to create a JSF login backed by the standards-compliant CDI framework (that is included with Java EE), and the PicketLink security framework (an open-source project from JBoss). Examples for this article were sourced from the very comprehensive, and quite understandable quick-start application from the PicketLink project itself.

Set up the Application

First things first, you’ll need to create a new Maven project set up as a Java EE web-application. You can do this using JBoss Forge, or you can just download the quick-start code, skip all the setup, and jump right to the explanation.

Activate JSF and CDI

You will also want to make sure that you have activated both JSF and CDI in your application configuration, so make sure that you do not forget to add the WEB-INF/beans.xml and WEB-INF/faces-config.xml files. Examples of these files (and where they need to be placed in the application) can be seen in the example code.

Add PicketLink to pom.xml

This step is as straightforward as the rest of this tutorial – just add the following configuration to your maven pom.xml file:

/pom.xml View the entire file <properties> <!-- PicketLink dependency versions --> <version.picketlink.javaee.bom>2.7.0-SNAPSHOT</version.picketlink.javaee.bom> <!-- ... --> </properties> <dependencyManagement> <dependencies> <!-- Dependency Management for PicketLink and Java EE 6.0. --> <dependency> <groupId>org.picketlink</groupId> <artifactId>picketlink-javaee-6.0</artifactId> <version>${version.picketlink.javaee.bom}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> <!-- ... --> </dependencyManagement> <dependencies> <!-- PicketLink Uber Dependency. It provides all PicketLink dependencies from a single JAR. You still can define each module separately, if you so choose. --> <dependency> <groupId>org.picketlink</groupId> <artifactId>picketlink</artifactId> <scope>compile</scope> </dependency> <!-- ... --> </dependencies>

Create the security configuration

/src/main/java/example/HttpSecurityConfiguration.java View the entire file /** * @author Pedro Igor */ public class HttpSecurityConfiguration { public void onInit(@Observes SecurityConfigurationEvent event) { SecurityConfigurationBuilder builder = event.getBuilder(); builder .http() .allPaths() .authenticateWith() .form() .authenticationUri("/login.jsf") .loginPage("/login.jsf") .errorPage("/error.jsf") .restoreOriginalRequest() .forPath("/javax.faces.resource/*") .unprotected() .forPath("/logout") .logout() .redirectTo("/home.jsf") .forPath("/home.jsf") .unprotected(); } }

This is where we will set up PicketLink, and tell it where our authentication page lives. This file should be placed anywhere on your Java source path.

This is essentially a simple CDI observer for the org.picketlink.event.SecurityConfigurationEvent . The event is fired during application startup and allows you to provide any configuration to PicketLink before it is initialized. All configuration related to Http Security is handled in this bean.

One thing to note is that we have set up both a login/logout page to restrict all page by default, but we have also set up some exceptions. These exceptions include the JSF resources path (necessary for serving image, stylesheet, and javascript files to component libraries), and also include the website homepage, because we’d like users to see something before they get shipped off to the login page.

In order for this configuration to recognize users, however, we’ll need to add some data to our IdentityManager . The IdentityManager is part of the PicketLink API that controls user credentials, passwords, and integration with your database (if you use one ;). To access this API, you should inject the PartitionManager into a @Startup, @Singleton bean.

/src/main/java/example/SecurityInitializer.java View the entire file /** * @author Shane Bryzak */ @Startup public class SecurityInitializer { @Inject private PartitionManager partitionManager; @PostConstruct public void create() { IdentityManager identityManager = this.partitionManager.createIdentityManager(); User user = new User("jane"); user.setEmail("jane@doe.com"); user.setFirstName("Jane"); user.setLastName("Doe"); identityManager.add(user); identityManager.updateCredential(user, new Password("abcd1234")); } }

This startup bean creates a default user account when the application is started. Since we are not providing an IDM configuration in this example, PicketLink will default to using a file-based identity store to persist user and other identity state.

Once we have this set up, our application is now ready to get a face-lift! It’s time to build the JSF pages that will use PicketLink to authenticate the user.

Create the Login Page

As we defined in our HttpSecurityConfiguration.java , we need to create a JSF login page located in the src/main/webapp/ folder.

This file contains a simple JSF form and command button that submits to PicketLink.

You must use <h:form method="POST" prependId="false"> . Otherwise, the form fields will be prepended with a random JSF component ID, like “j_3234:j_password”, and picketlink will not be able to handle the request!

/src/main/webapp/login.xhtml View the entire file <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:body> <h:form method="POST" prependId="false"> <h:inputText id="j_username" /> <h:inputSecret id="j_password"/> <h:commandButton id="login" value="Login" action="#{identity.login()}"/> </h:form> <p> Tip: you can login with a username/password of jane/abcd1234. </p> </h:body> </html>

Create a public and private page for the user to access

We also need to do the same for our server error page (where the user will be directed if login fails.)

/src/main/webapp/error.xhtml View the entire file <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <body> Sorry, there was an error!<br/> Tip: you can login with a username/password of jane/abcd1234. </h:form> </body> </html>

Last but not least, we need to add a few pages for the user to try to access, for which authentication is required, and the login form will be displayed before access is granted!

The home page is a public page, and can be accessed by any user

/src/main/webapp/home.xhtml View the entire file <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <body> <ui:fragment rendered="#{identity.loggedIn}"> <meta http-equiv="Refresh" content="0; URL=protected/private.jsf"/> </ui:fragment> <ui:fragment rendered="#{not identity.loggedIn}"> <h:form> <p> This is a public resource. </p> <p> Click <h:outputLink value="protected/private.jsf">here</h:outputLink> here to access the protected resources. </p> Tip: you can login with a username/password of jane/abcd1234. </h:form> </ui:fragment> </body> </html>

Files in the protected folder are secured by PicketLink (default configuration), and cannot be accessed until the user has successfully logged in:

/src/main/webapp/protected/private.xhtml View the entire file <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <body> <p>Hi <b>#{identity.account.loginName}</b>, this resource is protected. If you reach this page is because you're authenticated.</p> <p>Click here to <a href="#{request.contextPath}/logout">Logout</a></p> </body> </html>

Try it out!

It’s now time to deploy the application to WildFly (a Java EE standards compliant web-server), where you can try the application for yourself!

How did it go? What problems did you run in to? How could this example be made simpler? Let us know! For more examples on how to use PicketLink with many other frameworks like 2-factor authentication, SSO with Twitter, Google, and Facebook, check out the rest of the quickstarts: https://github.com/jboss-developer/jboss-picketlink-quickstarts