13

I am having an issue where an app tries to access resources from the same server using different authentication methods, the two methods are:

  • Credentials (NTLM, Basic, etc)
  • OAuth (Bearer)

Setup HttpBaseProtocolFilter

The HttpBaseProtocolFilter is setup to:

  • disable Caching
  • disable automatic UI credential request popup

Code

HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
filter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache;
filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.MostRecent;
filter.AllowUI = false;

Adding Server Credential

If the resource needs credentials then I use:

filter.ServerCredential = new PasswordCredential(
                RequestUri.ToString(),
                UserName,
                Password);

HttpClient httpClient = new HttpClient(filter);

Adding OAuth Token

If the resource needs a Bearer token I use:

HttpClient httpClient = new HttpClient(filter);
httpClient.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Bearer", token);

The ServerCredential are null

filter.ServerCredential = null

Getting response from server

using(httpClient)
{
   using(HttpRequestMessage requestMessage = new HttpRequestMessage(new HttpMethod(method), RequestUri))
   {
       using(HttpResponseMessage response = await httpClient.SendRequestAsync(requestMessage))
       {
           // Do something with response
       }
   }
}

The issue

If the HttpClient request returns a 200 (OK) using ServerCredential, then every following Bearer request also returns 200 (OK) even if the Bearer token is invalid and filter.ServerCredential is null.

It looks as if the filter.ServerCredential is cached and all subsequent calls are authenticated with the cached credentials.

I have to restart the app if I want to do a Bearer authentication.

How can I remove, disable or clear the ServerCredential of the Windows.Web.Http.HttpClient?


Things I've tried:

Deleting all cookies

var cookieManager = filter.CookieManager;
HttpCookieCollection myCookieJar = cookieManager.GetCookies(RequestUri);
foreach (HttpCookie cookie in myCookieJar)
{
    cookieManager.DeleteCookie(cookie);
}

The myCookieJar is empty.

Something with PasswordCredentialPropertyStore

Windows.Security.Credentials.PasswordCredentialPropertyStore credentialPropertyStore = new Windows.Security.Credentials.PasswordCredentialPropertyStore();

The credentialPropertyStore is empty.

AND

PasswordCredentialPropertyStore's method Clear is reserved for internal use and is not intended to be used in your code.

Any ideas?

