WIF passive federation with custom load balancer in place - wif

I'm implementing a simple load balancer - it's an http listener which parses incoming requests from browser and routes them to appropriate ASP.NET application. It listens on a certain port (8801) and when routing it preserves the original URI and changes only port number, e.g. https://machine.domain.com:8801/testsite/Default.aspx could be routed to https://machine.domain.com:8811/testsite/Default.aspx
With no security routing works just fine. The problem emerges when I try to apply WIF federation to the ASP.NET apps. I use ADFS 2.0. Here are two scenarios I tried:
scenario 1
relying party's WS-Federation passive endpoint is set to ASP.NET app URI
When load balancer URI is accessed through browser, load balancer routes to the ASP.NET app and the page gets loaded, however, the RequestSecurityTokenResponse from STS is redirected directly to the ASP.NET app (not the load balancer), according to the passive endpoint set up. So it works but since I want the entire communication towards ASP.NET app to be handled through the load balancer, this scenario doesn't meet my requirement.
scenario 2
relying party's WS-Federation passive endpoint is set to load balancer URI
When load balancer URI is accessed through browser, load balancer routes to the ASP.NET app, which returns Unauthorized response, browser redirects to STS, RequestSecurityTokenResponse is redirected back to the load balancer, but when further routed to the ASP.NET app, I get a response of 401 - Unauthorized: Access is denied due to invalid credentials. That's due to the URI mismatch I believe, as the saml token is issued for load balancer URI. I tried various combinations of audience uris and realms, but no success.
So my question is whether there exists a workaround that would enable load balancer handle all necessary federation communication, as my ASP.NET apps can only be accessed from the load balancer.
I hope I explained my problem clearly enough.
Help much appreciated
Thanks

Eventually the problem was somewhere else. What my load balancer actually does is to transform an incoming HttpListenerRequest to a new HttpWebRequest, which is then forwarded to the appropriate ASP.NET app. However, I didn't disable the auto redirect on the forwarded request so there were happening redirections from ASP.NET app to ADFS.
This code did the magic:
HttpWebRequest.AllowAutoRedirect = false;

In your relying party application web.config, can you confirm that your federatedAuthentication section looks something like this (the realm below should have your NLB port specified):
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="true" issuer="https://mysts.com/v2/wsfederation" realm="https://machine.domain.com:8801/testsite/Default.aspx" requireHttps="false" />
<cookieHandler requireSsl="false" />
</federatedAuthentication>
Also, another problem you should be aware of is the session cookie. WIF uses DPAPI by default to encrypt it, so you'll have to use RsaEncryptionCookieTransform instead. The same problem problem exists when using WIF in Azure. Here's an article that demonstrates how this is done:
http://msdn.microsoft.com/en-us/library/windowsazure/hh289318.aspx

Related

Authenticate .NET Framework 4.8 MVC behind AWS Load Balancer

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...

Why "requireSSL='true'" was throwing IIS error

I am working on MVC framework in ASP.NET where, I was trying to access the application but I was not able to go past the login screen, after which it kept throwing the not found IIS error. After workaround i found that i had this line : httpCookies httpOnlyCookies="true" requireSSL="true" in my web.config file which was stopping the access. Can anyone help me understand the problem and concept here?
Thanks already.
I was able to access the site after removing the requireSSL part only.
Web-config
httpCookies httpOnlyCookies="true" requireSSL="true"
Global.asax's Application Start :
if (ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Tls12) == false)
{
ServicePointManager.SecurityProtocol =
ServicePointManager.SecurityProtocol | SecurityProtocolType.Tls12;
}
I think the part of code in global.asax's Application Start might be causing the problem, but I'm not sure about it.
Websites use cookies to store information between page requests or browsing sessions.
The callback from an external provider to your site contains security tokens(httpCookies) that allow access to your site and contain user information.
If someone manage to steal other's authentication cookie for a website, he could carry out all the actions that they are capable of.
Transmitting this information over HTTPS to prevent interception while this information travels over the Internet is important
You can stop script access to all cookies in your site by adding a simple flag: HttpOnly. You can set
this flag in the web.config, as follows:
<httpCookies domain="" httpOnlyCookies="true" requireSSL="false" />
So If you write requireSSL="true" in your Web.config It Enforcing the external provider to make their callbacks to your site using HTTPS only.
#Vishesh Pandita In your case you are trying to access site using HTTP only. So faced "HTTP Error 403 - 403.4 Forbidden: SSL required" error.It means the page you are trying to access is secured with Secure Sockets Layer (SSL).
Solution:
To view the page, you must enable SSL (Secure Sockets Layer) by typing "https://" instead of "http://" at the beginning of the address you are attempting to reach. The "s" in "https" specifies a secure site.
Migration for HTTP to HTTPs
source : Professional ASP.NET MVC 5

