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

Unable to use System.Net.NetworkCredential inside docker #20387

Closed
BharatRajMeriyala opened this issue Mar 2, 2017 · 29 comments
Closed

Unable to use System.Net.NetworkCredential inside docker #20387

BharatRajMeriyala opened this issue Mar 2, 2017 · 29 comments
Labels
area-System.Net.Http bug os-linux Linux OS (any supported distro)
Milestone

Comments

@BharatRajMeriyala
Copy link

I am trying to authenticate my call to a SSRS report server hosted outside the docker application. And to accress the report I do the following:

HttpWebRequest webRequest = WebRequest.Create(sTargetURL) as HttpWebRequest;
webRequest.Credentials = new NetworkCredential(strReportUser, strReportUserPW);
WebResponse HttpWResp = await webRequest.GetResponseAsync();

But I continuesly get 401 unauthorized.

The approach of NetworkCredentials works fine when I am doing the same inside my Azure Hosted App service and also my local.

The credentials that I set on the header inside the docker environment, simply do not carry forward upto the report server and I get the error.

@karelz
Copy link
Member

karelz commented Mar 2, 2017

Which OS? Which .NET Core version do you use 1.0 or 1.1?

@BharatRajMeriyala
Copy link
Author

BharatRajMeriyala commented Mar 2, 2017

The docker machine runs linux and I am using dotnet core 1.1

@karelz
Copy link
Member

karelz commented Mar 2, 2017

@BharatRajMeriyala which Linux distro and version?

@BharatRajMeriyala
Copy link
Author

canonical:UbuntuServer:16.04.0-LTS:latest is the linux version.

@karelz
Copy link
Member

karelz commented Mar 3, 2017

Which OS is used on your local and in Azure host - in places where it works?

@BharatRajMeriyala
Copy link
Author

On my local machine, I have windows 7 and I have deployed the app on Azure App Service for Dotnet Core application. It works fine in these places. Only on my docker container running linux I have the issue.

@karelz
Copy link
Member

karelz commented Mar 3, 2017

@Priya91 is it worth quick investigation to assess the impact?
Just based on description it seems to be a bit worrisome, but I may be wrong.
You moved it to Future, so I wonder what kind of additional insight you have ...

@Priya91
Copy link
Contributor

Priya91 commented Mar 3, 2017

@BharatRajMeriyala Can you try this on the terminal in your docker container,

curl --user <username>:<password> <request-url>

Need more info to debug, could it be the case that server is requesting different authentication scheme than the one used by default by curl [Basic]. Can you post the headers received from the server?

@BharatRajMeriyala
Copy link
Author

This is what I get on my docker machine...

$ curl --user asdf\xxxx:xxxx "http://xx.xxx.xxx.xxx/ReportSer
ver/Pages/ReportViewer.aspx?%2fXXXX_XXX%2fXXXXX&rs:Command=Render&rs:for
mat=pdf"
[1]+ Done curl --user asdf\xxxx:xxxx http:
//xx.xxx.xxx.xxx/ReportServer/Pages/ReportViewer.aspx?%2fXXXX_XXX%2fXXXXX

@BharatRajMeriyala
Copy link
Author

Can you post the headers received from the server?

Can you tell me how exactly I can do that?

@Priya91
Copy link
Contributor

Priya91 commented Mar 14, 2017

In your code, you can do

WebResponse HttpWResp = await webRequest.GetResponseAsync();
var headers = (HttpWResp as HttpWebResponse).Headers;

and print out the headers..

@karelz
Copy link
Member

karelz commented Mar 17, 2017

@BharatRajMeriyala your reply seems to be deleted. Was it on purpose or by mistake?

@christle
Copy link

same problem here. Any Updates?

@BharatRajMeriyala
Copy link
Author

BharatRajMeriyala commented May 29, 2017 via email

@christle
Copy link

christle commented May 29, 2017

No. After 4 hours i solved the issue. My Client runs inside a Linux container and i changed my code to this:

var httpClientHandler = new HttpClientHandler();

CredentialCache cc = new CredentialCache();
cc.Add(new Uri(_apiBaseAddress), "NTLM", new NetworkCredential(_user, _password, "mydomain"));
httpClientHandler.Credentials = cc;

var client = new HttpClient(httpClientHandler);

outside from docker on a windows shell i dont need the credentialCache so i passed the NetworkCredential object directly to the handler. But that dont worked in docker. Inside the container, the wget command response with 2 unauthorized exceptions but the next one with 200. I think some kind of handshaking. Maybe the Cache object do the job right and dont throw an exception on the first request.

@karelz
Copy link
Member

karelz commented May 30, 2017

@Argolein Any Updates?

No updates - if you read the bug, you can notice that we don't have enough information to make any reasonable next steps. No one has a repro either.
Do you have a minimal isolated repro?

@christle
Copy link

@karelz i already posted a suitable Solution for the problem yesterday.

@karelz
Copy link
Member

karelz commented May 30, 2017

@Argolein it sounded like a workaround without clear understanding why it works. If you're fine with that, then that's ok ...

@kietbahuynh
Copy link

Any updates on this?

I'm having the same issue. Have tried the workaround suggested by @Argolein but no luck.

@christle
Copy link

Hi , my Solution with the credentialcache works only inside a Linux based docker Container. if i want to start outside of a Container i have to remove the credentialcache. I made a simple switch with a OS ENV var.

@kietbahuynh
Copy link

kietbahuynh commented Aug 30, 2017

@Argolein Thanks for your comment

I think I have the same setup as yours except that I'm using dotnet core 2.0.

