Web api 2 - windows + client cert auth - is it possible? - asp.net-web-api

I currently have an asp.net web api 2 site hosted in IIS secured with windows authentication. A requirement has now come in for us to support client certificate authentication in addition to windows, and I'm struggling to find out:
- if this is possible at all
- if there are any working examples available
I thought might be able to add an additional owin middleware or messagehandler or filter, but can't see any existing ones that do this specifically for windows rather than just relying on IIS. I know thinktecture identitymodel can do client cert, but not sure if the two can be combined?
Example of forms +win that i thought might be similar is here https://techblog.dorogin.com/mixed-windows-forms-authentication-for-ajax-single-page-application-e4aaaac0424a

Right so I managed to figure it out. Thankfully, if a controller returns a 401, IIS automatically adds the negotiate/ntlm headers, so if a user is on a windows browser, it will then automatically authenticate as usual. So with that in mind, to keep windows auth working, I:
updated the site in both IIS and VS to allow anonymous AND windows auth
added the [AuthorizeAttribute] as a global action filter (which causes the 401 to be returned if the user is not authenticated by the time they hit the filter)
To get client certificate auth working, I used the magnificent Thinktecture.IdentityModel library, which allowed me to add only one line to my Startup.cs file (we're using OWIN so this was easy)
app.UseClientCertificateAuthentication();
See https://github.com/IdentityModel/Thinktecture.IdentityModel/blob/master/samples/OWIN/AuthenticationTansformation/KatanaAuthentication/Startup.cs for an example

Related

cross application (authentication) issue using react.js, spring, tomcat 8

My team is rewriting an existing web application that has a react.js front-end and springboot backend. In addition, The original (legacy) app is written in java (tomcat 8 & struts) and that will continue to be used for some parts of the site until a later date when we will complete the rewrite. All 3 endpoints are on the same domain in the following format: react.js (mysite.mydomain.com), spring (mysiteapp.mydomain.com), and legacy (mysite.mydomain.com/old). All 3 apps are hosted on the same server, but the application urls all route through our F5, so nothing is pointing to localhost. We did this to use the same SSL certificate across the three apps. The new and legacy apps use the same database. We are trying to make cross app calls between the new and old app. When we make the cross app calls, we want the user session to be maintained between them without them having to log in twice. We have not been able to get this to work. In our latest attempt to authenticate the user to both apps simultaneously, we are using ajax to sign the user into legacy with the same credentials. We are getting the following error back from the legacy tomcat application: HTTP Status 403 Invalid CSRF token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'. The server understood the request but refuses to authorize it. We are stumped at this point and out of ideas. Code can be provided on request, but we are looking for the best approach to how to implement this and not as much locked on this path described above.

asp.net Identity authentication .net core 2.1

I'm having an issue with a .net core 2.1 MVC application that is running on Linux boxes using kestrel behind an nginx web server. This environment has 2 web servers behind a load balancer.
The issue is the .AspNetCore.Identity.Application cookie used for authentication. I am able to authenticate and redirected to a controller decorated with the
[Authorize]
attribute (sometimes). However, on the next request, the cookie's gone and I get a 401. When we take one server out of the mix and force all traffic to one server, everything works as expected.
With Forms auth, the same problem could be overcome with specifying the machine key. What's the equivalent for .net core using identity? I found some links that went over my head. They mention doing something like this:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
I have no idea if this will fix the issue and I don't want to try things without knowing what they do.
I suspect what you experience has to do with data protection.
ASP.NET Core cookie authentication relies on the data protection layer to encrypt and decrypt data stored in the cookies. By default, a local key is created on each machine, meaning they can't decrypt cookies created by the other one, as stated in the official documentation.
I suggest that you go through the data protection configuration documentation page and evaluate your options. One of them is to store the keys on a UNC share and encrypt them with a certificate (all the links in this paragraph link to different sections of the same page).

authenticate Angular 2 against ADFS via Web API

I have an angular 2 app, a Web API with OWIN Pipeline (.NET 4.6) and an ADFS 3.0. Every user who uses the angular 2 app needs to be authenticated and authorized via ADFS and if he's already logged in the domain he should be logged in to the Application automatically (Single Sign On)
Something like that:
I read tons of links and code on how to achieve that but I fail to put the pieces together.
As far as I understand ADFS 3.0 only supports OAuth 2 Authorization Code Flow which is either not supported or advised with a JS Application respectively on the Web per se.
I'm not quite sure which it is but the fact is I can't/shouldn't use it.
I understood that therefore I have to implement somekind of Authentication server on my Webserver where my Web API is (maybe IdentityServer 3 or something "homemade").
This lead me to think that I should use ADFS as an external login like google, or facebook which would lead to the following workflow
User requests token
Web API checks if user is already logged in to the domain
Logged in?
forward request to ADFS and verify.
ADFS returns OAuth Token to WebAPI
not logged in?
show login mask to user
forward request to ADFS and verify.
ADFS returns OAuth Token to WebAPI
Web API return OAuth Token to user
Is this even correct or am I completly off?
Anyway I fail to put the pieces to together.
I saw a lot of code which creates JWT Tokens in Web API (but doesn't communicate with ADFS) or communicates with ADFS via WS-Federation.
Additionally ADFS' OAuth 2 implementation seems to a bit special which adds another layer of complexity.
so my question would be:
How can I provide OAuth tokens to the user while authenticating against ADFS?
If you need any additional information I happily provide it
You will need ADFS 2016 which supports Single Page Apps that use Angular.JS. See https://technet.microsoft.com/en-us/windows-server-docs/identity/ad-fs/development/single-page-application-with-ad-fs for the flow and sample code.
You are right that ADFS 2012R2 only support authorization code flow which is only meant for native apps which are public clients to talk to a web api.
Thanks
//Sam (Twitter: #MrADFS)

Consuming Sharepoint web services with ADFS claims-based authentication

We've recently switched one of our Sharepoint instance to use ADFS claims authentication instead of windows authentication. And now I can't seem to get the Copy service to work correctly from the server.
I've tried many methods, but none worked. Including the one found here suggested by another answer here on SO. In this case I get a 400 bad request when I call the login method.
I don't necessarely need to impersonate the user, but that would be great.
Any idea how I should do this?
Things that I have on the server to help authenticate:
IClaimsIdentity containing all the claims issued by ADFS
Bootstrap token (I tried to authenticate using it but no luck so far)
credentials for the system account (that I used when trying to authenticate with Sharepoint's authentication service)

ADFS v2.0 Error : MSIS7042: The same client browser session has made '6' requests in the last '1' seconds

Folks,
I've got an ASP.NET MVC application that I am attempting to secure using the Release Candidate version of ADFS v2.0 (Geneva). I have configured the application as a relying party trust, and I've used Fedutil.exe to modify the application's Web.config so that it has the information about the Geneva server and uses the Geneva server as its claims source.
However, when I try and hit the MVC app, it redirects to Geneva, which then (after warning me about self-signed certs) re-directs me to the MVC app again. After accepting both self-signed cert warnings, the two servers play ping-pong with each other in an infinite redirect loop until finally Geneva spews the following message:
The same client browser session has made '6' requests in the last '1' seconds. There could be a possible bad configuration. Contact your administrator for details.
There are no errors in the event logs on the MVC side or on Geneva except for an event containing the above message. If someone could give me some information on how to try and debug, diagnose, and hopefully fix this problem, I would be eternally grateful.
Again, the Geneva box is the ADFS v2.0 Release Candidate and the ASP.NET MVC site was built using the latest (late '09) version of the Windows Identity Foundation SDK with Web.config modified using FedUtil.exe from the WIF SDK.
So you will all get a kick out of this... I tried this same application from Firefox and ... IT WORKS. I get prompted for my domain credentials, the ADFS v2 server re-directs me ONCE and then I end up on the home page of my application, complete with my account name and personalized greeting.
So now the real issue is this: Why the hell is IE8 getting caught in an infinite redirect loop and Firefox ISN'T ??
After even further testing, I've been able to get this scenario working, out of the box, without modification of any of the default pipeline stuff from ADFS v2 (RC) or from WIF (RTW) on BOTH Safari AND Firefox. IE8 is the ONLY browser to exhibit any problem dealing with this authentication scenario. I've tried everything, including installing and trusting the self-signed certs, adding the sites to my local intranet zone and dropping security to low and even setting first AND third party cookies to always allow.
I had the same issue with ADFS 1.0
And to resolve it, I made sure that the URL had a trailing forward slash "/" that would always work in FireFox as well as IE
eg : https://somedomain.com/Application_2/
Turns out that the host name of the relying party had an underscore in it (khoffman_2). Apparently, the underscore is an illegal DNS character and ONLY IE will reject the information with the underscore in it.
I renamed my machine from khoffman_2 to khoffman2 and the ADFS v2/MVC relying party combination works flawlessly on Firefox, Safari, AND IE.
While this isn't your problem, we have had identical problems to what you described. Our solution was to:
Enabled Basic Authentication in IIS (this solved nothing but was required for the next 2 steps)
Disable Windows Authentication in IIS (this solved the problem for some IE browsers but not all)
Disable Anonymous Access in IIS (this solved the problem for the rest of the IE browsers)
Jaxidian's answer is close.
In my case I only had to:
Windows Authentication -> Disabled
Anonymous Auth -> Enabled
ASP.NET Impersonation -> Disabled
Forms Auth -> Disabled
Windows Auth -> Disabled
This loop can occur when a user is not authorized to access a page.
We had a custom authorization attribute on our MVC controller that checks to see if the user was in a role based on the claims provided if the setting for UseADFS was true in the config files. I thought this setting was set to true and was confounded that I kept getting the adfs loop when accessing the page because I was in the groups that were authorized to access the page.
The key to troubleshooting was to make a web page that displayed my adfs claims without necessarily requiring authentication.
#if (User.Identity.IsAuthenticated)
{
<div>UserName: #User.Identity.Name;</div>
var claimsIdentity = User.Identity as System.Security.Claims.ClaimsIdentity;
<table>
#foreach (var claim in claimsIdentity.Claims)
{
<tr><td>#claim.Type</td><td>#claim.Value</td></tr>
}
</table>
}
I noticed that I was getting logged into ADFS, and my claims were getting set, so ADFS was working. The actual issue was my config file had UserADFS="true" instead of UseADFS="true" which basically caused my custom authorization code to return false on authorization. Therefore, the page kept forwarding me back to adfs to authenticate again.
Anyways, if a user does not have the correct claims to access the page, then this adfs login loop can occur, as well.
Also, if you wrote a custom authorize attribute be sure to check out the following link which describes how to prevent the loop.
Redirect loop with .Net MVC Authorize attribute with ADFS Claims
Custom HandleUnauthorizedRequest handler code for AuthorizeAttribute from that link:
protected override void HandleUnauthorizedRequest System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
//One Strategy:
//filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
//Another Strategy:
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "u",
action = "LoginStatus",
errorMessage = "Error occurred during authorization or you do not have sufficient priviliges to view this page."
})
);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}

Resources