Technical Challenge

Recently I touched on a problem that F5 IT was facing with Two-Factor Authentication (TFA) and VPN clients that didn’t support it (Two-Factor Authentication - Captive Portal). I figured this would be a great opportunity to talk about another interesting challenge IT is experiencing, end users have expressed a desire to access internal resources without the need to establish a Full-VPN tunnel.

This problem could be solved with BIG-IP APM using either Portal Access or an App Tunnel but I wanted to approach it from a different angle. Reading through the release notes for 11.6 I noticed a feature that would enable remote employees to connect directly to either a workstation or our internal Remote Desktop Services (RDS) cluster.

Native MSRDP Support - This feature provides native support for Microsoft RDP clients to connect to backed resources without establishing a VPN Tunnel. In other words the BIG-IP APM is now able to act as an Remote Desktop Gateway.

Okay here comes the curve ball, to keep the security-team happy the only way they would bless this service is if it required TFA. No big deal right, TFA has been around since 1984……

Looking at the Remote Desktop Connection application answered my TFA question real quick.

The supported login methods are NTLM or Smart Cards (Oh Joy, my liquor cabinet is going to need a refill after this one). So how do you add TFA to NTLM?

Capture-RDG01

The Solution

The answer is YOU DON’T, my initial thought process was maybe some type of Password+Token concatenation solution but then I remembered how NTLM worked. And at that point I realized that if the employee concatenated their password and token it would break the NTLM Authentication process.

  1. (Interactive authentication only) A user accesses a client computer and provides a domain name, user name, and password. The client computes a cryptographic hash of the password and discards the actual password.
  2. The client sends the user name to the server (in plaintext).
  3. The server generates a 16-byte random number, called a challenge or nonce, and sends it to the client.
  4. The client encrypts this challenge with the hash of the user's password and returns the result to the server. This is called the response.
  5. The server sends the following three items to the domain controller:
      • User name
      • Challenge sent to the client
      • Response received from the client
  6. The domain controller uses the user name to retrieve the hash of the user's password from the Security Account Manager database. It uses this password hash to encrypt the challenge.
  7. The domain controller compares the encrypted challenge it computed (in step 6) to the response computed by the client (in step 4). If they are identical, authentication is successful.

So now that we have determined that modifying the credentials on the client is a non-starter what’s left? Well what if the employee validated their Username, Password & TFA Token against a website and that session was used to satisfy the TFA requirement for RDG?

That just might work, here is what it would look like.

  1. Employee browses to a secure page hosted on the same BIG-IP APM that will act as the Remote Desktop Gateway (RDG)
    1. The employee provides a valid Username, Password & TFA Token
    2. After the credentials are validated a session is created and the session is marked valid for a given period of time
  2. Next the employee launches their preferred RDP application and connects to the Fully Qualified Domain Name of the RDG
    1. The employees credentials are validated again against RDG
    2. After the credentials are validated the BIG-IP APM checks it’s local session table for all active sessions with the same username and client-ip to see if any of them have recently completed TFA
    3. If a session is found the employee’s RDP request is proxied through RDG, if not their RDG session is terminated and an error message is displayed.

*NOTE – For more information on using the BIG-IP APM RDG function please see

Putting Everything Together

  • This section will assume that you have completed the F5 Microsoft Remote Desktop Gateway Servers Deployment Guide referenced above.
  • That you have configured the required Active Directory AAA resource that will be used for Username/Password Validation
  • That you have configured the required Radius AAA resource that will be used for TFA Token Validation
    • Other AAA resources beyond Radius are supported but for this guide I will use Radius

Step 1 – Update the “rdg-apm-access” Access Policy

At this point you should have a VPE policy that looks similar to the image below

Capture-RDG02

Now we need to add a second logic branch to the fallback section of the policy to handle web based authentication for employees. This branch will validate their TFA token.

Step 1.1 – Adding a Logon Page

Under the fallback option for “Client Type” resource and a new “Logon Page” resource and configure field 3 to collect your OTP information

Capture-RDG03

*NOTE – I configured field 3 to store the entered value as otp, this id will be required later when we validate the provided token against the radius server

Capture-RDG04

Step 1.2 – Validating the Username & Password

Next add the AAA resource that will handle Username and Password validation.

Capture-RDG05

Capture-RDG06

Step 1.3 – Validating the TFA Token

After the Username and Password are validated you will need to update the password session variable so that it contains the OTP value. The Radius AAA resource will expect the OTP value to be stored in the password variable

Capture-RDG07_1

Capture-RDG07_2

Capture-RDG07

Next add the AAA resource that will handle OTP validation and update the successful result to Allow.

Capture-RDG07_3

Capture-RDG07_4

*NOTE – You can add a second Logon Page and Radius Auth to the fallback path of the “Radius Auth” resource to allow employees to retry just their OTP token on Radius Failure.

*NOTE – To keep the TFA session active you should add an Advanced Resource Assign object to the successful branch of the Radius Auth path. The advanced resource object should contain a Webtop object and one other resource (a webtop link would work). This way as long as the TFA webtop is open the session will remain active, communicate to your employees that in order to use the RDG feature the TFA webtop must be open. You could use a custom session table to store this information but I wanted to keep this section simple. For more information on session tables take a look at => https://devcentral.f5.com/wiki/iRules.session.ashx

Step 2 – Two-Factor Validation for RDG

This iRule should be applied to the virtual that employees will use as their Remote Desktop Gateway

when ACCESS_POLICY_COMPLETED {
	## Checks to see if the employee has succesfully authenticated to the RDG using NTLM
	if {[ACCESS::policy result] eq "allow"}
	{
		
		## Stores the username associated to this session as a variable
		set s_username	[ACCESS::session data get session.logon.last.username]
		## Stores the Access Profile name as a variable
		set s_profile	[PROFILE::access name]
		
		## Enumerate all Session ID's active on this profile for the provided username
		set a_uuid		[ACCESS::uuid getsid "$s_profile.$s_username"]
		
		## Set the variable that will be used to identify completed TFA to fail
		set b_tfa		0
		
		## Loop through each Session ID to see if it contains a valid TFA
		foreach s_uuid $a_uuid {
			
			## Store the Client IP associated to the current loop as a variable
			set s_clientip	[ACCESS::session data get -sid $s_uuid session.user.clientip]
			
			## Store the Radius Result associated to the current loop as a variable
			set b_radius	[ACCESS::session data get -sid $s_uuid session.radius.last.result]
			
			## Check to see if the Client-IP associated to the session UUID matches the current request ip
			## Check to see if the session has passed Radius Authentication
			if {$s_clientip eq [IP::client_addr] && $b_radius}
			{
				## Since we have found an active session that has completed TFA
				## we need to update the variable created earlier
				set b_tfa	1
				
				## Exit the ForEach Loop
				break
			}
		}
		
		## Check to see if the employee has passed TFA
		if {!($b_tfa)}
		{
			## If the employee has not passed TFA prevent them from connecting to the RDG and return a 500 error message
			## Note the RDG failure may not be obvious to the employee
			ACCESS::respond 500 content "Please complete Two-Factor Authentication prior to establishing an RDG Connection"
		}
	}
}