Understanding By-Design Behavior of ISA Server 2006: Using Kerberos Authentication for Web Proxy Requests on ISA Server 2006 with NLB

Introduction

With companies working more and more to achieve scenarios of high availability, ISA Server 2006 Enterprise Edition Integrated NLB is becoming very popular. High availability is also complemented by the need to offer performance improvement with Kerberos Authentication while browsing using Internet Explorer 7.

Note: For more information on the benefits offered by Internet Explorer 7 with Kerberos authentication for Web Proxy request, reviews the article Improving Web Proxy Client Authentication Performance on ISA Server 2006 at Microsoft TechNet.

Some customers implement ISA Server 2006 Enterprise Edition with NLB and use a virtual name mapped to the virtual IP as proxy server on Internet Explorer. They notice that if they do that the HTTP request that the request sent to the ISA Server 2006 is authenticated using NTLM protocol. This post will explain why this is an expected behavior and how to allow Kerberos authentication while maintaining the NLB configuration.

Understanding the Authentication

The Internet Explorer 7 is the first version of Microsoft browser that supports Kerberos authentication for Web Proxy request. The only thing that you will need to do is configure the FQDN of the ISA Server 2006 computer in the Internet Explorer 7 Proxy settings. The problem is that some implementations use the following configuration:

Server Name

ISA01.contoso.msft

ISA02.contoso.msft

Server IP

10.20.20.1

10.20.20.2

SPN

http/isa01.contoso.msft

http/isa02.contoso.msft

Virtual Name

Proxy.contoso.msft

Virtual IP

10.20.20.3

Using this configuration, what will happen is the client workstation will send the request for the virtual name, however there is no SPN for http/proxy.contoso.com, therefore it will not be possible to get the Kerberos ticket for this resource, the DC will answer with the error ERR_S_PRINCIPAL_UNKNOWN. The end result is that the client and the server negotiate to use NTLM as authentication method and this is an expected behavior.

You might be asking: what if I use SETSPN utility to register http/proxy.contoso.com, will it fix this problem? No it will not. As a matter of fact, you will receive KDC Event ID 11 error DS_SERVICE_PRINCIPAL_NAME saying that you have a duplicate SPN, which maps to the KB 321044.

Using Kerberos and NLB

On a scenario where you are using ISA Server 2006 with NLB and you also want to use Kerberos for Web Proxy authentication what you should do is use Automatic Script Configuration (WPAD). However we had a change from ISA Server 2000 to ISA Server 2004/2006 in the way that we build the server’s list for the configuration file. On ISA Server 2000 we return the fully-qualified names within the function MakeProxies() . In ISA 2004 and later, we use the server IP addresses appropriate to the network where the script was requested. This change from fpcNameSystem_DNS to fpcNameSystem_IP for ISA 2004/2006 was made to eliminate the common name resolution problems seen in many ISA deployments.

Note: For best practices in DNS configuration on ISA Server follow the recommendations from article Configuring DNS Servers for ISA Server at Microsoft TechNet Library.

With the adoption of Internet Explorer 7 and the option to use Kerberos for Web Proxy authentication, the use of the IP causes Kerberos authentication to fail and the browser falls back to NTLM authentication. To change how the ISA Server 2004 and 2006 will build the script by using the fully-qualified name rather than the IP address, save and run the following script on the ISA Server:

Const fpcCarpNameSystem_DNS = 0

Const fpcCarpNameSystem_WINS = 1

Const fpcCarpNameSystem_IP = 2

Dim oISA: Set oISA = CreateObject( "FPC.Root" )

Dim oArray: Set oArray = oISA.GetContainingArray

Dim oWebProxy: Set oWebProxy = oArray.ArrayPolicy.WebProxy

If fpcCarpNameSystem_DNS = oWebProxy.CarpNameSystem Then

    WScript.Echo "ISA is already configured to provide DNS names in the WPAD script"

    WScript.Quit

End If

