Friday, February 16, 2018

Kerberos authentication

I finally had a chance to look into this subject rather thoroughly, till having arrived to a certain result. Though in the end, I decided to not to use it, and pursued a different solution to implement the requirement in hand.

First of all, why Kerberos?

In the previous post, I wrote about SharePoint .NET client object model. I looked at it, in order to implement an ASP.NET web app, which allows the users to perform operations such as creation of a document library, on a remote SharePoint. The SharePoint is of “on-premises”. We are not yet on Office 365. Everybody cannot create the document libraries, of course. The users logon to the web app. And only those who are authorized (granted the permission at the SharePoint site) can. Yes, it is the famous “authentication double hop”, or whatever else you may call it, scenario.

To date, in our environment, “Windows authentication” = NTLM. Nowhere Kerberos is used, as far as my knowledge goes. But, it is known that the web server cannot pass to another server, the user credential that it acquires with NTLM authentication. In a scenario such as the above, you need to implement the “Kerberos delegation”.

I was new to Kerberos, leant it only on the university textbook many years ago, so started with some reading of blog posts such as this one: https://blogs.technet.microsoft.com/askds/2008/03/06/kerberos-for-the-busy-admin/. I read it now once again. Still not so easy to read. But in short, this is how I understand it works.

When you choose the “Windows Authentication” for the web app on the IIS Manager, since it comes first in the list, when the client such as Internet Explorer accesses the app and receives the 401 challenge response, it goes to the domain controller and see if the corresponding SPN (Service Principal Name), HTTP/the_web_server in this case, exists.

winowsauthproviders

In case the SPN does exists, under the account (machine or domain) that indeed runs the service, the IIS worker process in this case, your authentication against the web app with Kerberos should succeed.

In short, the key to the success is as simple as registering the correct SPN with the correct account.

1. Service Principal Name

It looks something like HTTP/the_web_server. The first part is called “service class”, and HTTP for web access which uses the default port 80. The same “HTTP” for https (433) as well.

Then the second portion is the name of the web server. This is a bit tricky. This documentation by Microsoft support reads that in case a hostname based virtual web site is in use, the hostname should be registered with the SPN. What I found is different though. It is always the server’s BIOS name, or the machine name that the IE always looks for to the domain controller. And actually, due to this fact, I decided to not to go for this solution. I would like to talk about it later in more detail.

2. The account running the service

When you register or add a SPN, you issue the command like follows on the domain controller.

CMD> setspn –a SPN account_running_the_service

The Kerberos ticket the client gets from the domain controller and then submits to the web server is encrypted using the account specified, its password hash. The web server, the IIS worker process to be more precise, decrypts the ticket submitted with the password hash of the account who runs the process. Therefore, this is imperative that you register the SPN with the account that runs your web app.

However, in the case of IIS, things are a little more complicated.

winowsauthadvancedsettings

This is the advanced settings of the windows authentication. It reads that by default the so-called kernel-mode authentication is used. What is kernel-mode authentication? How it changes the behavior?

When the kernel-mode authentication is used, it is always the machine account, something like the machine BIOS name followed by a $ sign, is used to decrypt the tickets, not the custom identity specified for the application pool, that is the worker process. So, if you, without knowing it, register the SPN with the custom identity of the application pool, the authentication fails, with the KRB_AP_ERR_MODIFIED error. By the way, this error you find in the client Event Viewer is super cryptic. I “decrypted” it, thanks to this blog post.

Abandoned nevertheless. Why?

Our organization aggregates many web services under one single hostname, or a domain name; ourorganization.org. You access one such web service at its URL ourorganization.org/webservice1, another at ourorganization.org/webservice2 and so on.

In such an environment, image that I register the SPN for my web app, which is accessed as ourorganization.org/mywebapp just like all the others, as HTTP/ourorganization.org with the custom identity of the application pool that runs the app.

What happened was that for all other web services to which the Windows authentication is chosen, the authentication had started failing!! For none of them, Kerberos is intended to use, but it is there as the first choice by default!! And the kernel-mode authentication is chosen, again not by intention, but by default!! And the authentication fails because they cannot decrypt the Kerberos tickets encrypted using my custom identity. So I retreated. Too heavy side-effects...

Other references:

Tuesday, February 13, 2018

SharePoint .NET client object model against load balanced servers

This, I found nowhere on the net the solution, and so nearly given up.

For the SharePoint client object model, the sample code are available everywhere on the net e.g. https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-client-library-code. None worked for me. The error was “(401) Unauthorized”. The problem was that as you know, even though the servers, a SharePoint farm in this case, are loaded balanced with whatever actual software and/or hardware in use to do so, to perform operations only the authorized users can perform, you need to interact with a single server. There seem, however, no documentation available (I was not able to find at least) explaining how to achieve this.

And so this is how I made it work. Bear in mind that I am not from Microsoft or anything, not an authority, so cannot guarantee you that this is the way to go.

code1

and then

code2

What I expect with this was to accept the load balancer issuing sticky cookie and send it back with the subsequent requests. And it seems do the trick.

Hope this helps you.