Simple Java EE (JSF) Login Page with JBoss PicketLink Security
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
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:
<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
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./** * @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 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.
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.
/** * @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
This file contains a simple JSF form and command button that submits to PicketLink.
<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!<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.)
<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
<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:
<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
Thanks for that!
I’ve got an app running on Wildfly 9, jsf/primefaces. I’m using form-based authentication using the standard security module, not picketlink (at least not directly, I’m not sure if the standard wf uses it by default.)
Anyway, I’m wondering what your logout code looks like? I’ve got a problem where users often have to hit the logout button twice before it logs them out.
I’ve got a servlet, mapped to a url pattern in web.xml, simple and old school, that just does this:
String contextPath = request.getContextPath();
request.logout();
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
and then it redirects to the (protected) home page, which causes the login page to appear half the time. But the other half the time it just goes right through to the home page. Then if you click Logout a second time it works.
I know this isn’t a support column! But I’m just asking, since you posted login code, could you just please post your logout code?
thanks
Michael Davis
Ottawa
Thanks very much,
Oops – looks like I copy/pasted it wrong – of course the logout call comes after the request.getSession()!
Hey Michael,
I’m glad you’re finding this helpful! The logout code is in the HttpSecurityConfiguration:
Maybe it is interesting to note that when using components like PrimeFaces, RichFaces, IceFaces, OpenFaces, AngularFaces (if I forgot one, please let me know), that adding
is ‘required’ to have these components work and look good in an unprotected login page
Hey Ronald,
Yep! That’s a good point. Un-restricting the JSF resource path is important to make sure that images, stylesheets, and javascript can still be loaded properly from the browser. I’ll update that.
~Lincoln
How to get current authenticated account in a cdi bean ?
I’m having the following problem:
The User is with the expired session and fills the data from the form and send.
I need to recover this last action to perform after login with the same information form.
Hi,
Does PicketLink play nice with Rewrite? If I configure PicketLink with something like …authenticateWith().form().loginPage("/login.xhtml") and have some rewriting rule /login.xhtml -> /login, PicketLink redirects on /login.xhtml and not /login.
This could occur if PicketLink SecurityFilter comes before RewriteFilter (which wraps the response) or if PicketLink does not call response.encoreRedirectUrl(). Any idea?
Thanks,
Xavier
I’ve been searching for about a month for a example of how to use Picketlink with Glassfish and i’ve got nothing. You guys could provide us with some.
[…] 20. Simple Java EE (JSF) Login Page with JBoss PicketLink … […]
[…] 6. Simple Java EE (JSF) Login Page with JBoss PicketLink … […]