Technical Article

Two-Factor Authentication With Google Authenticator And APM

Two-factor authentication (TFA) has been around for many years and the concept far pre-dates computers. The application of a keyed padlock and a combination lock to secure a single point would technically qualify as two-factor authentication: “something you have,” a key, and “something you know,” a combination. Until the past few years, two-factor authentication in its electronic form has been reserved for high security environments: government, banks, large companies, etc. The most common method for implementing a second authentication factor has been to issue every employee a disconnected time-based one-time password hard token. The term “disconnected” refers to the absence of a connection between the token and a central authentication server. A “hard token” implies that the device is purpose-built for authentication and serves no other purpose. A soft or “software” token on the other hand has other uses beyond providing an authentication mechanism. In the context of this article we will refer to mobile devices as a soft tokens. This fits our definition as the device an be used to make phone calls, check email, surf the Internet, all in addition to providing a time-based one-time password.

A time-based one-time password (TOTP) is a single use code for authenticating a user. It can be used by itself or to supplement another authentication method. It fits the definition of “something you have” as it cannot be easily duplicated and reused elsewhere. This differs from a username and password combination, which is “something you know,” but could be easily duplicated by someone else. The TOTP uses a shared secret and the current time to calculate a code, which is displayed for the user and regenerated at regular intervals. Because the token and the authentication server are disconnected from each other, the clocks of each must be perfectly in sync. This is accomplished by using Network Time Protocol (NTP) to synchronize the clocks of each device with the correct time of central time servers.

Using Google Authenticator as a soft token application makes sense from many angles. It is low cost due to the proliferation of smart phones and is available from the “app store” free of charge on all major platforms. It uses an open standard (defined by RFC 4226), which means that it is well-tested, understood, secure. Calculation as you will later see is well-documented and relatively easy to implement in your language of choice (iRules in our case). This process is explained in the next section.

This Tech Tip is a follow-up to Two-Factor Authentication With Google Authenticator And LDAP. The first article in this series highlighted two-factor authentication with Google Authenticator and LDAP on an LTM. In this follow-up, we will be covering implementation of this solution with Access Policy Manager (APM). APM allows for far more granular control of network resources via access policies. Access policies are rule sets, which are intuitively displayed in the UI as flow charts. After creation, an access policy is applied to a virtual server to provide security, authentication services, client inspection, policy enforcement, etc. This article highlights not only a two-factor authentication solution, but also the usage of iRules within APM policies. By combining the extensibility of iRules with the APM’s access policies, we are able to create virtually any functionality we might need.

Note: A 10-user fully-featured APM license is included with every LTM license. You do not need to purchase an additional module to use this feature if you have less than 10 users.

Calculating The Google Authenticator TOTP

The Google Authenticator TOTP is calculated by generating an HMAC-SHA1 token, which uses a 10-byte base32-encoded shared secret as a key and Unix time (epoch) divided into a 30 second interval as inputs. The resulting 80-byte token is converted to a 40-character hexadecimal string, the least significant (last) hex digit is then used to calculate a 0-15 offset. The offset is then used to read the next 8 hex digits from the offset. The resulting 8 hex digits are then AND’d with 0x7FFFFFFF (2,147,483,647), then the modulo of the resultant integer and 1,000,000 is calculated, which produces the correct code for that 30 seconds period.

Base32 encoding and decoding were covered in my previous Tech Tip titled Base32 Encoding And Decoding With iRules. The Tech Tip details the process for decoding a user’s base32-encoded key to binary as well as converting a binary key to base32.

These two pieces of code contribute the bulk of the processing of the Google Authenticator code. The rest is done with simple bitwise and arithmetic functions.

Triggering iRules From An APM Access Policy

Our previously published Google Authenticator iRule combined the functionality of Google Authenticator token verification with LDAP authentication. It was written for a standalone LTM system without the leverage of APM’s Visual Policy Editor. The issue with combining these two authentication factors in a single iRule is that their functionality is not mutually exclusive or easily separable. We can greatly reduce the complexity of our iRule by isolating functionality for Google Authenticator token verification and moving the directory server authentication to the APM access policy.