Spring SAML Application using two IDPs and different URLs

I can’t seem to figure out how to use two different IDPS and 2 different applications URLs. I had this working on weblogic but not with a spring boot application using the spring saml security.
One important part is that we have two different URLs.
Proxy URL for external users. They must use this URL as they are not in the network.
a. These users hit IDP-A
Internal URL for internal users.
b. These users hit IDP-B
The metadata we sent to the each of the IDPs use the same entity ID but different endpoint URLs.
One thing we did was turn on discovery and where able to hit each IDP but it always redirects us to the internal URL. I noticed that AssertionConsumerServiceUrl is always set to the internal URL, which explains why it is returned to is the same. In our weblogic implementation we do not send AssertionConsumerServiceUrl.
Can we exclude AssertionConsumerServiceUrl?
Do you know if the configuration I am attempting to do is even possible?
you can autowire the MetadataManager bean in your service and then call the addMetadataProvider to inititate a metadata.
You can get the entityId from the Metadata Obtained from IDP and can append to the url :
'http:///saml/login?idp=' by hitting this url it will redirect you to appropriate IDP login.

Disable security verify SSL in oracle apex

I'm using Oracle Application Express 11g.
To secure RESTful services I want to create Third Party Authentication for it.
According to this article : http://www.oracle.com/technetwork/developer-tools/rest-data-services/documentation/listener-dev-guide-1979546.html
In order to register my third party user I need to access this url : https://server:port/ords/resteasy/ui/oauth2/clients/ as I don't have SSL every time I face this error(entring the url in http) :
403-Forbidden
This resource must be accessed over HTTPS only
The Question is : how can I disable "security verify SSL" in apex, in order that I never face this error again.
Note that there is no error like this in other pages because I'm not forced to use https, and I'm receiving this error entring the url in http.
https://docs.oracle.com/cd/E37099_01/doc.20/e25066/install.htm#AELIG7183
1.4.5 Using OAuth2 in Non HTTPS Environments
RESTful Services can be protected with the OAuth2 protocol to control access to nonpublic data. To prevent data snooping, OAuth2 requires all requests involved in the OAuth2 authentication process to be transported using HTTPS. The default behavior of Oracle REST Data Services is to verify that all OAuth2 related requests have been received using HTTPS. It will refuse to service any such requests received over HTTP, returning an HTTP status code of 403 Forbidden.
This default behavior can be disabled in environments where HTTPS is not available as follows:
Locate the folder where the Oracle REST Data Services configuration is stored.
Edit the file named defaults.xml.
Add the following setting to the end of this file just before the </properties> tag.
<entry key="security.verifySSL">false</entry>
Save the file.
Restart Oracle REST Data Services if it is running.
Note that it is only appropriate to use this setting in development or test environments. It is never appropriate to use this setting in production environments because it will result in user credentials being passed in clear text.

How to force Spring Security to make https redirect requests when behind a load balancer

We are currently using AWS ELB -> Apache in front of our Tomcat instance running Grails. We use Apache to redirect http requests to https requests. This works fine for us on our regular site. The issue arrives when trying to embed our site within an iframe on Chrome. Chrome does not like an https site redirecting to an http page (even if that page subsequently redirects to https). The reason this happens is that to Spring Security it looks like we're on http because we're behind a load balancer. Here is the network ping pong from Developer Tools:
Here is the problem when putting that same page within an iframe on Chrome.
We have found many solutions that will allow the Spring Security Grails plugin to redirect http requests to https request for certain URL patterns. Here and here are two of these examples. We have already solved this issue by having Apache intercepting http requests and redirecting to https.
The issue is that Chrome won't even make the http request within the iframe. We need an ability to tell Spring Security that even though the saved request you receive is using http, we need you to change that to https once you complete the authentication.
One solution we thought may work was changing to a relative URL using contextRelative instead of the absolute URL, which Spring Security views as http because of the ELB proxy. This post seemed to suggest the same, but the solution also did not change the URL generated when changing contextRelative to "true".
How can we tell the Grails Spring Security plugin to always either format the URLs as relative or force them to an https scheme so that we can run the application within an iframe in Chrome?
If you want to modify the SavedRequest then you can implement your own SavedRequestAwareAuthenticationSuccessHandler that will override the protocol when it pulls the saved request out of the cache and force it to be https.

Resources