Two Factor Authentication with Freeradius for Horizon View

At work we were evaluating different options to enable two factor authentication for VMware Horizon View. They were all more than we were interested in paying and none had the ability to integrate with the communication platforms that we were interested in utilizing for delivering the PIN used as the “second factor”. Given that, my director gave me the opportunity to innovate and develop something custom.

Before we get started, you should know that I will not be providing a complete solution for two factor authentication with freeradius. My intention in this post is to demonstrate a working example of freeradius issuing an Access-Challenge response to a VMware View authentication request to achieve two factor authentication. Further development will be necessary to provide a full “solution”. (Integrating the freeradius perl module with LDAP or some other central authentication mechanism as well as deliver PINs and validate them.) If you have any questions in regards to how I achieved this, feel free to ask in the comments.

I had been looking for a good reason to play with freeradius and I finally had one. After some research within VMware’s documentation I knew I needed to learn how to get freeradius to send an “Access-Challenge” response.

https://pubs.vmware.com/view-52/index.jsp?topic=%2Fcom.vmware.view.administration.doc%2FGUID-73027CC6-8EA6-4887-A1F7-B40BF664E353.html
“If the RADIUS server issues an access challenge, View Client displays a dialog box similar to the RSA SecurID prompt for the next token code.”

Unfortunately, getting freeradius to do this is not well documented, but here are a few links I used for my research:
http://wiki.freeradius.org/guide/multiOTP-HOWTO
https://lists.freeradius.org/pipermail/freeradius-users/2008-August/030680.html
http://motp.sourceforge.net/
http://lists.freeradius.org/pipermail/freeradius-users/2011-January/051466.html
https://www.howtoforge.com/how-to-use-freeradius-with-linotp-2-to-do-two-factor-authentication-with-one-time-passwords
http://lists.freeradius.org/pipermail/freeradius-users/2012-May/060929.html
http://techtitude.blogspot.com/2014/12/freeradius-pap-challenge-authentication.html
http://lists.freeradius.org/pipermail/freeradius-users/2009-February/035675.html
http://www.mail-archive.com/freeradius-users@lists.freeradius.org/msg47441.html
http://lists.freeradius.org/pipermail/freeradius-users/2013-February/065099.html

I also read a few chapters from this book to get a better understanding of the configuration and inner workings of freeradius.

After all my research I used the example.pl code that comes with the freeradius perl module and modified the authenticate function like so:

sub authenticate {
        # For debugging purposes only
#       &log_request_attributes;
        if ($RAD_REQUEST{'State'} eq "0x6368616c6c656e6765") {
                if($RAD_REQUEST{'User-Password'} eq "1234") {
                        $RAD_REPLY{'Reply-Message'} = "Access granted";
                        return RLM_MODULE_OK;
                } else {
                        $RAD_REPLY{'Reply-Message'} = "Denied access by rlm_perl function";
                        return RLM_MODULE_REJECT;
                }
        } else {
                if($RAD_REQUEST{'User-Name'} eq "testusernamehere" && $RAD_REQUEST{'User-Password'} eq "testpasswordhere") {
                        $RAD_REPLY{'State'} = "challenge";
                        $RAD_CHECK{'Response-Packet-Type'} = "Access-Challenge";
                        $RAD_REPLY{'Reply-Message'} = "Enter your PIN.";
                } else {
                        $RAD_REPLY{'Reply-Message'} = "Denied access by rlm_perl function";
                        return RLM_MODULE_REJECT;
                }
        }
}

The code above is extremely bare-bones and serves only as an example to use the perl module with freeradius to send an authenticator an Access-Challenge response to an authentication request. You will want to modify the “testusernamehere” and “testpasswordhere” strings to something more appropriate and optionally the “1234” test PIN. This code first authenticates a user by validating their username and password. If it is successful, an Access-Challenge response is sent to the authenticator and the “State” AVP (Attribute-Value Pair) is set to “challenge”. When the authenticator receives the Access-Challenge it prompts for a PIN. When the PIN is entered, the request is processed by the first block of code because the text value of the “State” AVP (challeng) now matches the hexadecimal string “0x6368616c6c656e6765” in the first if statement. This happens because in the previous request we set the State AVP to be equal to “challenge” which is the text equivalent to the hexadecimal string “0x6368616c6c656e6765”. The same User-Name is sent as used previously, but this time User-Password must match “1234”. Any other PIN will cause authentication to fail.

Here are screenshots of the Horizon View client authentication behavior using a freeradius server with this configuration.

two factor authentication vmware view first factor

two factor authentication vmware view second factor