oWebProxy.CarpNameSystem = fpcCarpNameSystem_DNS

oWebProxy.Save true

WScript.Echo "ISA was configured to provide DNS names in the WPAD script..."

Important: shortly after runing this script, the Firewall Service will restart. Therefore we recommend doing this change after business hours.

The End Result

Let’s see on the scenario below, what will be the final result after running this script and configure the client computer to use the virtual name of the array:

1. Client sends the DNS Query for proxy.contoso.msft (virtual name that is mapped to the virtual IP):

10.20.20.200 10.20.20.20 DNS DNS:QueryId = 0x9413, QUERY (Standard query), Query for proxy.contoso.msft of type Host Addr on class Internet

2. DNS Server answers with the virtual IP address of the NLB:

10.20.20.20 10.20.20.200 DNS DNS:QueryId = 0x9413, QUERY (Standard query), Response - Success, 10.20.20.3

3. Client then performs the ARP resolution for this IP and receives the answer:

10.20.20.200 proxy.contoso.msft ARP ARP:Request, 10.20.20.200 asks for 10.20.20.3

proxy.contoso.msft 10.20.20.200 ARP ARP:Response, 10.20.20.3 at 02-BF-0A-14-14-03

4. Client starts the TCP Handshake with the destination server:

10.20.20.200 proxy.contoso.msft TCP TCP:Flags=......S., SrcPort=1240, DstPort=HTTP Alternate(8080), PayloadLen=0, Seq=792829912, Ack=0, Win=65535 (scale factor 0) = 65535

proxy.contoso.msft 10.20.20.200 TCP TCP:Flags=...A..S., SrcPort=HTTP Alternate(8080), DstPort=1240, PayloadLen=0, Seq=2467905888, Ack=792829913, Win=16384 (scale factor 0) = 16384

10.20.20.200 proxy.contoso.msft TCP TCP:Flags=...A...., SrcPort=1240, DstPort=HTTP Alternate(8080), PayloadLen=0, Seq=792829913, Ack=2467905889, Win=65535 (scale factor 0) = 65535

5. Since the client is configured to “use automatic configuration script” it sends the request for the array.dll. Notice that the HTTP header shows the virtual name:

10.20.20.200 proxy.contoso.msft HTTP HTTP:Request, GET /array.dll

