Create a User Lockout Policy with Access Policy Manager

This article will cover a simple access policy that when completed will lock out a user using BIG-IP Access Policy Manager.  Start by making an access policy with the Device Wizard. Since I just want to make a quick and easy example, I’ll be using the fourth radio option, Web Application Access Management for Local Traffic Virtual Servers.

Create a virtual server via the wizard or use an existing virtual server if you already have a HTTPS virtual server. I called my Policy “Lockout” and I disabled the Antivirus Check just because I don’t want to crowd my access policy.

I chose Active Directory as my authentication factor but feel free to use what you like. Next, create a virtual server if you don’t already have one. I have one already but if didn’t, I would do the following.

Review the configuration and before finishing the wizard, click on Edit Access Policy in Visual Policy Editor.

Your access policy should look like the following. First change the Max Logon Attempts Allowed to one.

Next, I just added a Lockout macro (I need to be more creative with the naming scheme). Our macro will only consist of one block but for the sake of encapsulation, I made it into a macro in case in the future we want to add something else to it.

In the macro, create a new iRule Event with ID “lookup user” and with the following branch rules.

NameExpression
Lockout userexpr { [mcget {session.custom.badpwdcount}] >= [mcget {session.custom.lockout}] }
Can allow throughexpr { [mcget {session.custom.badpwdcount}] < [mcget {session.custom.lockout}] }

Now add some more appropriate terminals to our macro since the default “Out” is not very descriptive.

Great, now just add the macro between the Logon Page and the AD Auth. The AD Auth is most likely on the Lockout branch but we can easily move it to the correct, Allow Through, branch by clicking on the little down arrow on the AD Auth block.

Now that everything is in place, we should edit the endings of the access policy so that it would make more sense. Right now we only have Allow and Deny but we should add something like a Lockout with more information for the user. Don’t forget to attach the lockout ending to the lockout branch (use a different name if you want).

Error TitleError Message
You’ve been locked out, %{session.logon.last.username}Please try again in %{session.custom.timeout} minutes.

In the Error title, I added a session variable that personalizes the lockout. Also, I added a custom session variable I added in iRules that lets the users know how much more they have to wait to try again. Apply the access policy and finish the device wizard. The final step is to attach the iRule below.

when ACCESS_POLICY_AGENT_EVENT {
  set user [ACCESS::session data get session.logon.last.username]
  if {[ACCESS::policy agent_id] eq "lookup user"} {
    # The lockout and timeout variables are customizable here. 
    # The lockout variable determines how many times a user may try
    # before getting locked out. The timeout variable determines how
    # long a user has to wait until they can come out of their lockout.
    set lockout 5
    set timeout 900
    # We do not want to touch (reset the timer) the user unless we know
    # for sure that this user’s bad password count has not exceeded the
    # lockout number.
    set badpwd [table lookup -notouch $user]
    if {$badpwd == {}} {
      table add $user 0 $timeout
    } elseif {$badpwd < $lockout} {
      table lookup $user
    }
    ACCESS::session data set session.custom.badpwdcount $badpwd
    ACCESS::session data set session.custom.lockout $lockout
    ACCESS::session data set session.custom.timeout [expr {[table timeout -remaining $user] / 60}]
  }
}
# When the policy completed we want to check the authentication results.
# If the user failed, we want to increment their bad password count. If 
# they have succeeded logon, we want to remove them from the session table. 
when ACCESS_POLICY_COMPLETED {
  set user [ACCESS::session data get session.logon.last.username]
  set result [ACCESS::session data get session.ad.last.authresult]
  # If we never went to authentication, the auth result would be null 
  # and we don’t want to do anything in that case.
  if {$result == ""} {
    return
  } elseif {$result} {
    table delete $user
  } else {
    table incr $user
  }
}

A failed login should result in this screen:

Thanks again to ystephie for another great solution!

About the Author

image

 

Stephanie is a summer intern at F5, heading back to school soon to continue her EECS degree at UC Berkeley, and has been having a blast creating interesting solutions for BIG-IP. Stephanie’s passion for engineering, and smile, is contagious.

Published Aug 26, 2011
Version 1.0

Was this article helpful?

4 Comments

  • Great article! I wound up using this while using APM to proxy ActiveSync. I used your article to emulate the lockout functionality of TMG (http://blogs.technet.com/b/isablog/archive/2012/11/01/using-the-account-lockout-feature-in-tmg-2010.aspx).
  • HI , I have tried the same as mentioned but its not working for me. I have been through the document multiple times, where should we assign these variables. where should we declare session.custom.badpwdcount session.custom.lockout
  • Is it possible to lockout a number of users based on a time period of not having signed in? say a month.