I'm struggling to understand some of this...
For some background, I am running a .NET Framework 4.8 ASP.NET MVC 5 Web UI application on an AWS EC2 instance behind an application load balancer. The load balancer is configured to authenticate via Azure AD.
I am fairly new to this world of Authentication in web applications so I'm trying to find examples of similar configurations or documentation describing my specific setup but mostly all I find is examples citing .NET Core (not .NET Framework).
Based on this documentation (Authenticate users using an Application Load Balancer), I know I am supposed to receive the headers X-Amzn-Oidc-Accesstoken, X-Amzn-Oidc-Identity, and X-Amzn-Oidc-Data from the load balancer. And indeed, if I check the headers, they are populated:
protected void Application_BeginRequest(object sender, EventArgs e)
{
var amznOidcData = Request.Headers.Get("X-Amzn-Oidc-Data");
var amznOidcIdentity = Request.Headers.Get("X-Amzn-Oidc-Identity");
var amznAccessToken = Request.Headers.Get("X-Amzn-Oidc-Accesstoken");
logger.Debug($"X-Amzn-Oidc-Data => {amznOidcData}");
logger.Debug($"X-Amzn-Oidc-Identity => {amznOidcIdentity}");
logger.Debug($"X-Amzn-Oidc-Accesstoken => {amznAccessToken}");
}
Great! Now, I know that the X-Amzn-Oidc-Data header contains a JWT containing my claims. I have found examples on how to decode the content of that header and I can pull out my ClaimsIdentity. Ok, I'm getting there! But, where exactly is the proper place to do this? Currently, I have this code inside my Application_PostAuthenticateRequest method within Global.asax.cs. I pull the ClaimsIdentity from the JWT and assign it to HttpContext.Current.User. Boom Request.IsAuthenticated is now showing true. Calls to Controllers with [Authorize()] are now succeeding when I load my first View.
However, this just not feel right. Yes, it seems to work for that first request to display Home/Index...but now, when the client-side javascript on that page tries to perform a callback to refresh some of the data in, let's say, a grid, I get CORS errors coming back from login.microsoft.com. Specifically:
Access to XMLHttpRequest at 'https://login.microsoftonline.com/...' (redirected from
'https://example.net/Home/Something') from origin 'https://example.net' has been blocked by CORS
policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
My assumption here is that those javascript callbacks are not recognizing that the application has already authenticated and so is trying again, on each call, to re-authenticate. I'm not sure what to do here short of marking each Controller method that would potentionally be called from the client as [AllowAnonymous()]. That seems like overkill and not what one should do.
So, my questions are these:
Where should I properly be reading in the JWT from the load balancer?
How do I properly configure my application to read that ClaimsIdentity from that JWT?
How do I ensure that client-side javascript calls to my application don't each need full callback to Microsoft to re-authenticate?
On that 2nd question, I've read a bunch of examples describing using OWIN middleware to authenticate against Azure AD...but how do I use the middleware with the JWT I already have from AWS?
Help me StackOverflow, you're my only hope...
Related
I have a route in my application that returns results from an LDAP query. I'm using a privileged account for this as it needs to return information that a regular account can't access.
Is there a way to deny users access to this route if they're not using it via one of the application's views? What I'm trying to prevent is a someone reverse engineering it and building their own app to gain access to the PII.
There is no reliable way to say this request originated from this view vs. this request originated from (e.g.) the command line.
An HTTP URL request doesn't have a verifiable source of origination. There is a "referrer" HTTP header which is intended for saying where the previous request originated, but it is not for security and completely spoofable, and not even always included in the request.
Somehow you'll need to authenticate the request. Don't invent your own way. Use devise or some other tested tool to build an authentication strategy, and figure out how to modify your application to work with existing conventions of HTTP request authentication (secure token, cookie based auth, etc.)
I have a Web Forms application which makes use of WIF and Claims based authorization. Im using Thinktecture IdentityServer v2.5 for my STS with my custom login page and custom authentication against database and then issuing the token.
Its all working fine at the moment and no issues, the only problem came when I was configuring Sliding Sessions as shown by Brock Allen in this post
http://brockallen.com/2013/02/17/sliding-sessions-in-wif-with-the-session-authentication-module-sam-and-thinktecture-identitymodel/
My problem is that the event mentioned in the post SessionSecurityTokenReceived is getting called too many times per page load. I just wanted to know what is the reason behind that and could this be a performance hit ?
I'm doing something similar and have come across the same issue. It is because the event is called for every single resource the page consumes (css, js, etc) that is also secured by the web application. In global.asax.cs, in the event, if you insert the line...
var requestContext = HttpContext.Current.Request.RequestContext.HttpContext.Request;
...and put a breakpoint on this line, you can observe this behavior by inspecting the value.
How does the new routing service deal with security? According to http://blogs.microsoft.co.il/blogs/applisec/archive/2011/12/12/wcf-routing-and-message-security.aspx, it might be difficult when default windows security is not chosen (typically a simple username/password scenario).
Can wcf routing actually support a scenario where the router receives a WS-Security secured message over HTTP and forwards it to another server over HTTP, without unwrapping the security token?
My scenario is as follows:
A server (relying party), a custom STS with username/password authentication and a client. We use ws2007FederationHttpBinding and message security.
Now we setup wcf routing, it works with basicHttp or wsHttp.
Then we using WIF, we can instanciate proxies, the STS generates claims, but it fails at the first service call. It seems the router is waiting for the certificate definition (included, otherwise we get an error), then seems to require Cardspace UI (while in fact we're using username/password).
If so, would you have an example ?
Thanks.
Good question, i couldn't find anything about this on google yet beside this question also being unanswered on msdn. I don't think this is added out of the box as normally u would need to use delegatation (ActAs) whenever u want to route the request to another service.
The only solution i can think of is creating a message inspector and use that one in your WCF Routing Service. And ofcourse u'll need to use "SupportInteractive = false"
I did found something that might be the answer, see the following post (ignore silverlight lol) http://zamd.net/2011/02/08/silverlight-claim-based-security/
Zamd says:
For the 2nd part I have implemented a message inspector along with an extension method which makes it super easy to attach the SAML with outgoing messages.
I have an application a the moment which for a particular set of reasons will be interacting oddly with the hosting server.
The application is to be accessed through a larger portal and can be encapsulated within the portal display, however it makes extensive use of AJAX requests which are not intercepted by the portal. These requests are made directly to the hosting server, however I am seeing a problem.
When the first ajax request is made (a little way into the application flow) the Ajax request is not carrying with it the JSessionId cookie (obviously as it's sending this to a different server than it received it from)
Is there a good grails way to find the session the AJAX call should be interacting with. I have tried setting grails.views.enable.jsessionid to true, but this only works if the browser is not accepting cookies.
Create a hidden form input value that has the jsessionid in it on the page you send back to the portal on the first request. Then read that form variable, and set the cookie in your javascript code that makes the AJAX request.
I'm guessing seeing that this already works, cross-site scripting isn't an issue? AJAX requests to domains other than that which the main page originated from will be blocked by the browser.
The most reliable way will be for you to set up your own "cookie" and pass that along with the requests.
It sounds like you are running into issues due to the portal and it's cookies and then having to continue that "session" onto a different server. Your application needs to simply handle it's own sessions itself in order to prevent getting stomped on by the "normal" cookies.
The idea is essentially to create a session token when the portal makes a request from to your application, and then the subsequent AJAX calls your application makes back to it's own server should include that token. You can then easily associate that token with the session you need to be using.
If you are looking to make it a bit more robust and handle it above the level of your application, you can leverage the fact that Grails is built on Spring MVC deep down and override the default session handler to pick up on whatever mechanism you decide to go with. I'm not sure of exactly how to do this with Grails, but I've done similar things on Spring MVC projects and it isn't too tough once you get your head wrapped around the various injection points of the framework.
It isn't ideal, since there is now a fair bit more complexity, but in theory, the benefits of the portal are outweighing the added complexity required for traditionally "handled" things like sessions and expiring them, etc.
i'm trying to goto the following url :-
http://user1:pass1#localhost:1234/api/users?format=xml
nothing to complex. Notice how i've got the username/password in the url? this, i believe, is for basic authentication.
When I do that, the Request Headers are MISSING the 'Authorize' header. Er... that's not right :(
I have anonymous authentication only setup on the site. I don't want to have anon off and basic turned on .. because not all of the site requires basic.. only a few action methods.
So .. why is this not working? Is this something to do with the fact my code is not sending a 401 challenge or some crap?
For What It's Worth, my site is ASP.NET MVC1 running on IIS7 (and the same thing happens when i run it on cassini).
Update:
If this is an illegal way of calling a resource using basic auth (ala security flaw) .. then is this possible to do, for an ASP.NET MVC website .. per action method (and not the entire site, per say)?
If you want to use basic authentication, the first request to the resource needs to return a HTTP 401 error code, and set a WWW-Authenticate header. This will instruct the browser to actually send those credentials.
You mentioned you're using ASP.NET MVC. You might be able to do this via the web.config, but I'm not sure on the exact mechanics.
My company makes a product called the Neokernel Web Server (http://www.neokernel.com), it is an ASP.NET web server with support for basic authentication among other features.
You specify protected resources in an apache-style config file so you could put your "protected" actions in a folder requiring authentication and put everything else in the root / unprotected. Look at the "http.authentication" file installed in the Neokernel root directory for an example, or at the authentication samples in the demos.zip file.