I'm able to use NetworkCredentials just fine outside of docker. However, once inside docker, I keep having 401 error.

I've tried your suggestion and then call the code below but doesn't seem to work
var result = client.GetStringAsync(requestUrl).Result;

A bit more information about my setup, I use port mapping as following:
docker run -p 5000:80 myapp

and also expose ports 80, 443, 5000

Any help is much appreciated

@kietbahuynh
Copy link

@Argolein Just ignore my previous comment. It works now.

For anyone who's having the same problem, the key here is use "NTLM" authentication type and it has to authenticate using base URL.

@mstephano
Copy link

I had the same problem before but managed to resolve it. My container was supposed to call a webapi inside the same domain using the service account set on the app pool (in my case, it was a group Managed Service Account - gMSA). The webapi was secured and we were allowing only the service account to be able to access that webapi, so no employee in the company could hack and call the webapi manually (confidential data). When running in debug in Visual Studio 2017, the container was running using a local IP in the nat network of the host.

So using HttpClient with param UseDefaultCredential=true or setting the CredentialCache to use the NetworkCredential always result with 401 unauthorized.

The fix was:

  1. Run your container with a fixed IP.
  2. Create a DNS entry in your domain controller server (test.yourdomain.com for example) using the container fixed IP. This dns can only be used by the host of the container if the IP is in its nat network, unless you have created a transparent network, or else..
  3. Properly create SPN for the service account with entry HTTP/<test.yourdomain.com>
  4. Connect to your website using http://test.yourdomain.com.

Any questions let me know and I will try to help.

@BogdanovKirill
Copy link

Same issue in AWS + Cluster + Windows spot instance + Docker. My solution is to manually set Authorization header in HttpWebRequest.

        HttpWebRequest request = WebRequest.CreateHttp(snapshotUri);
        request.Method = WebRequestMethods.Http.Get;
        request.KeepAlive = false;
        request.PreAuthenticate = false;
        request.UseDefaultCredentials = false;
        request.Proxy = null;

        if (authenticator != null)
        {
            string value = authenticator.GetResponse(1, snapshotUri, request.Method);
            request.Headers.Add("Authorization", value);
        }

        return (HttpWebResponse) await request.GetResponseAsync()
            .WithTimeoutAndCancellation(_connectionParameters.NetworkTimeout, token);

@davidsh
Copy link
Contributor

davidsh commented May 5, 2018

Based on reading the discussion on this issue and some workarounds that worked, I suspect the problem is related to several things.

What authentication schemes is the server requesting? It sounds like either Negotiate or NTLM is being requested by the server.

Using default credentials from a Linux host trying to authenticate against a Windows Active Directory has many requirements in order to be successful. The Linux machine must be "joined" to the Windows Active Directory domain. This is usually done with a separate step using Kerberos tools on the Linux machine.

If both Negotiate and NTLM schemes are offered by the server, Negotiate will be chosen first since it is considered more secure. Negotiate has the ability to try Kerberos first. If that isn't possible, then NTLM will be tried. However, some Linux distros have problems with Negotiate and can't downgrade to NTLM. So, the authentication will fail with 401.

Another item to consider is that you usually must specify the domain name in the NetworkCredential constructor if you are passing explicit credentials on a Linux machine. This isn't always required on the Windows machine because it can determine the default domain implicitly.

So this code pattern is usually recommended:

new NetworkCredential(_user, _password, "mydomain");

Since there are many variables here, it would be best if you could re-try the repro scenario. Please attach WireShark and/or Fiddler traces so that we can see what kind of network traffic is being used especially in terms of what authentication schemes the server is attempting.

You might also want to try out the new .NET Core 2.1 Preview 2 release which uses a newer HTTP stack, SocketsHttpHandler:

See: https://blogs.msdn.microsoft.com/dotnet/2018/04/11/announcing-net-core-2-1-preview-2/

For now, we'll close this issue. But please report back when you have a new repro case.

@davidsh davidsh closed this as completed May 5, 2018
@kwaazaar
Copy link

The SocketsHttpHandler only support basic auth, so make sure you disable it there, as described in the blogpost mentioned above. Once you do, on Linux you will fallback to the CurlHandler, which seems to have the fix mentioned above as well.

@davidsh
Copy link
Contributor

davidsh commented Oct 18, 2019

The SocketsHttpHandler only support basic auth,

This isn't true. HttpClient and all the handlers (i.e. SocketsHttpHandler) support Basic/Digest/NTLM/Negotiate schemes.

@kwaazaar
Copy link

The SocketsHttpHandler only support basic auth,

This isn't true. HttpClient and all the handlers (i.e. SocketsHttpHandler) support Basic/Digest/NTLM/Negotiate schemes.

But check my link. What does that comment mean?:
"// Just look for basic credentials. If in the future we support preauth
// for other schemes, this will need to search in order of precedence."

@davidsh
Copy link
Contributor

davidsh commented Oct 21, 2019

But check my link. What does that comment mean?:
"// Just look for basic credentials. If in the future we support preauth
// for other schemes, this will need to search in order of precedence."

The comment is only about handling a certain kind of optimization for pre-authenticate where the 'Authorization:' request header can be added even before any HTTP 401/407 response code is returned by a server.

SocketsHttpHandler handles Basic/Digest/NTLM/Negotiate authentication flows and will use the .Credentials property as the credentials. It also handles these authentication schemes for proxy authentication as well as server authentication.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 3.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net.Http bug os-linux Linux OS (any supported distro)
Projects
None yet
Development

No branches or pull requests

10 participants