I've always wanted to find a cost effective way to implement 2-factor authentication. Commercial solutions are expensive, and if you are a small business, you might not want to spend a small fortune on implementing an enterprise solution with hardware tokens. I stumbled across Google Authenticator a while back and started to wonder how it can be used to implement a free 2-factor authentication solution in my lab. I also found a few posts that suggested teaming it up with Freeradius and that's really where this post started.
After several attempts, I've managed to find a quick and easy way to get it working. Well, at first glance you'll probably disagree as this is quite a lengthy post, but the steps required to implement the solution are actually very simple. In this blog post, I've tried to explain each step in order. I do not expect everyone to be a Linux expert, and I kept that in mind whilst writing this post. To be honest, this is version 0.1 of this post and I'll probably expand this post over the next few weeks to include overall solution diagrams and extra information. For now, I've managed to at least write up the steps required to implement the solution.
Overview
This solution is based on CentOS 6.3. You can use any other Linux distribution, but the instructions in this post are CentOS/RHEL specific. We will be using Freeradius, an open source Radius server as the main component. Freeradius will make use of Pluggable Authentication Modules (PAM) and PAM will call upon Google Authenticator which is basically a module that is written for PAM. Google Authenticator will verify a user's password together with a token code that changes every 30 seconds. The user will make use of the Google Authenticator mobile APP to obtain a new token code every time a new login is required.
To finish, we will configure VMware Horizon View to make use of RADIUS authentication, and to contact the Freeradius server whenever a user requests a new connection using the View Client.
Checking DNS:
Before we do anything, we need to be sure tha the server is able to resolve it’s own hostname via DNS.
[root@radiussrv ~]# ping radiussrv PING radiussrv.spiesr.com (192.168.1.19) 56(84) bytes of data. 64 bytes from radiussrv.spiesr.com (192.168.1.19): icmp_seq=1 ttl=64 time=0.034 ms 64 bytes from radiussrv.spiesr.com (192.168.1.19): icmp_seq=2 ttl=64 time=0.041 ms 64 bytes from radiussrv.spiesr.com (192.168.1.19): icmp_seq=3 ttl=64 time=0.044 ms 64 bytes from radiussrv.spiesr.com (192.168.1.19): icmp_seq=4 ttl=64 time=0.041 ms ^C --- radiussrv.spiesr.com ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3199ms rtt min/avg/max/mdev = 0.034/0.040/0.044/0.003 ms
Installing NTP to Ensure Accurate Server Time:
yum install ntp /etc/init.d/ntpd start chkconfig --level 345 ntpd on
Disabling SELinux:
Ah SELinux. SELinux is going to get in our way. We can configure SELinux to work with Freeradius, PAM and Google Authenticator, but for the sake of this document, I’ll just disable SELinux. If you need SELinux, please go and read the SELinux documentation in order to configure it properly.
Also, as the configuration we are about to do, can be tricky, disabling SELinux now will ensure that it’s not the cause of any issues if we run into issues later on.
To disable SELinux in run-time, enter the following command:
setenforce 0
To disable SELinux permanently (persist through reboots), edit the file /etc/selinux/config
Change the line that reads
SELINUX=enforcing
to read
SELINUX=disabled
Disabling the Linux Firewall
Another thing that could get in our way whilst troubleshooting, is the firewall. Let’s disable the Linux iptables firewall now, for both IPv4 and IPv6
service iptables stop service ip6tables stop
We can permanently turn off iptables and prevent it from starting up with the server with the chkconfig command:
chkconfig iptbales off chkconfig iptables off
Ensure that both versions of iptables have been turned off:
chkconfig --list | grep tables ip6tables 0:off 1:off 2:off 3:off 4:off 5:off 6:off iptables 0:off 1:off 2:off 3:off 4:off 5:off 6:off
Installing wget
We will be using wget to download the RepoForge (RPMForge) RPM file in order to install it. Using yum, let’s install wget now:
yum install wget
Installing the RepoForge (RPMForge) Repository
Google Authenticator can generate QR codes that contain the keys used to configure your mobile Google Authenticator app. This is not required, but it does help to quickly and accurately configure your mobile app simply by scanning the generated QR code. QR codes can be generated in Linux using the qrencode library. When generated, the QR code will be displayed on screen or in the SSH session.
Unfortunately, the qrencode library is not included in the standard CentOS/RHEL repositories. It is however located in the RPMForge (now known as RepoForge) repositories. We will now add the RPMForge repository to the server in order to use yum to download and install the library, along with everything else that we’ll need.
Using wget, download the RPMForge Repository RPM file to /var/tmp:
cd /var/tmp wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
With the RPM downloaded, install it with the following command:
rpm --ivh rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
Ensure the RPMForge Repository is available
yum list --enablerepo=rpmforge-extras
Check to see if the qrencode library is available to be installed
yum list qrencode Loaded plugins: fastestmirror, presto Loading mirror speeds from cached hostfile * base: mirrors.vooservers.com * extras: centos.mirroring.pulsant.co.uk * rpmforge: ftp.nluug.nl * updates: mirrors.vooservers.com Available Packages qrencode.x86_64 3.2.0-1.el6.rf rpmforge
Ensuring Linux Build Tools are Installed
When we download the Google Authenticator PAM module later, it will be cloned from a git repository to the local server. This means that we will be downloading source code that we will have to compile and install as binaries. To enable us to compile source code, we need a C compiler and a utility called make. Install all build tools using yum in a single line:
yum install gcc cpp make
Installing Screen
This is not a required component, but I find it very useful. Install screen using yum:
yum install screen
Installing the Required Packages
With the pre-requisites in place, let’s install the software we need to proceed:
yum install pam-devel freeradius freeradius-utils git qrencode
Download Google Authenticator PAM Module Source
We need to download the Google Authenticator source code, compile it and install it. I always use /var/tmp to download files to and to compile from source before installing the compiled software.
Change directory to /var/tmp
cd /var/tmp
Using git, download the entire Google Authenticator project source code by cloning the repository. No need to download and extract tar archives!
git clone https://code.google.com/p/google-authenticator/
Compile and install the Google Authenticator PAM module
cd /var/tmp/google-authenticator/libpam/ make && make install
Configuring Freeradius
Now that Freeradius has been installed, it needs to be configured. Generally the only configuration that’s normally required for Freeraduis is to leave it alone. However, we are not that fortunate. In a nutshell, what we need to do is:
1. Change the user under which radiusd runs
2. Add a user group called disabled. Linux user accounts who are members of this group won’t be able to authenticate with Radius
3. Configure Freeradius to deny access to members of “disabled”
4. Configure Freeradius to use PAM as the default authentication type
5. Enable PAM in the Freeradius configuration
6. Configure a “client” entry for the VMware View Connection Server
The above 6 easy steps will configure Freeradius to make use of PAM, and allow the View Connection Server to send requests to the radius server.
On CentOS/RHEL, the configuration files for Freeraduis is located at /etc/raddb
1. Configuring radiusd To Run As root
Note:
I am always uncomfortable when having to run services as the root user. I always recommend running services/daemons with the lowest possible privileges that it can get away with. However, due to the design of the Google Authenticator PAM module, and the fact that we are trying to authenticate with PAM and Freeradius against Google Authenticator, we have to run the Freeradius daemon (radiusd) as root, and here’s why:
When a user is set up to use Google Authenticator, the user’s private key will be stored in /home/<username>/.google_authenticator. The Freeradius daemon (radiusd) needs to have access to that file in order to read the key and pass authentication. The only user that has such access to all user’s home directories is root. Therefore, in order for radiusd to gain access to the file, it has to run as root.
When I get some time, I will see if I can find a way around this. But for now, this is how it works.
Edit the file /etc/raddb/radius.conf
Find the two lines that read:
user = radiusd group = radiusd
And change them to read:
user = root group = root
Save the radius.conf file and exit the editor.
2. Adding the disabled Group
Back at the bash prompt, create a new user group called "disabled":
groupadd disabled
3. Configuring Freeradius to Deny Access To “disabled”
We now need to configure Freeradius to deny access to members of the disabled group. Edit the /etc/raddb/users file and find the section that reads:
# # Deny access for a group of users. # # Note that there is NO 'Fall-Through' attribute, so the user will not # be given any additional resources. # #DEFAULT Group == "disabled", Auth-Type := Reject # Reply-Message = "Your account has been disabled." #
Uncomment the section to read:
# # Deny access for a group of users. # # Note that there is NO 'Fall-Through' attribute, so the user will not # be given any additional resources. # DEFAULT Group == "disabled", Auth-Type := Reject Reply-Message = "Your account has been disabled." #
Do not yet save and exit the editor. Step 4 will introduce an additional change to the users file
4. Setting PAM as the Default Authentication Type
Now, change the default authentication type to PAM by adding the following line directly underneath the above section (below the uncommented section in the /etc/raddb/users file as described in step 3):
# # Deny access for a group of users. # # Note that there is NO 'Fall-Through' attribute, so the user will not # be given any additional resources. # DEFAULT Group == "disabled", Auth-Type := Reject Reply-Message = "Your account has been disabled." # DEFAULT Auth-Type := PAM
Save the file and exit the editor
5. Enabling PAM Support in FreeRadius
Ok, so we’ve told Freeradius that the default authentication type should be PAM, however PAM is disabled by default in this release of Freeradius, so we will have to enable it.
To enable PAM, edit the /etc/raddb/sites-enabled/default file
Under the Authentication section, locate the following lines:
# # Pluggable Authentication Modules. # pam
Uncomment the line that reads pam:
# # Pluggable Authentication Modules. pam
Save the file and exit the editor.
6. Creating a Client Configuration for the View Connection Server
In order to accept requests from the VMware View Connection server, we need to set up a client for the View Connection server in /etc/raddb/clients.conf
Edit /etc/raddb/clients.conf and locate the following section:
# # You can now specify one secret for a network of clients. # When a client request comes in, the BEST match is chosen. # i.e. The entry from the smallest possible network. # #client 192.168.0.0/24 { # secret = testing123-1 # shortname = private-network-1 #} # #client 192.168.0.0/16 { # secret = testing123-2 # shortname = private-network-2 #}
Add the following lines after the above section. The IP address just after “client” should match the IP address of the VMware View Connection Server. Make a note of the “secret” you specify here, as it will later be needed to configure the View Connection Server to use this Radius server for two-factor authentication. The “shortname” should match that of the View Connection server name
client 192.168.1.24{ secret = testing123-2 shortname = viewconnect }
Save the file and exit the editor.
Configure the Freeradius daemon to start with the server:
chkconfig --level 345 radiusd on
This is all the configuration changes that we need to make to Freeradius. The next step is to configure PAM.
Configuring PAM
We now need to tell PAM to make use the Google Authenticator module. Configuring PAM to use the Google Authenticator module is as simple as editing a single file.
Edit the /etc/pam.d/radiusd file and change the file to look as below:
#%PAM-1.0 #auth include password-auth #account required pam_nologin.so #account include password-auth #password include password-auth #session include password-auth auth requisite pam_google_authenticator.so forward_pass account required pam_unix.so use_first_pass
Starting the Freeradius Daemon In Debug Mode
Start the radiusd daemon in debug mode to see if it starts up without any issues:
radiusd -X
Verify the following:
... adding new socket proxy address * port 35031 Listening on authentication address * port 1812 Listening on accounting address * port 1813 Listening on command file /var/run/radiusd/radiusd.sock Listening on authentication address 127.0.0.1 port 18120 as server inner-tunnel Listening on proxy address * port 1814 Ready to process requests.
If all look well, press Ctrl+C to exit out of debug mode
If the radius server started up and is ready to process requests, we can stop the server and restart it in another screen to complete our initial testing and possible troubleshooting:
service radiusd stop screen –dmS radiusserver radiusd -X
Attach to the radiusserver screen
screen –r radiusserver
Verify the following again to be sure the server has started in a screen without any issues:
... adding new socket proxy address * port 45692 Listening on authentication address * port 1812 Listening on accounting address * port 1813 Listening on command file /var/run/radiusd/radiusd.sock Listening on authentication address 127.0.0.1 port 18120 as server inner-tunnel Listening on proxy address * port 1814 Ready to process requests.
Detatch from the screen:
Press Ctrl+a d (Press Ctrl+A. Release all keys and then press D)
NOTE: The server should now have detached from the screen running the Freeradius debug session and should be back at a prompt. Whilst detached from the screen, the daemon is still running in debug mode and we can reattach to its screen at any time by typing:
screen –r freeradiusserver
Testing the Freeradius + PAM + Google Authenticator implementation
We can test the radius server using radtest, a utility that was installed as part of the freeradius-utils package earlier. In order to do any kind of testing, we need a user to test against.
Add a user in order to test out 2-factor authentication. The users will be Linux users and authentication will require the Linux user password combined with the One Time Password generated by the user’s APP on his mobile phone.
Create a test user with the username “testuser” and assign password123 as the users’ password:
useradd testuser passwd testuser password123 password123
Let’s configure the new user to make use of Google Authenticator:
Log in as the user
su testuser
Ensure that we are in the testuser home directory and start the Google Authenticator configuration for the user by entering:
cd ~ google-authenticator
The google-authenticator command will launch a wizard that will generate a key for the user as well as a QR code. As the code is too large to display in the post, I took a screen grab and resized it between line1 and line 2 in the code blocks below:
Do you want authentication tokens to be time-based (y/n) y
Image may be NSFW.
Clik here to view.
Your new secret key is: GGQS2OFTRGK5B4VE Your verification code is 935687 Your emergency scratch codes are: 48439961 69903227 75907760 40390365 23419041 Do you want me to update your "/home/testuser/.google_authenticator" file (y/n)y Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y By default, tokens are good for 30 seconds and in order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of 1:30min to about 4min. Do you want to do so (y/n) n
Setting up Google Authenticator on a Mobile Device
At the time of writing, Google Authenticator supports Android, iOS and Blackberry devices. Download the mobile all “Google Authenticator” from the relevant marketplace on your mobile device. Once installed, scan the provided QR code generated by your server. This will add an account to your mobile app that corresponds with the user account on the server:
Image may be NSFW.
Clik here to view.
The APP will generate a new six-digit code around every 30 seconds.
Now that we have created a new user, created a Google Authenticator token for the user and have our APP generating a new code every 30 seconds, we can test the configuration using radtest.
Exit the user account and revert to root by typing ‘exit’
[testuser@radiussrv ~]$ exit exit [root@radiussrv pam.d]#
Test the configuration with the following command syntax:
radtest <username> <password>+<Google OTP> <radiusservername>:<port> <nas-port> <clientsecret>
The nas-port parameter value is not important. Enter 10 here. It do just fine.
[root@radiussrv pam.d]# radtest testuser password123430876 localhost:1812 10 testing123 Sending Access-Request of id 4 to 127.0.0.1 port 1812 User-Name = "testuser" User-Password = "password123430876" NAS-IP-Address = 192.168.1.19 NAS-Port = 10 Message-Authenticator = 0x00000000000000000000000000000000 rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=4, length=20
If you have followed the steps properly, you should see an “Access-Accept” packet. If so, the configuration is working fine.
Troubleshooting
If the configuration doesn’t work, it could be one of many things. I would check the following:
- Ensure that the time on the mobile device running the Google Authenticator APP is within 30 seconds of that of the server.
- Check the /var/log/radius/radius.log file for any errors.
- Check the radius debug screen for any errors.
Configuring VMware View to authenticate using the new Freeradius server:
- Open a web browser to and navigate to the View Admin portal (https://<view-connection-server>/admin)
- Log in as an administrator.
- On the left hand side, expand the “View Configuration” section and click “Servers”
- Click on the “Connection Servers” tab and select the Connection Server to be configured
- Click the edit button
- The Edit View Connection Server Settings dialog appears. Click the “Authentication” tab
- Under “Advanced Configuration”, select “RADIUS” from the drop down list next to “2-factor authentication”
- Next to “Authenticator”, select “Create New Authenticator” from the drop down list
Image may be NSFW.
Clik here to view.
Now, let's set up the new authenticator:
- Enter the label for the connection. This will be displayed in the View Client Connection Dialog.
- Enter a description
- Enter the IP address of the Freeradius server
- Enter the secret as specified in the clients.conf file. If they don’t match, authentication won’t work.
Image may be NSFW.
Clik here to view.
Testing VMware View Radius Authentication
- Open the View Client and attempt to connect.
- Enter the Linux username
- Enter the Linux User password followed by the OTP displayed on the Google Authenticator mobile app.
Image may be NSFW.
Clik here to view.