Owin WebApi 2 Hostname IntegratedAuth Failing - 400 error and bad credentials - c#

I have an intranet application using OWIN self hosting to serve a SPA/WebAPI 2 type site. Everything works great as localhost:port, and IP:port, but hostname:port fails for IE and Chrome. Yet the application works with FireFox.
I believe this is due to the integrated authentication. Chrome returns ERR_INVALID_AUTH_CREDENTIALS, and IE returns 400 bad request. Fiddler doesn't show much difference in the headers of the request/response, except that the Authentication comes through and I get a 200 in FF, a 400 in IE and a 401 in Chrome.
Most of my code was "borrowed" from SO articles or MSDN tutorials.Here's my Program.cs:
string baseAddress = "http://*:9000/";
using (WebApp.Start<Startup>(new StartOptions(baseAddress) { ServerFactory = "Microsoft.Owin.Host.HttpListener" }))
{
// Keep server operational till stopped
Console.WriteLine("Started, Press any key to stop.");
Console.ReadKey();
Console.WriteLine("Stopped");
}
Here's my startup.cs:
public void Configuration(IAppBuilder appBuilder)
{
var listener = (HttpListener)appBuilder.Properties["System.Net.HttpListener"];
listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
appBuilder.UseWebApi(config);
appBuilder.UseFileServer(new FileServerOptions
{
RequestPath = new PathString(string.Empty),
// path to static files.
FileSystem = new PhysicalFileSystem("./public"),
EnableDirectoryBrowsing = false
});
}
I also made sure to set the url reservation using netsh:
netsh http add urlacl url=http://*:9000/ user=Everyone
Both IE and Chrome attempt the intranet model of Integrated Authentication and attempt to send the credentials immediately in all of our intranet applications. FF always prompts for credentials and never auto-authenticates. This has me leaning towards authentication as the problem.
Does anyone have an idea for what I can check to validate the authentication side of things? Fiddler didn't illuminate the request very well. Breakpoints never seem to get touched in the app when requesting against the host.
I think there could be a group/local policy that is getting in the way of proper authentication, but I'm not certain where to start looking.
*edit - updated tags
*update
Some further testing indicates that forcing auth to NTLM (versus integrated) allows Chrome to auto-logon, FF to work the same as it always did, and IE in a weird place.
IE will autologon, but then fail to load the JS on the page, or Prompt for a user and then login properly depending on FQDN vs shortname. I believe this is due to the default IE behaviors and trusted/intranet site settings.
I now have a work around, but it'd still be nice to figure out kerberos if anyone has any ideas.

Change the code to
HttpListener listener = (HttpListener)app.Properties["System.Net.HttpListener"];
listener.AuthenticationSchemes = AuthenticationSchemes.Ntlm;
In Self Host Web API, it solved the issue.

Related

Blazor WASM authentication in Chrome Incognito

I do have a Blazor WASM (.NET 6) application that is using an Identity Server hosted on different URL for authentication.
I'm configuring the authentication like this:
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = configuration.OidcAuthority;
options.ProviderOptions.ClientId = configuration.OidcClientId;
options.ProviderOptions.ResponseType = configuration.OidcResponseType;
options.ProviderOptions.PostLogoutRedirectUri = configuration.OidcPostLogoutRedirectUri;
options.ProviderOptions.RedirectUri = configuration.OidcRedirectUri;
options.ProviderOptions.DefaultScopes = configuration.DefaultScopes;
});
Everything works great locally and in production as well.
The problem occurs when I want to open the page in Chrome Incognito window with Third party cookies disabled.
I see in the browser that during authorization process I receive cookies with SameSite=None and Secure=true, but this cookie is not send with
https://login.myidserver.net/connect/authorize?client_id=myclientid&redirect_uri=h...
as oppose to normal Chrome window.
Because of that I receive back
https://localhost:12345/authentication/login-callback?error=login_required&state=....
and access_token is not saved in session storage as it should be.
Is there any way to overcome this and force the cookie to be used in this case?
Or am I misunderstanding something?
All the solutions I've seen on the internet seems not to work for me.
Edit:
Ok, why is authorize called right after sucessful authentication and receiving of the token?. I understand I cannot force to send this cookie but can I somehow avoid do this authorize call when I'm right after successful login?

C# GCP auth2.0 403 mismatch redirect

I'm using this code to try to get the auth from Google:
await HttpContext.ChallengeAsync("Google", new AuthenticationProperties() {RedirectUri = "/"});
The thing is the redirect always take the HTTP url even if I'm running it from https url.
The url with https://something-sss.com is already whitelisted on the GCP API identifiers.
But it always take the Uri with http
To expose my docker app I used to use Expose http://*:80 and even if the associated domain was started with an HTTPS, inside the app it was always an HTTP call, so all the redirects were done through the http protocol.
I have changed the way I expose my app from http://*:80 to https://*:443 in the code I used kestrel to launch the app and it's working perfectly now.

OWIN OpenIdConnect Middleware IDX10311 nonce cannot be validated

I have an application using the OWIN middleware for OpenIdConnect. The startup.cs file uses the standard implementation of app.UseOpenIdConnectAuthentication. The cookie is set to the browser, but it errors with:
IDX10311: RequireNonce is 'true' (default) but validationContext.Nonce is null. A nonce cannot be validated. If you don't need to check the nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'.
I've found that when running fiddler as I do for most debug projects this behavior happens. The error is returned, but if I go back to the site everything is working and my user is authenticated. Has anyone seen this behavior when running fiddler?
With fiddler:
SecurityTokenValidated notification in OpenIdConnect is executed twice.
After the second pass through the IDX10311 error is thrown
Browser contains the valid cookie, going back to the page I can view the valid User.Identity data.
Running without fiddler:
SecurityTokenValidated executes once in OpenIdConnect
No error thrown, proceeds to load up controller action for post authentication redirect Uri
Cookie also valid and User.Identity data correct.
Ideas? I can get around it without running fiddler, but when debugging it would be nice to also run fiddler to inspect traffic.
Maybe is this the cause?
Hello there, I think I found the root cause of this issue.
I'm summing up my discoveries:
The problem is in the OpenIdConnect.nonce.OpenIdConnect cookie
This cookie is set from the app (let's call this "ID Client") as soon as the OpenID Middleware init an authentication session
The cookie should be sent back from the browser to the "ID Client" as soon as the authentication has been completed. My assumption is that this cookie is needed to have a double check from the ID client point of view (i.e. did I really started an OpenID Connect authorization flow?)
A lot of confusion in me was caused by the "Nonce" term, used both in this cookie and in the OpenID Connect flow from the ID server.
The exception, in my case, was caused by the missing cookie (not the nonce of the ID Server), simply because it wasn't sent by the browser back to the "ID client"
So the main root, in my case, was this: OpenIdConnect.nonce.OpenIdConnect cookie was not sent back to the ID Client by the browser. In some cases (i.e. Chrome, Firefox and Edge) cookie was sent correctly, while in others (IE11, Safari) it wasn't.
After a lot of research, I discovered that the problem was on the Cookie restriction policy, defined on the browser. In my case, the "ID client" is embedded in an <iframe>. This cause the "ID Client" to be seen as a "third-party client", because the user didn't navigate to that URL directly in the main window. Because this is a third-party, for some browsers, it's cookies have to be blocked.
Indeed the same effect may be obtained on Chrome, by setting "Block third-party cookies".
So, I have to conclude that:
a) If iframe is a must (as in my case, because "ID Clients" are apps that must run inside the graphic content of the our main platform app), I think the only solution is to intercept the error, and handle it with a page, asking the user to enable third party cookies.
b) If iframe is not a must, it should suffice opening the "ID Client" in a new window.
Hope this helps somebody, because I got crazy!
Marco
I had the same problem but switching back the Microsoft.Owin.Security.OpenIdConnect to version 3.0.1 solved the issue
For anyone else who gets here in 2021, you'll likely get this issue if:
You're redirecting http -> https
Or you've changed your app's host domain.
Both of these aren't an issue with the middleware or your app, but it's about the combination of two issues:
The fact that your app is still hosted on the old old domain or protocol. You want to prevent browsers hitting that by implementing a redirect on the web server.
The redirect URI (sometimes know as reply URL) in Azure or whichever OpenIdConnect authorization server you're authenticating with. You want to get this updated to the new protocol or domain.
Our example: We had https://old.example.com/app/ that was now also hosted at https://new.example.com/app/. We wanted users' previous bookmarks to still work.
Our solution:
We updated the redirect URI (reply url) to point to the new domain for the app (https://new.example.com/app/signin-endpoint). Ideally, make sure there is only one URI listed for your app and that it's https.
We added the new domain binding to the site in IIS (we're old school, but do the same for your hosting of choice 😊)
We added an IIS redirect to the new domain (new.example.com) so that users' bookmarks still work. Again if you're not on IIS, implement a permanent redirect in the web server of your choice.
Until we had the final step above, we were seeing the error in the OP's post. It's the same process if you're forcing http -> https.
Here is the IIS re-write for those who are also "old school":
<rewrite>
<rules>
<rule name="Redirect old.example.com to new.example.com" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
<match url="*" />
<conditions>
<add input="{HTTP_HOST}" pattern="old.example.com" />
</conditions>
<action type="Redirect" url="https://new.example.com{REQUEST_URI}" />
</rule>
</rules>
</rewrite>
It goes in the <system.webServer> section of your web.config file. Enjoy!
For me changing reply url in Azure active directory works.
This happens when you enable SSL because it changes only the sign on URL to the HTTPS URL while the reply URL remains the same HTTP URL.
When you try to access your app using the https URL, it sets a cookie with a unique number(nonce) in your browser and hits Azure AD for authentication. After authentication, the browser has to give access to that cookie. But since the sign on URL and reply URL are different the browser does not recognize your app and does not give access to that cookie and hence the application throws this error.
I know its an old post but I had this problem and nothing was working for me, after lose my mind behind a solution to make my enterprise application works I end up fixing it by setting the multi-tenanted option to yes in azure (in Azure select: app registration>settings>properties, set multi-tenanted to yes and click save).
hope it helps someone, couldn't see nobody mentioning it.
I noticed this error when running IIS Express in the background when I had switched to hosting in full IIS. When I disabled the IIS Express, my error went away.
A cookies rewrite rule in the web.config to ensure samesite cookies gave this cryptic exception. Disabling that rule solved it.
A temporary solution which worked for me for an app secured via Azure Active Directory was to signout (by going to the sites/Account/SignOut page) and then I was able to return to the home page and sign in ok. Hope this helps someone.
I know it's been a while on this one. My specific issue was with the IDX10311 error in relation to authenticating with IdentityServer while Fiddler (traffic inspector proxy) was running. I added a custom owin middleware to catch and absorb the IDX13011 in the case where the hostname contained "localhost". Ignoring this exception allowed us to use the site with fiddler as a workaround. I think it causes breaks in the authentication process though where we have to press enter in the browser address bar on the callbacks to get it going again, but this only affects development.
Here's the invoke method we used in the middleware to absorb the error. I should note though that we have seen this error in production occasionally as well. No explanation for a cause, but I have a feeling it is related to users on IE browsers.
public override async Task Invoke(IOwinContext context) {
try {
await Next.Invoke(context);
} catch (Exception ex) {
_errorHandling = new ErrorHandling();
if (ex.Message.Contains("IDX10803")) {
//do something here to alert your IT staff to a possible IdSvr outage
context.Response.Redirect("/Error/IdSvrDown?message=" + ex.Message);
} else if(ex.Message.Contains("IDX10311") && context.Request.Host.Value.Contains("localhost")) {
//absorb exception and allow middleware to continue
} else {
context.Response.Redirect("/Error/OwinMiddlewareError?exMsg=" + ex.Message + "&owinContextName=" + lastMiddlewareTypeName);
}
}
}
For me it was a different problem. My site was working with both of the urls below
https://www.example.com
and
https://example.com
But my redirect url was https://www.example.com.
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["ClientId"].ToString(),
Authority = ConfigurationManager.AppSettings["Authority"].ToString(),
RedirectUri = ConfigurationManager.AppSettings["RedirectUri"].ToString();//https://www.example.com
}
Users who use https://example.com the mentioned exception occurs.
The cookie generated for www.example.com and example.com are different. So after the login when it redirects, the cookie doesn't contain the correct nonce to validate and the exception occurs.
The solution for the problem is to set the redirect URL dynamically
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["ClientId"].ToString(),
Authority = ConfigurationManager.AppSettings["Authority"].ToString(),
RedirectUri = ConfigurationManager.AppSettings["RedirectUri"].ToString(),//https://www.example.com
,
// sample how to access token on form (when adding the token response type)
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = async n =>
{
var uri = n.Request.Uri; //From request URL determine the RedirctUri and set below
n.ProtocolMessage.RedirectUri =""//Set the url here
}
}
}
The same issue can happen with https://www.example.com and http://www.example.com
Users where getting this issue when Edge was set to IE compatibility mode, removed it from IE compatibility and it solved the issue. Setting / list of sites is controlled under edge://compat.
I end up allowing the Owin to skip to the next Middleware on AuthentificationFaild callback function. I'm checking if the error message contains nonce error Id and call SkipToNextMiddleware function from the context. With that, I'm restarting the sign-in process so if the user cookies were not set there will be a second call that will set the cookie.
The code is written in vb.net
Dim oidcAuthOpt= New OpenIdConnectAuthenticationOptions()
oidcAuthOpt.Notifications = New OpenIdConnectAuthenticationNotifications With {
.AuthenticationFailed = Function(n)
If (n.Exception.Message.StartsWith("OICE_20004") Or n.Exception.Message.Contains("IDX10311")) Then
n.SkipToNextMiddleware()
Return Task.FromResult(0)
End If
Return Task.FromResult(0)
End Function
}

