Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASP.NET Core 2.1 Kerberos delegation not working #1453

Closed
philipszalla opened this issue Dec 20, 2019 · 13 comments
Closed

ASP.NET Core 2.1 Kerberos delegation not working #1453

philipszalla opened this issue Dec 20, 2019 · 13 comments

Comments

@philipszalla
Copy link

Hi all,

we have an ASP.NET Core 2.1 API running on a Windows Server 2012 R2 in IIS.
The IIS is configured to use Kerebros authentication, SPNs are set correctly and the application pool identity is a custom domain user. Delegation is enabled, too.

The API is called by a browser and tries to connect to a SharePoint 2013 Server using impersonation and web requests.
When I call the API with my account, which is a local administrator on the Server hosting the API impersonation works perfect.
If a regular account tries to call the API an exception gets thrown:

System.Net.WebException: An error occurred while sending the request. Error 5 calling WinHttpOpen, 'Access is denied'. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: Error 5 calling WinHttpOpen, 'Access is denied'.
   at System.Net.Http.WinHttpHandler.ThrowOnInvalidHandle(SafeWinHttpHandle handle, String nameOfCalledFunction)
   at System.Net.Http.WinHttpHandler.EnsureSessionHandleExists(WinHttpRequestState state)
   at System.Net.Http.WinHttpHandler.StartRequest(WinHttpRequestState state)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at System.Net.HttpWebRequest.SendRequest()
   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   --- End of inner exception stack trace ---
   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
   at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
   at Microsoft.SharePoint.Client.ClientContext.ExecuteQueryAsync()

Now, if I just open the Internet Explorer on the server hosting the API as a regular user the impersonation works from the clients computer.

Has anyone an idea?

Greetings from Hamburg!

@Tratcher
Copy link
Member

@davidsh is this an issue you've seen with WinHttpHandler?

@analogrelay
Copy link
Contributor

This seems like it's likely an issue in HttpClient not ASP.NET Core. Sounds like this is an issue for dotnet/runtime, since it's an issue with impersonation (WindowsIdentity.Impersonate I presume?)

@analogrelay
Copy link
Contributor

@Phibsi Can you clarify, are you using .NET Framework with ASP.NET Core 2.1? Impersonation isn't support in .NET Core, so I'm presuming you are?

Can you provide a runnable sample that illustrates what you're doing and where it's failing (I realize that it will depend upon per-machine configuration like Windows domains, etc.).

@Tratcher
Copy link
Member

Tratcher commented Jan 3, 2020

Clarification: ASP.NET Core doesn't do impersonation by default on .NET or Core, but you can do impersonation manually on either.

@philipszalla
Copy link
Author

philipszalla commented Jan 6, 2020

Hi @anurse,

I created a sample project to reproduce the issue: https://github.com/phibsi/sample-aspnetcore-impersonation

You need to publish the webservice to an IIS Website on Windows Server 2012 R2.
The Windows Server needs to be joined to an Active Directory. Kerberos requieres SPNs set to the Computer Account or Application Pool Account. DNS A-recoreds needs to be set for the services (Webservice and SharePoint).
You don't need to use Microsoft.SharePoint.Client, a simple HttpClient call reproduces the issue, too.

@philipszalla
Copy link
Author

Hi @Tratcher,

Impersonation is done in https://github.com/phibsi/sample-aspnetcore-impersonation/blob/ec4aa0de0f2f44ee771c6cff0b0d2bf50155bc93/Services/ImpersonationService.cs#L64 using IIS, Kerberos and

var user = (WindowsIdentity)Context.User.Identity;
WindowsIdentity.RunImpersonated(user.AccessToken, action);

@Tratcher
Copy link
Member

Tratcher commented Jan 6, 2020

Does it work any better when the action being run under impersonation is not async (or is forced to complete synchronously within the impersonation)? We've seen issues in the past with the impersonation being reverted too soon.
https://github.com/phibsi/sample-aspnetcore-impersonation/blob/ec4aa0de0f2f44ee771c6cff0b0d2bf50155bc93/Controllers/HomeController.cs#L39-L44

@philipszalla
Copy link
Author

Hi @Tratcher,

I updated the project and changed the async CSOM request to sync WebRequest:
https://github.com/phibsi/sample-aspnetcore-impersonation/blob/2e277d4f7d9de851a4e1391a68ec2db94eceb64d/Controllers/HomeController.cs#L94-L116

But I get the same error message :(

Any idea?

@Tratcher
Copy link
Member

Tratcher commented Jan 8, 2020

Ok, since this is primarily an issue with impersonation and outgoing requests I'm going to transfer it over to the folks that own those. This does have some similarities to https://github.com/dotnet/corefx/issues/38646, but not quite the same stack trace.

@Tratcher Tratcher transferred this issue from dotnet/aspnetcore Jan 8, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Net untriaged New issue has not been triaged by the area owner labels Jan 8, 2020
@davidsh
Copy link
Contributor

davidsh commented Feb 5, 2020

@davidsh is this an issue you've seen with WinHttpHandler?

We haven't seen any prior customer issues with delegation and WinHttpHandler.

@Phibsi

I noticed that HttpWebRequest is being used. Also, WinHttpHandler is no longer the default HTTP stack for latest .NET Core (such as 3.0/3.1). You might want to try latest .NET Core to see if the problem reproduces.

@karelz
Copy link
Member

karelz commented Feb 20, 2020

Triage: Looks like it may be addressed in .NET Core 3.0+. As we do not have clear repro to try, closing for now. Feel free to reopen if there is evidence it is still failing on .NET Core 3.0+. Ideally with a repro for us to try. Thanks!

@karelz karelz closed this as completed Feb 20, 2020
@karelz karelz added this to the 5.0 milestone Feb 20, 2020
@karelz karelz removed the untriaged New issue has not been triaged by the area owner label Feb 20, 2020
@philipszalla
Copy link
Author

Hi all,

I'm sorry for my late answer.

I updated the app to ASP.NET Core 3.1 and I implemented async requests (HttpClient) and I removed the UseSocketsHttpHandler.

Now the error message looks like this:

System.Net.Http.HttpRequestException: A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
 ---> System.Net.Sockets.SocketException (10111): A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Sample.AspNetCore.Impersonation.Controllers.HomeController.GetSharePointLoginNameAsync(String webUrl) in C:\_DEV\aspnet-core-impersonation\Controllers\HomeController.cs:line 200

Any idea?

@philipszalla
Copy link
Author

Triage: Looks like it may be addressed in .NET Core 3.0+. As we do not have clear repro to try, closing for now. Feel free to reopen if there is evidence it is still failing on .NET Core 3.0+. Ideally with a repro for us to try. Thanks!

You can find the code in this repo: https://github.com/phibsi/sample-aspnetcore-impersonation/

@ghost ghost locked as resolved and limited conversation to collaborators Dec 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants