HttpWebRequest Class does not use Port number in SPN when using Kerberos
If you look at a Kerberos ticket when HttpWebRequest is trying to retrieve a resource, you will notice that it does not have the port number in the SPN.
For example you are trying to retrieve a WebService https://someserver:8888/webservice/webservice.asmx and you notice the Kerberos ticket request does not specify the SPN in the request.
If you are using .NET 1.1, you will not be able to work around this due to a design limitation of the classes. You will need to upgrate and use the .NET 2.0 framework.
To use the SPN with the port number specified in the URI of the request for the .NET 2.0 framework you must use the AuthenticationManger.CustomTargetNamedDictionary property and add the appropriate parameters. https://msdn.microsoft.com/en-us/library/system.net.authenticationmanager.customtargetnamedictionary.aspx
From this article:
When a WebRequest requires mutual authentication, the SPN for the destination must be supplied by the client. If you know the SPN, you can add it to the CustomTargetNameDictionary before sending the request. If you have not added SPN information to this dictionary, the AuthenticationManager uses the RequestUri method to compose the most likely SPN; however, this is a computed value and might be incorrect.
For example, here is how you could workaround this issue for the URI I listed above:
// do this step in the WebService client before calling the service
AuthenticationManager.CustomTargetNameDictionary.Add(“https://someserver:8888/webservice/webservice.asmx”,
“http/someserver:8888”);
Here’s an example whereby the SPN is automatically determined from the URL:
Uri uri = new Uri(url);
string spn = uri.Scheme + '/' + uri.Authority;
AuthenticationManager.CustomTargetNameDictionary.Add(url, spn);
Thanks to Hui Zhu for this info!
Comments
- Anonymous
November 19, 2013
The above code didn't work for me, I am using .NET 4.0 and it seems to be very sensitive to how the SPN is added. To get Kerberos working with a CNAME, the spn needs to be added; the scheme MUST be upper case, HTTP and not http. so to get the spn: string spn = uri.Scheme.toUpper() + '/' + uri.Host (you don't need the port number as a part of SPN).