APM iRules differ from those that we typically develop for LTM. iRules assigned to LTM virtual server are triggered by events that occur during connection or payload handling. Many of these events still apply to an LTM virtual server with an APM policy, but do not have perspective into the access policy. This is where we enter the realm of APM iRules. APM iRules are applied to a virtual server exactly like any other iRule, but are triggered by custom iRule event agent IDs within the access policy. When the access policy reaches an iRule event, it will trigger the ACCESS_POLICY_AGENT_EVENT iRule event. Within the iRule we can execute the ACCESS::policy agent_id command to return the iRule event ID that triggered the event. We can then match on this ID string prior to executing any additional code. Within the iRule we can get and set APM session variables with the ACCESS::session command, which will serve as our conduit for transferring variables to and from our access policy. A visual walkthrough of this paragraph is shown below.

iRule Trigger Process

Create an iRule Event in the Visual Policy Editor

Specify a Name for the object and an ID for the Custom iRule Event Agent

Create an iRule with the ID referenced and assign it to the virtual server

Add branch rules to the iRule Event which read the custom session variable and handle the result

Google Authenticator Two-Factor Authentication Process

Two-Factor Authentication Access Policy Overview

Rather than walking through the entire process of configuring the access policy from scratch, we’ll look at the policy (available for download at the bottom of this Tech Tip) and discuss the flow. The policy has been simplified by creating macros for the redundant portions of the authentication process: Google Authenticator token verification and the two-factor authentication processes for LDAP and Active Directory.

The “Google Auth verification” macro consists of an iRule event and 5 branch rules. The number of branch rules could be reduced to just two: success and failure. This would however limit our diagnostic capabilities should we hit a snag during our deployment, so we added logging for all of the potential failure scenarios. Remember that these logs are sent to APM reporting (Web UI: Access Policy > Reports) not /var/log/ltm. APM reporting is designed to provide per-session logging in the user interface without requiring grepping of the log files.

The LDAP and Active Directory macros contain the directory server authentication and query mechanisms. Directory server queries are used to retrieve user information from the directory server. In this case we can store our Google Authenticator key (shared secret) in a schema attribute to remove a dependency from our BIG-IP. We do however offer the ability to store the key in a data group as well.

The main portion of the access policy is far simpler and easier to read by using macros. When the user first enters our virtual server we look at the Landing URI they are requesting. A first time request will be sent to the “normal” logon page. The user will then input their credentials along with the one-time password provided by the Google Authenticator token. If the user’s credentials and one-time password match, they are allowed access. If they fail the authentication process, we increment a counter via a table in our iRule and redirect them back to an “error” logon page. The “error” logon page notifies them that their credentials are invalid. The notification makes no reference as to which of the two factors they failed. If the user exceeds the allowed number of failures for a specified period of time, their session will be terminated and they will be unable to login for a short period of time. An authenticated user would be allowed access to secured resources for the duration of their session.

Deploying Google Authenticator Token Verification

This solution requires three components (one optional) for deployment:

In the New Virtual Server form, fill in the Name, Destination address, Service Port (should be HTTPS/443), next select an HTTP profile and anSSL Profile (Client).

Next you’ll add a SNAT Profile if needed, an Access Profile, and finally the token verification iRule

Depending on your deployment you may want to add a pool or other network connectivity resources

Finally click Finished

At this point you should have a function virtual server that is serving your access policy. You’ll now need to add some tokens for your users. This process is another section on its own and is listed below.

Generating Software Tokens For Users

In addition to the Google Authenticator Token Verification iRule for APM we also wrote a Google Authenticator Soft Token Generator iRule that will generate soft tokens for your users. The iRule can be added directly to an HTTP virtual server without a a pool and accessed directly to create tokens. There are a few available fields in the generator: account, pre-defined secret, and a QR code option. The “account” field defines how to label the soft token within the user’s mobile device and can be useful if the user has multiple soft token on the same device (I have 3 and need to label them to keep them straight). A 10-byte string can be used as a pre-defined secret for conversion to a base32-encoded key. We will advise you against using a pre-defined key because a key known to the user is something they know (as opposed to something they have) and could be potentially regenerate out-of-band thereby nullifying the benefits of two-factor authentication. Lastly, there is an option to generate a QR code by sending an HTTPS request to Google and returning the QR code as an image. While this is convenient, this could be seen as insecure since it may wind up in Google’s logs somewhere. You’ll have to decide if that is a risk you’re willing to take for the convenience it provides.