- Http: Request, GET /array.dll

    Command: GET

  + URI: /array.dll?Get.Routing.Script

    ProtocolVersion: HTTP/1.1

    Accept: */*

    UserAgent: Mozilla/4.0 (compatible; MSIE 7.0; Win32)

    Host: proxy.contoso.msft:8080

    HeaderEnd: CRLF

6. The ISA Server answers the request with the script file. Here it is the place that the script that you ran will make a difference, you will see the computer name rather than the IP address that it is there by default:

proxy.contoso.msft 10.20.20.200 HTTP HTTP:Response, HTTP/1.1, Status Code = 200, URL: /array.dll

- Http: Response, HTTP/1.1, Status Code = 200, URL: /array.dll

    ProtocolVersion: HTTP/1.1

    StatusCode: 200, Ok

    Reason: OK

    Date: Sun, 22 Jun 2008 17:45:50 GMT

    Connection: close

    ContentType: application/x-ns-proxy-autoconfig

    Cache-Control: max-age=3000

    HeaderEnd: CRLF

  - payload: HttpContentType = application/x-ns-proxy-autoconfig

     AutoConfig: //Copyright (c) 1997-2006 Microsoft Corporation

     AutoConfig: BackupRoute="DIRECT";

     AutoConfig: UseDirectForLocal=true;

     AutoConfig: function MakeIPs(){

     AutoConfig: }

     AutoConfig: DirectIPs=new MakeIPs();

     AutoConfig: cDirectIPs=0;

     AutoConfig: function MakeCARPExceptions(){

     AutoConfig: this[0]="*.windowsupdate.com";

     AutoConfig: this[1]="windowsupdate.microsoft.com";

     AutoConfig: this[2]="*.windowsupdate.microsoft.com";

     AutoConfig: this[3]="*.update.microsoft.com";

     AutoConfig: this[4]="download.windowsupdate.com";

     AutoConfig: this[5]="download.microsoft.com";

     AutoConfig: this[6]="*.download.windowsupdate.com";

     AutoConfig: this[7]="wustat.windows.com";

     AutoConfig: this[8]="ntservicepack.microsoft.com";

     AutoConfig: }

     AutoConfig: CARPExceptions=new MakeCARPExceptions();

     AutoConfig: cCARPExceptions=9;

     AutoConfig: function MakeNames(){

     AutoConfig: this[0]="*.contoso.msft";

     AutoConfig: this[1]="*.contoso.msft";

     AutoConfig: }

     AutoConfig: DirectNames=new MakeNames();

     AutoConfig: cDirectNames=2;

     AutoConfig: HttpPort="8080";

     AutoConfig: cNodes=2;

     AutoConfig: function MakeProxies(){

     AutoConfig: this[0]=new Node("ISACONTN2.contoso.msft",2531460408,1.000000);

     AutoConfig: this[1]=new Node("ISACONTN1.contoso.msft",3457248957,1.000000);

     AutoConfig: }

     AutoConfig: Proxies = new MakeProxies();

     AutoConfig: function Node(name, hash, load){

     AutoConfig: this.name = name;

     AutoConfig: this.hash = hash;

     AutoConfig: this.load = load;

     AutoConfig: this.score = 0;

     AutoConfig: return this;

     AutoConfig: }

     AutoConfig: function FindProxyForURL(url, host){

     AutoConfig: var hash=0, urllower, i, fIp=false, ip, nocarp=false, skiphost=false;

     AutoConfig: var list="", pl, j, score, ibest, bestscore;

     AutoConfig: urllower = url.toLowerCase();

     AutoConfig: if((urllower.substring(0,5)=="rtsp:") ||

     AutoConfig: (url

7. At this point, the client will use the script to calculate which ISA Server it will use and then send the request to it:

10.20.20.200 isacontn2.contoso.msft HTTP HTTP:Request, GET http://www.microsoft.com/isaserver

8. Since the rules that allows client to browse Internet requires authentication, the ISA Server will send the 407:

isacontn2.contoso.msft 10.20.20.200 HTTP HTTP:Response, HTTP/1.1, Status Code = 407, URL: http://www.microsoft.com/isaserver

9. The client then goes to the DC and request a ticket (KRB_TGS_REQ) for the correct SPN as you can see below:

10.20.20.200 10.20.20.20 KerberosV5 KerberosV5:TGS Request Realm: CONTOSO.MSFT Sname: HTTP/isacontn2.contoso.msft

10. The DC replies with the ticket (KRB_TGS_REP):

10.20.20.20 10.20.20.200 KerberosV5 KerberosV5:TGS Response Cname: Administrator

11. The client workstation sends the request to the ISA Server using the Kerberos ticket built in:

10.20.20.200 isacontn2.contoso.msft HTTP HTTP:Request, GET http://www.microsoft.com/isaserver

  - ProxyAuthorization: Negotiate

   - Authorization: Negotiate

    - NegotiateAuthorization:

       Scheme: Negotiate

     - GssapiKrb5: 0x1

        Kerberos:

Conclusion

As you can see it is possible to align the use of NLB and auto configuration scripts while using Kerberos for Web Proxy authentication.

Last but not least, the other point to remember is that the proxy server name will also be cached by Internet Explorer. If you want to change this behavior on the client side, apply the steps from KB 271361.

Authors:

Yuri Diogenes

Microsoft CSS Forefront (ISA/TMG) Team

Jim Harrison

Microsoft Forefront (ISA/TMG) Sustained Engineering Team

Technical Reviewer:

Doron Juster

Microsoft Forefront (ISA/TMG) Sustained Engineering Team