Basic Authentication redirects to login page instead of returning an auth challenge

I needed to support, in addition to standard out-of-the-box cookies/forms authentication, also Basic Authentication over HTTPS for SignalR. SignalR runs in the context of a mixed MVC/WebApi site.
After putting the pieces together how to implement this, I used ThinkTecture.IdentityModel.Owin.BasicAuthentication library for this on the server, like this:
app.Map("/basicauth", map =>
{
map.UseBasicAuthentication("realm", ValidateUser);
map.MapSignalR<AuthenticatedEchoConnection>("/echo");
map.MapSignalR();
});
But instead of returning a challenge, I always get a HTTP 302 response that redirects to the Login page of the MVC site. To better debug this, I quickly rolled my own simple OWIN middleware for basic authentication and got the same result. Further testing with a simple mapping like this:
app.Map("/test", map =>
{
map.Use((context, next) =>
{
// context.Response.StatusCode = 401;
context.Response.Write("Hello World!");
return Task.FromResult(0);
});
revealed that a simple "Hello World" response is returned normally. But when I comment out the the line that sets the response code to 401, I get the redirect to the Login page again. I do not understand this behavior ... why does my MVC site gets involved here and not the 401 response is returned? How can I prevent this?
For OWIN, besides the special /basicauth map above, I had only the top level SignalR mapping in the startup method defined that should continue to work for all cookie authenticated calls:
app.MapSignalR();
Nothing else had been configured by me for OWIN.
Can anybody help me with this?
Ok, I found a way to work around this issue. The first part is to throw out map.MapSignalR<AuthenticatedEchoConnection>("/echo"); from the first sample - it is not necessary and for some reason I not found out it prevented SignalR from working properly.
The second part, and the workaround for the actual problem, is that in the client I also send the credentials with the first request and do not wait for a challenge. Thus, a 401 never happens and so no redirect to login page. And that's good enough for me.
So the workaround is, in the client, do not use NetworkCredential like this:
connection.Credentials = new NetworkCredential(username, password);
Instead, add the Authorization header yourself so it is included already in the first request:
string creds = string.format("{0}:{1}", username, password);
string encodedCreds = Convert.ToBase64String(Encoding.Utf8.GetBytes(creds));
connection.Headers.Add("Authorization", "Basic " + encodedCreds);
In addition, what I found out is that with OWIN, this issue seems to be a more general one and not only related when used with SignalR or even Basic Auth:
http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
Thus, with some modifications to the basic authentication module, it should also be possible to prevent this redirection. I might look into this and will update this post when done.

401 unathorised when using windows authentication to access web services

I have a asp.net mvc 4.0 web application that attempts to use windows authentication to authenticate against some web services. its hosted in iis7
The web services are autodesk vault 2011 web services, I present the user with a login screen where they can use a vault user account or they can use their windows login. There is no issue with using a vault account it logs in via the vault web services and call the various vault web services such as pulling data out of the vault. no issues here
When trying to log in using windows authentication then I get a 401 error when accessing the web services
I think that it could be a double hop issue so the server admins are going to enable Kerberos so we can at least eliminate this as a possibility. In the live environment the site and web services are located on different servers.
However for testing I have a virtual machine setup and the site and web services are on the same machine and I still get a 401 issue so maybe it is an iis configuration issue and not a double hop issue as originally thought
I have tried the following but with no success
I have added the following code to the winauthservice (I have wrapped the web services so that I can override the invoke and I have created a factory class to instantiate the services)
this.UnsafeAuthenticatedConnectionSharing = true;
var credentialCache = new CredentialCache();
credentialCache.Add(new Uri(this.Url), "NTLM", new NetworkCredential(identity.Name, identity.Password.ConvertToUNSecureString(), identity.Name.Substring(0, identity.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase))));
this.Credentials = credentialCache;
I have also tried it with Negotiate instead of NTLM
I have disabled the loopback check in the registry and I have added the server name and localhost to the BackConnectionHostNames registry entry
I have disabled anonymous authentication for the web site in iis and enabled windows authentication. In the providers for windows authentication I have removed negotiate and just left NTLM as saw a post recommending to do this.
In the web.config I have set authentication mode = windows
I have the following in my IIS logs
2013-09-25 09:11:05 fe80::9565:6102:fe2d:8f41%10 POST /AutodeskDM/Services/WinAuth/WinAuthService.asmx - 80 - fe80::9565:6102:fe2d:8f41%10 Mozilla/4.0+(compatible;+MSIE+6.0;+MS+Web+Services+Client+Protocol+4.0.30319.296) 401 2 5 11572
2013-09-25 09:11:05 fe80::9565:6102:fe2d:8f41%10 POST /AutodeskDM/Services/WinAuth/WinAuthService.asmx - 80 - fe80::9565:6102:fe2d:8f41%10 Mozilla/4.0+(compatible;+MSIE+6.0;+MS+Web+Services+Client+Protocol+4.0.30319.296) 401 1 3221225581 10
I'm running out of ideas as to what the issue could now be, but my thought is if I can get this working in my test vm then I may have more luck in the live environment
I had problems with authentication surviving a redirect when using a HttpWebRequest object, but I'm not sure if this is your problem. I noticed the redirect and the missing authentication using Fiddler2.
What I had to do was to set PreAuthenticate = true on the HttpWebRequest object
HttpWebRequest request;
request = (HttpWebRequest)WebRequest.Create(uri);
request.PreAuthenticate = true;
request.Credentials = new CredentialCache {{uri, "Basic", credentials}};
But, like I said, I'm not sure if this applies in your situation though.

Categories

Resources