ADFS 3.0, WAP, SNI and Network Load Balancing

So you decide to build an ADFS 3.0 farm using Windows Server 2012 R2. You configure the farm properly and the ADFS checks performed directly on the ADFS servers are working fine.

The next step is to load balance the traffic between the two ADFS nodes. To achieve this functionality you will use a NLB solution. Let’s assume you will use IIS + ARR.
Please note this scenario is valid also for other NLB solutions. I mention here IIS + ARR for the simple fact IIS + ARR are Microsoft solutions and a lot of companies are leveraging first the Microsoft solution (before looking into alternatives).

After you properly configure the IIS + ARR to load balance the traffic between the two ADFS servers, you try to verify the connection usually by connecting at https://[yourSTSfqdn]/adfs/ls/idpinitiatedsignon.htm, but you receive a HTTP 502.

502 – Web server received an invalid response while acting as a gateway or proxy server.

There is a problem with the page you are looking for, and it cannot be displayed. When the Web server (while acting as a gateway or proxy) contacted the upstream content server, it received an invalid response from the content server.

The page will be available soon.

 ADFS_3.0_WAP_SNI_and_Network_Load_Balancing_01

What’s the reason?
ADFS 3.0 (part of Windows Server 2012 R2) is by default setup (by the ADFS Configuration Wizard) to require Server Name Indication.
Web Application Proxy (part of Windows Server 2012 R2, replacement of ADFS proxy) is also by default setup (by the Web Application Proxy Configuration Wizard) to require Server Name Indication.

Like the WebDav client does not support Server Name Indication (SNI) situation, ARR is non-SNI capable.
The majority of articles I read about SNI are mentioning a list of SNI compatible web browsers. Yes, the web browsers probably represent 99% of the HTTP clients, but the rest of the HTTP based clients are applications which can also be non-SNI capable.
To make sure I am not misunderstood: SNI is not evil. In fact I like it and I am using as much as possible. From Wikipedia: “Server Name Indication (SNI) is an extension to the TLS protocol that indicates to what hostname the client is attempting to connect at the start of the handshaking process. This allows a server to present multiple certificates on the same IP address and port number and hence allows multiple secure (HTTPS) websites (or any other Service over TLS) to be served off the same IP address without requiring all those sites to use the same certificate. It is the conceptual equivalent to HTTP/1.1 virtual hosting for HTTPS.”

What does ARR extension mainly does, is to receive your (client) HTTP request and route it based on specific load balancing algorithm to a specific server (part of a farm configuration). The server replies back to NLB (IIS + ARR) the HTTP response and after that the NLB sends the HTTP response back to the client. So, at some point ARR is behaving as a HTTP client.

What’s the problem?
The problem in this case is: ARR is non-SNI capable, which means the request sent by the NLB (IIS+ARR) node to the ADFS/WAP servers does not contains “server_name” extension as part of the SSL/TLS handshake.

Example of a successful ADFS request sent by a SNI capable client.
ADFS_3.0_WAP_SNI_and_Network_Load_Balancing_02

Example of an unsuccessful ADFS request sent by ARR (non-SNI capable).
ADFS_3.0_WAP_SNI_and_Network_Load_Balancing_03
as result, without the Server Name extension in the header, ADFS is unable to identify which certificate to serve and the connection will be reset by server.
ADFS_3.0_WAP_SNI_and_Network_Load_Balancing_04

Well, as mentioned earlier, ADFS 3.0 and WAP are by default setup to listen and respond to HTTPS connections where “server_name” extension is present as part of the SSL/TLS handshake. It’s the same reason why the non-SNI web browsers don’t work with by default ADFS 3.0 and WAP configurations.

Solution
The solution is to make ADFS 3.0 and WAP to respond also to the HTTPS requests sent by non-SNI capable clients. Basically we need to configure an http.sys fallback certificate and is 100% supported by Microsoft (it’s just not part of the default configuration – and somehow I agree with this decision).
So, on all ADFS and WAP nodes load balanced using IIS+ARR is necessary to configure an http.sys fallback certificate. Basically these servers will bind the ADFS/WAP listeners to HTTPS and will use one certificate to encrypt all the traffic performed through TCP 443. From best practices point of view this configuration is totally fine (because for servers like ADFS and WAP is not recommended to install and configure other roles who need to be bound to HTTPS).
A full description can be found here -> http://blogs.technet.com/b/applicationproxyblog/archive/2014/06/19/how-to-support-non-sni-capable-clients-with-web-application-proxy-and-ad-fs-2012-r2.aspx.

How to configure an http.sys fallback certificate?
make sure you replace XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX with the thumbprint certificate used to secure the AFDS communications (from command line execute “netsh http show sslcert”, or check the certificate)
ADFS_3.0_WAP_SNI_and_Network_Load_Balancing_05

On all ADFS 3.0 servers execute the following command

netsh http add sslcert ipport=0.0.0.0:443 certhash=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX appid={5d89a20c-beab-4389-9447-324788eb944a}

 

On all WAP servers execute the following command

netsh http add sslcert ipport=0.0.0.0:443 certhash=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX appid={f955c070-e044-456c-ac00-e9e4275b3f04}

 

Once the change is performed the connections performed by non-SNI clients will be accepted by ADFS / WAP servers (in this case ARR will be able to establish TLS communications with ADFS/WAS => so an IIS+ARR based NLB can be used to load balance the ADFS traffic).
ADFS_3.0_WAP_SNI_and_Network_Load_Balancing_06

How can I find out if my ADFS/WAS server accepts only SNI requests?
When the ADFS/WAS server doesn’t have a fallback certificate configured, the following registry key is empty: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters\SslBindingInfo