Barnstokkr
  • 2,904
  • 1
  • 19
  • 34
  • With no knowledge whatsoever I will guess that maybe you can use `HttpClient` in a `using` block and close for every different request. As an workaround of course. – Vitor Canova Jun 09 '15 at 12:04
  • That's actually what I'm doing.. :( – Barnstokkr Jun 09 '15 at 12:08
  • Very strange it keeping credentials even after left `using` block. Looks like it is beeing cached at user level in the O.S. – Vitor Canova Jun 09 '15 at 18:24
  • If this is for windows 8.1, Do you find the password in Credential Manager in control panel after the request is finished? You can try to clear password credentials for this requested Uri, `try { var credentials = _vault.FindAllByResource(PasswordVault); foreach(var passwordCredential in credentials) { _vault.Remove(passwordCredential); } } catch { // ignored }` – Ahmed Rashad Mohamed Aug 24 '15 at 15:47
  • Did you try using `System.Net.Http`? – kiewic Sep 08 '15 at 11:51
  • @kiewic in Windows 8 there was cookie sharing between `System.Net.Http` and the Webbrowser control, but in Windows 8.1 the `System.Net.Http` api does not integrate with the `Windows.UI.Xaml.Controls.WebView` for authentication; the only one that does is `Windows.Web.Http`. – Barnstokkr Sep 08 '15 at 12:26
  • Right, if you need integration with `WebView`, then it is not an option. – kiewic Sep 08 '15 at 12:29

4 Answers4

3

Thanks for reporting this issue. This is a known behavior in the low level WinINet HTTP stack that sits underneath the Windows.Web.Http.HttpClient API in the operating system. Once an HTTP request succeeds, the credentials are cached in the process memory for that app. Hence, even if you create a new HttpClient instance and set different credentials into the HttpBaseProtocolFilter, the same (original) credentials apply and will be used as long as they continue to be valid on the server side. (If the cached credentials stop being valid on the server side, they will be overwritten with the newly supplied ones.)

We are aware of this issue and are working on correcting it by allowing the clearing of cached credentials. Unfortunately, the only workaround currently is having the user restart the app which will clear the process memory for the app. That will allow a different credential to be used at first. However, that credential will also 'stick' for the remainder of the application process as long as it is valid on the server.

Thanks,

Sidharth Nabar [Windows Networking team]

  • Sidharth: Thanks for this answer. This is a major problem for us. It didn't happen in Windows 8.1 when using the System.Web HttpClient, but since you now use WinInet under the covers in UWP, existing code (and more importantly SDKs) running in the context of a UWP app could have major security issues since signing out no longer works. This should be a high priority issue. – dotMorten Nov 06 '15 at 19:16
  • Hi @dotMorten, We have now fixed this issue and the fix is included in the Insider build 10586 (http://blogs.windows.com/windowsexperience/2015/11/05/announcing-windows-10-insider-preview-build-10586/). Please try compiling your app on this build. Also, a slight correction in terminology - I think you mean "System.Net.Http.HttpClient" and not "System.Web HttpClient", correct? Thanks – Sidharth Nabar Nov 06 '15 at 21:50
  • Thanks @sidharth. However I can still reproduce the issue. I'll shoot you an email with a repro. – dotMorten Jan 07 '16 at 17:03
1

Just append

uwp_bugs_never_got_fixed={something never repeat}

in your request URL query parameters.

Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
Vangelis
  • 11
  • 1
1

This issue has now been resolved and the fix is included in the //build 2016 version of the SDK. There are two parts to this fix:

  1. In Windows build 10586 onwards, new credentials can overwrite older cached values in the same app. So, if you were using an instance of HttpClient c1 with (userA, paswordA), and then created a new client instance c2 with (userB, passwdB) in the same app: this should work. The new credentials overwrite the old cached ones (this would not work in earlier versions).

  2. However, #1 is still not sufficient to let you clear the original cached credentials - you can only overwrite them. To support clearing of cached credentials, we have now added a method to HttpBaseProtocolFilter - HttpBaseProtocolFilter.ClearAuthenticationCache() which clears all cached credential information. You can call this when you want to clear the credentials and/or client certificates from past instances of HttpClient in your app. The documentation for this method will soon be available here

Thanks Sidharth

[Windows Networking team]

  • Thank you Sidharth. I'm working on a UWP App running om 10586, but I don't see any `HttpBaseProtocolFilter.ClearAuthenticationCache()` available??? I'm running VS 2015 w/ update 2 and "Tools (1.3.1) and Windows 10 SDK (10.0.10586)" have been installed. What am I missing? – 1iveowl Apr 22 '16 at 12:59
  • @JasperHedegaardBojsen - the ClearAuthenticationCache API was added only recently (10586 is the Nov. 2015 version). Please use the Windows anniversary SDK preview (version 14295) through the Windows Insider program - http://insider.windows.com/ – Sidharth Nabar Apr 28 '16 at 21:53
0

For whomever is facing this issue ;

I had the same issue with Basic Credentials on a UWP Phone app ; Once a user got authenticated succesfully once, it cached those credentials. Even when closing the app, even when restarting the phone. I honestly suspected a bug on the server end or so, but there was a similar App which worked as expected against the same server.

I found that adding :

filter.CookieUsageBehavior = HttpCookieUsageBehavior.NoCookies

solved my issue. When entering proper credentials all was fine, when retrying with false credentials authentication failed. Exactly as it is supposed to do !

F. Hanhart
  • 11
  • 2