3. Logout and events

Now that we can do basic authentication and authorization, it is time to have a logout option and feedback on some actions of the user.

There will be 2 parts in this example, each concentrating on one of the topics of this chapter.

3.1 Main scenario - Logout

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

We will add a logout button to the examples we have created earlier. We also add the HTTPSession id value so that we can follow when the Session is invalidated by Octopus.

This text will start from the main scenario from the chapter 1 example.

3.1.1 Add Logout button

We add the logout button to the user page (user is authenticated at that moment)

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

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

3.1.2 Add session info

We also add the session id to the index.xhtml page.

  • Place the following code below the a-tag

      Session id = #{session.id}
    

3.1.3 Add default page

We add a default page for the application.

  • Add following config in the web.xml page

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

3.1.4 test the application

You can test the application

  • Click on that logout button on the user page and see how the index page is shown again.

  • Going to the secured user page needs authentication, so you can test following scenario (for the explanation about the session id values, see 3.2.2)

  • Go to (type in the URL address) index page /index.xhtml

  • Click on the secured link
  • Enter some credentials
  • Click on the logout button (try also scenario without clicking the button)
  • Click again on the secured link on the index page.
  • Enter some credentials, only needed when you have used the logout button in step 4!
  • Open a new tab and go to the index page
  • Click on the secured link
  • Credentials are needed when you haven't logged in already on the first tab.

3.2 Explanation

3.2.1 Add Logout button

The Logout button calls the required code to logout the user. It removes the Principal information and invalidates the HTTPSession.

The application is redirected to the welcome file page (actually there is a redirect to /) afterward. See alternative 1 to define a specific logout page.

Therefore you should not define the action property of the commandButton because octopus defines the following page.

If you want to use this logout functionality in a programmatic way, inject an instance of be.c4j.ee.security.OctopusJSFSecurityContext and call the logout() method.

3.2.2 Add session info

Perform the test scenario described in section 3.1.4 again and look closely at the session ids on the pages.

When we start on the index.xhtml page, we have a sessionId printed.

After we have clicked on the secured link and authenticated yourself with the login page, we see the user page where we have printed the sessionId again. But this time it is a different one. This is because Octopus recreates the HTTPSession when the user logs in.

And when we click on the logout button, we end up on the index page again and now we see another value. During logout, the HTTPSession is also invalidated.

The session recreation during login can be disabled in case the copy of the session attributes gives you some problems. Set the session.invalidate.login to false within the ocotpusConfig.properties file.

3.2.3 Add default page.

Since the default logout action is a redirection to /, adding the welcome file list page make sure the user sees a regular page after he has logged out.

3.3. Main scenario - events

There are various CDI events generated by Octopus, this example shows you the most important ones.

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

We will add various observer methods to track these events.

This text will start with the main scenario from the previous example.

3.3.1 Add Observer methods

  • Create a new class EventObserver
  • Mark it is a CDI Application scoped bean
  • Add methods for the various CDI events and write out their contents.

      @ApplicationScoped
      public class EventObserver {
    
         public void onLogin(@Observes LogonEvent logonEvent) {
    
           System.out.println(String.format("Log in of %s at %s", logonEvent.getUserPrincipal().getName(), new Date()));
         }
    
         public void onLogout(@Observes LogoutEvent logoutEvent) {
    
           System.out.println(String.format("Log out of %s at %s", logoutEvent.getUserPrincipal().getName(), new Date()));
         }
    
         public void onFailure(@Observes LogonFailureEvent failureEvent) {
    
           System.out.println(String.format("Invalid password for %s ", failureEvent.getToken().getPrincipal()));
         }
    
      }
    

3.3.2 Test the application

Test the application and use various scenarios

  • Use a valid password (same as username)
  • Click also on the logout button
  • Use an invalid password (like something else than the username)

And watch the log for the various messages which appear there.

3.4 Explanation

LogonEvent, is thrown when the user has successfully logged on. At that moment, the Shiro Subject isn't updated yet, but all the information is available in the event (UserPrincipal and authenticationInfo from which it is created)

At the moment of the event, the new HTTPSession is already established.

The LogoutEvent is thrown just before the system will remove all the Principal information from the system and the HTTPSession will be invalidated.

The failure event happens in the case when the method SecurityDataProvider#getAuthenticationInfo return null (because the user can't be found) or the CredentialMatcher(s) have decided that the Credentials aren't valid.

3.5 Where to go next

  • Try the alternative/additional (see 3.6) to learn about the specification of a logout page.
  • Look at the advanced permissions which are active during the Events. (see ???)
  • See the chapter about the programmatic way of authenticating a user with the help of Octopus(JSF)SecurityContext (see ???)
  • Have a look at the chapter ??? to see which user is working with the app and how you can manipulate them.

3.6 Alternative/Additional

3.6.1 Specify logout page

In this alternative, I'll show you how you can define a custom logout page.

You can start from the main scenario created in 3.1.

  • Create the octopusConfig.properties file within the src/main/resources directory so that it will be added to the classpath.
  • Add a configuration entry for the logout page definition

      logoutPage = /logout.xhtml
    
  • Create the /logout.xhtml JSF page, and for example following content

       <h2>Logout</h2>
    
       You have been logged out of the application.
    
       <a href="index.xhtml">index</a>
    
  • Test the application.

This time, when you click on the logout button on the user page, the logout page is shown.

Additional info

The value of the configuration value logoutPage is always used to determine the page which needs to be shown after the user logs out. By default, it has the value / which leads to the welcome page to be shown.

Here we have redefined the value and thus we have our custom defined logout page whenever we click the logout button.

3.6.2 Track user actions

This second example isn't really an alternative but an additional example of tracking the end user. In the second part of the main scenario, we saw how we can be informed about log on and log out actions. In this example, we will track every page action of the user.

We start from the code created in the first main scenario.

  • Create a copy of the user.xhtml page and name it anotherPage.xhtml.
  • Add to this page a link back to the user.xhtml page.

      <a href="user.xhtml">To main page</a>
    
  • Add a link on the user.xhtml page to the newly created page.

      <a href="anotherPage.xhtml">To other page</a>
    
  • Create a CDI bean (AuditProcessor.java) to receive the events of user actions.

  • Add the method with an @Observes parameter to receive the event

      @ApplicationScoped
      public class AuditProcessor {
    
          public void onPageAccess(@Observes OctopusAuditEvent auditEvent) {
              UserPrincipal principal = (UserPrincipal) auditEvent.getPrincipal();
              String userName = principal == null ? "Anonymous" :  principal.getUserName();
              System.out.println(String.format("User %s accessed the resource %s from ip address %s with browser %s",
                  userName, auditEvent.getRequestURI(), auditEvent.getRemoteAddress(), auditEvent.getUserAgent()));
          }
       }
    
  • Create the octopusConfig.properties file within the src/main/resources directory so that it will be added to the classpath.

  • Add a configuration entry for the logout page definition

      globalAuditActive=true
    
  • Test the application.

Additional info

When the configuration parameter globalAuditActive is set to true, every URL which is requested on the server results in an OctopusAuditEvent CDI event.

So in the above example, we see various lines in the log. The first few ones are reporting the user as Anonymous because we didn't submit the username and password yet.

Afterward, we see the username, together with the requested URL, IP address (probably 127.0.0.1) and your browser User-Agent information.

results matching ""

    No results matching ""