7. Remember-me functionality

In this chapter, We create a Java EE 7 JSF application where the credentials can be 'remembered' so that during the next visit to the application, no username and password needs to be supplied.

7.1 Main scenario

The code for this example can be found in the gitbook/ex7 directory of this Git Repository.

7.1.1 Basic Octopus setup

Instead of repeating all the different steps to define the basic requirements of a Java EE 7 JSF application with the Octopus framework, I refer to them in chapter 1. Just repeat the step 1.1.1 to 1.1.6 (included) but use for example the directory name ex7.

Some of the files need a small change and will be explained in the next sections.

7.1.2 Add remember-me checkbox

  • Open the login.xhtml file which was created during the basic setup, and add a 3rd 'row' for the checkbox

      <p:outputLabel for="remember" value="Remember me:"/>
      <p:selectBooleanCheckbox id="remember" value="#{loginBean.remember}" />
    

7.1.3 Set short Session timeout

  • Define a HTTP session timeout within web.xml file of 1 minute.

      <session-config>
          <session-timeout>1</session-timeout>
      </session-config>
    
  • Add default page, handy for the logout functionality of next sections

      <welcome-file-list>
          <welcome-file>/index.xhtml</welcome-file>
      </welcome-file-list>
    

7.1.4 Add logout option

  • Add the following code as body of the /pages/user.xhtml JSF view

      <h:form>
          authenticated user : #{loggedInUser}  <br/>
          <h:commandButton actionListener="#{loginBean.logout}" value="Logout"/>
      </h:form>
    

7.1.5 Test the application

  • Deploy the application on a Java EE 7 compliant application server capable of running on Java 8.
  • Open the browser pointing to the following URL : http:///ex7/index.xhtml
  • Click on the user page link
  • Fill in any username and password information in the login page (username must be equals to password)
  • Make sure the remember-me checkbox is ticked
  • Click on the Login button
  • See if you end up on the user page and see your username displayed here.
  • Wait at least 1 minute
  • Close the browser, only the tab or just type in the URL of the index page http:///ex7/index.xhtml
  • Click on the user page link
  • You will see that the login page is not shown this time and the user page is (with the username you used at the beginning of this test procedure)
  • Click on the logout button.
  • Repeat the above procedure but DO NOT check the checkbox this time.
  • You will see that you need to provide the credentials this time after the time waited.

7.2 Explanation

7.2.1 Basic setup

For an explanation of the steps in the basic setup, I also refer to the explanation which can be found in the sections 1.2.1 through 1.2.6.

7.2.2 remember-me checkbox

This time we foresee a checkbox within the login screen so that we can be remembered and thus that we do not need to provide our credentials each time.

This checkbox needs to be linked to the remember property of the loginBean so that it gets properly set within the UsernamePasswordToken instance.

When the remember-me is detected by Octopus/Apache Shiro, a cookie is prepared which contains the encrypted information about the user. When later on, an anonymous user request is detected, with the correct cookie, the user will be authenticated by means of this cookie. So no username and password need to be entered and verified.

7.2.3 Short session timeout

The short session timeout defined in the web.xml file makes it easier to test. As long as the session is active, the user is still authenticated by the information included in this session. The default is 30 minutes, which is a bit too long if you need to wait.

7.2.4 How does it work

When a successful authentication is performed and the remember-me flag is detected, the user information (PrincipalCollection containing the UserPrincipal from Octopus) is serialized to a byte array. This byte array is then encrypted and stored as a BASE64 encoded value within the cookie.

When the user makes another request with this cookie in the request, it will be used in case no other subject is already authenticated. It is then decrypted, and PrincipalCollection is deserialized from the byte array.

The serialized information takes about 800 bytes and size will increase with the information we put into the userInfo map. (See ??? for an explanation of the userInfo map of the UserPrincipal). When this is encoded into BASE64, it takes more than 1kb.

The encryption is a Block encryption using AES.

The remember-me functionality is not an SSO. Although in theory, you can use the same cookie for authenticating the user with a different application (see the alternative 1) it is not recommended as you have no control if the user is allowed to access the other application or not. Octopus has also an SSO solution which is shown in chapter ???.

When you click on the logout button, or in general, when a logout is performed, the cookie will be cleared. So after a logout, the user will always need to supply his credentials.

7.3 Where to go next

  • Try the alternatives (see 7.4) of this example to learn about the more advanced use case.
  • Learn about the SSO Octopus solution (See ???)
  • Discover the other integrations for authentication (LDAP, OAuth2, ...) (See ???)
  • Learn about the core features of Octopus, Authorization. (See ???)

7.4 Alternatives

This alternative shows the configuration options of the cookie and the best practice of defining the encryption key (otherwise a new key is generated during each application startup)

  • Create an additional shiro configuration file /src/main/resources/shiro_extra.ini with the following contents

[main] securityManager.rememberMeManager.cookie.name = Atbash securityManager.rememberMeManager.cookie.maxAge = 3600 securityManager.rememberMeManager.cipherKey = 2cVtiE83c4lIrELJwKGJUw==

  • Test the application again.
  • Login in where you tick the remember-me checkbox.
  • Restart the server
  • See if you can access the protected user page without the need for credentials.

Additional information

The configuration of the cookie is not yet possible from the Octopus configuration file (this will be provided in a future version) but we can perform it through the Shiro config. By default, the file shiro_extra.ini on the classpath will be used for some additional Shiro configuration (additional to what Octopus generates dynamically)

The cookie name can be verified by looking at the network panel of the developer tools of your browser.

The maxAge is the number of seconds the cookie will be valid after it is created. In the example, it is 1 hour, by default it is 365 days. Important to understand is this lifetime of the cookie. When the user works with your application during 2 hours for example, but the lifetime of the cookie is only 1 hour, he will see the login screen since the cookie is no longer valid.

It is also advised to use a fixed key for the AES encryption. Otherwise, a random key is generated during the deploy of the application. And a new key means the cookies which are encrypted with the old key can't be decrypted and used anymore. The user will see then the login screen, although he has still a valid cookie (and you see also an exception message in the log)

The following program can be used to generate a BASE64 encoded byte array which is usable as key for the AES encryption.

    public class KeyGeneration {

        public static void main(String[] args) {
            SecureRandom secureRandom = new SecureRandom();
            byte[] key = new byte[16];
            secureRandom.nextBytes(key);

            System.out.println(Base64.encodeToString(key));
        }
    }

and can be found within the test directory. It generates a 128-bit key (16*8) and when you need larger key sizes (like, 256 bit) you need to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files on the JVM.

results matching ""

    No results matching ""