Once the token has been generated, it will need to be added to a data group on the BIG-IP:

Navigate to Local Traffic > iRules > Data Group Lists

Select Create from the upper right-hand corner if the data group does not yet exist. If it exists, just select it from the list.

Name the data group “google_auth_keys” (data group name can be changed in the beginning section of the iRule)

The type of data group will be String

Type the “username” into the String field and paste the “Google Authenticator key” into the Value field

Click Add and the username/key pair should appear in the list as such: user := ONSWG4TFOQYTEMZU

Click Finished when all your username/key pairs have been added.

Your user can scan the QR code or type it into their device manually. After they scan the QR code, the account name should appear along with the TOTP for the account. The image below is how the soft token appears in the Google Authenticator iPhone application:

Once again, do not let the user leave with a copy of the plain text key. Knowing their key value will negate the value of having the token in the first place. Once the key has been added to the BIG-IP, the user’s device, and they’ve tested their access, destroy any reference to the key outside the BIG-IPs data group.If you’re worried about having the keys in plain text on the BIG-IP, they can be encrypted with AES or stored off-box in LDAP and only queried via secure connection. This is beyond the scope of this article, but doable with iRules.

The sample doesn't seem to work anymore, but here's the steps for creating an APM policy for AD + Google auth
1. Login page. For field #3, change it to a text type, and change the session and post variable names to ga_code_attempt. Change "Logon Field Input #3" to "Google Auth"
2. AD Auth. Set up to auth against your domain controller
3. AD Query for object attribute. Add a required attribute for wherever you are storing the shared key. For testing, I put mine in the 'mobile' attribute for my user account. Yes, I know this is not secure. Delete the default branch rule, create a new one. Call it "Has shared key". Condition is "Active Directory Query has passed".
4. Create an iRule Event object attached to the "Has shared key" branch. Call this "Google Auth verify". For the id, enter "ga_code_verify". Delete the default branch rule. For simplicity's sake just create 1 branch. Call the first one "Success". Go to Advanced enter the expression "expr { [mcget {session.custom.ga_result}] == 0}". Fallback shouuld go to a Deny
5. Attach your resource assigns and ALLOW statement to the Success branch.
Assign this APM policy to a virtual server, add the google_auth_verify_apm iRule to the server. Modify the iRule as instructed above to change ga_key_storage to 'ad' and ga_key_ad_attr to whatever attribute you're using ('mobile' in my case).
Generate your shared secret and paste it into your user attribute and test. Works like a charm. Make sure that the clock on your F5 is using NTP as the the time needs to be accurate.

The iRule is now working as expected (I added some log statements to catch the userid/code entered/code calculated/return value.
However, the branch rules aren't working. I get an error "Rule evaluation failed with error: invalid command name "expr { 0 == 0}".

Been using this code for awhile now and one of the things i noticed is some of the time on people's device are off by a few seconds that can mess with the token on their end. Is it possible to modify this code so that its checks what they enter, fail it and then run the code again but this time run the code with "time-30 seconds" so that it basically approves the token that is valid right now and the token that was valid before.

Hey All, Sample access policy is importable on the BIG-IP 11.3. No error by doing that. From there you can upgrade the BIG-IP to higher versions, or manually replicate the configuration on another BIG-IP such as 11.6 or 12. I am currently doing this on the 12.0 and it is working out fine.

I am using this for a web based service. The VPE configured is a follows:

Macro configuration is:

While testing it seems to be directed to the fallback branch in the macro ultimately resulting in a deny
I am using the Google Authenticator Soft Token Generator code with another VS for linking with google authenticator app. The key generated that particular VS is added to the data group. What am I missing ?

I just noticed that if the user mapping is removed from the data-group then the macro always directs the session to branch2 (No google auth key found). however if the user mapping is present in the data-group the session always directs to fallback branch. Any ideas what might be the issue?

0

About DevCentral

We are a community of 300,000+ technical peers who solve problems together.