January 16th, 2015 by Lincoln Baxter III

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 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:

<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.
/src/main/java/example/HttpSecurityConfiguration.javaView 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 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.javaView 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.xhtmlView 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.xhtmlView 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.xhtmlView 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.xhtmlView 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

Posted in JBoss, JSF2, Rewrite, Security

11 Comments

  1. Michael Davis says:

    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,

    1. Michael Davis says:

      Oops – looks like I copy/pasted it wrong – of course the logout call comes after the request.getSession()!

    2. Hey Michael,

      I’m glad you’re finding this helpful! The logout code is in the HttpSecurityConfiguration:

      .forPath("/logout")
                          .logout()
                          .redirectTo("/home.jsf")
  2. Ronald van Kuijk says:

    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

    .forPath("/javax.faces.resource/*")
                        .unprotected()

    is ‘required’ to have these components work and look good in an unprotected login page

  3. 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

  4. SMHJamali says:

    How to get current authenticated account in a cdi bean ?

  5. Evandro says:

    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.

  6. Xavier says:

    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

  7. Renato Clementi says:

    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.

  8. […] 20. Simple Java EE (JSF) Login Page with JBoss PicketLink … […]

  9. […] 6. Simple Java EE (JSF) Login Page with JBoss PicketLink … […]

Leave a Comment




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.