I'm having great difficulty working out what's going on with a Grails 2.2.5 application which uses the Shiro plugin (v.1.2.1). This is on a system which has been working fine for a couple of years. It sits behind an nginx remote proxy server, which has hitherto been listening on ports 80/443. We've just moved the test rig, and it now shares a server with an Apache installation which has those ports, so we have nginx listening on ports 8070 for http and 8443 for https. It's largely working, but there are some puzzling problems with redirects when a user is not authenticated, and these problems seem to be coming from Shiro (although I'm having difficulty being certain).
Basically what's happening is that when an unauthenticated user goes to 'https://myapp.com:8443/admin/', the Grails application is issuing a redirect which takes them to 'https://myapp.com:8443/auth/login?targetUri=%2F' - i.e., the context has been stripped out. It should be 'https://myapp.com:8443/admin/auth/login?targetUri=%2F', and is so on the live server, which uses the standard ports (80/443). In fact, when I look at the Location header in the response, what it's actually responding with is 'http://myapp.com:8070/auth/login?targetUri=%2F' (i.e., with the http port, which is no problem as nginx is handling SSL).
Because my code, in AuthController.groovy, doesn't actually get involved until it receives the /auth/login request, this problem doesn't seem to be coming from anywhere in my code, and must be coming from the Shiro plugin. But why would the non-standard port be causing this problem (stripping out the context)? And more importantly, what can I do to solve it?
I think I may have been wrongly ascribing blame to Shiro or the Shiro plug-in here. I have solved the problem, which seems to be caused by a quirk in Grails itself.
In version 1 of Grails, one had to set grails.serverURL correctly in Config.groovy in order for redirects to work properly, but with version 2 that was no longer necessary, and in fact this property was commented out in a newly created app.
However, whatever was done doesn't seem to play nicely with non-standard ports. If the server port is something like 8070 or 8443, as I was using the redirect is incorrectly formed.
I have resolved the issue by reinstating grails.serverURL and making sure it's configured correctly. Now redirects work as they should again.
Related
From the Electron renderer, I am accessing a local GraphQL endpoint served by a Django instance on my computer, which I'd like to do over HTTP, not HTTPS. But Electron's Chromium seems to intercept my fetch request and preemptively return a 307 redirect.
So if my fetch request is POST to http://local.myapp.com:3000/v1/graphql, then Chromium returns a 307 and forces a redirect to https://local.myapp.com:3000/v1/graphql, which fails because my server is listening on port 3000 and for my use case I can't do a local cert for local.myapp.com.
Theoretically the first insecure request should be hitting an nginx docker container listening on port 3000 without any SSL requirement. And nginx is proxying the request to a Hasura container. But I'm not even seeing the requests in the nginx access logs, so I'm pretty sure the request is being intercepted by Chromium.
I believe this StackOverflow comment summarizes well why this is happening: https://stackoverflow.com/a/34213531
Although I don't recall ever returning a Strict-Transport-Security header from my GraphQL endpoint or Django server.
I have tried the following code without success to turn off this Chromium behavior within my Electron app:
import { app, } from 'electron'
app.commandLine.appendSwitch('ignore-certificate-errors',)
app.commandLine.appendSwitch('allow-insecure-localhost', )
app.commandLine.appendSwitch('ignore-urlfetcher-cert-requests', )
app.commandLine.appendSwitch('allow-running-insecure-content', )
I have also tried setting the fetch options to include {redirect: 'manual'} and {redirect: 'error'}. I can prevent the redirect but that doesn't do me any good because I need to make a successful request to the endpoint to get my data.
I tried replacing the native fetch with electron-fetch (link) and cross-fetch (link) but there seems to be no change in behavior when I swap either of those out.
Edit: Also, making the request to my GraphQL outside of Electron with the exact same header and body info works fine (via Insomnia).
So I have a couple of questions:
Is there a way to programmatically view/clear the list of HSTS domains that is being used by Chromium within Electron?
Is there a better way to accomplish what I'm trying to do?
I think the issue might be from the server, most servers don't allow HTTP in any possible way, they'll drop the data transfer and redirect you to HTTPS and there's a clear reason why they would do that.
Imagine you have an app that connects through HTTPS to send your API in return for some data, if someone just changed the https:// to http:// that'd mean the data will be sent un-encrypted and no matter what you do with your API key, it'll be exposed, that's why the servers don't ever allow any HTTP request, they don't accept even a single bit of data.
I could think of two solutions.
Chromium is not the reason for the redirect, our Django instance might be configured as production or with HTTPS listeners.
Nginx might be the one who's doing the redirecting (having a little bit of SSL def on the configuration)
Last but not least, just generate a cert with OpenSSL (on host http://local.myapp.com:3000/) note: include the port and use that on your Django instance. You can trust the certificate so that it could work everywhere on your computer.
I want to enforce HTTPS for a Spring Boot application to be hosted at Pivotal CloudFoundry, and I think most of the applications would want this today. The common way of doing it, as I know, is using
http.requiresChannel().anyRequest().requiresSecure()
But this is causing a redirect loop. The cause, as I understand by refering to posts like this, is that the load balancer converts back https to http. That means, it has to be done at the load balancer level.
So, is there some option to tell CloudFoundry to enforce HTTPS for an application? If not, shouldn't this be a feature request? And, what could be a good way to have this today?
Update: Did any of you from Cloud Foundry or Spring Security team see this post? I think this is an essential feature before one can host an application on CloudFoundry. Googling, I found no easy solution but to tell the users to use https instead of http. But, even if I tell so, when an anonymous user tries to access a restricted page, Spring Security is redirecting him back, to the http login page.
Update 2: Of course, we have the x-forwarded-proto header as many answers suggest, but I don't know how hard it would be to customize the features of Spring Security to use that. Then, we have other things like Spring Social integrating with Spring Security, and I just faced an issue there as well. I think either Spring Security and tons of other other frameworks will need to come out with solutions to use x-forwarded-proto, or CloudFoundry needs to have some way to handle it transparently. I think the later would be far convenient.
Normally, when you push a WAR file to Cloud Foundry, the Java build pack will take that and deploy it to Tomcat. This works great because the Java build pack can configure Tomcat for you and automatically include a RemoteIpValve, which is what takes the x-forwarded-* headers and reconfigures your request object.
If you're using Spring Boot and pushing as a JAR file, you'll have an embed Tomcat in your application. Because Tomcat is embedded in your app, the Java build pack cannot configure it for the environment (i.e. it cannot configure the RemoteIpValve). This means you need to configure it. Instructions for doing that with Spring Boot can be found here.
If you're deploying an web application as a JAR file but using a different framework or embedded container, you'll need to look up the docs for your framework / container and see if it has automatic handling of the x-forwarded-* headers. If not, you'll need to manually handle that, like the other answers suggest.
You need to check the x-forwarded-proto header. Here is a method to do this.
public boolean isSecure (HttpServletRequest request) {
String protocol = request.getHeader("x-forwarded-proto");
if (protocol == null) {
return false;
}
else if (protocol.equals("https")) {
return true;
}
else {
return false;
}
}
Additionally, I have created an example servlet that does this as well.
https://hub.jazz.net/git/jsloyer/sslcheck
git clone https://hub.jazz.net/git/jsloyer/sslcheck
The app is running live at http://sslcheck.mybluemix.net and https://sslcheck.mybluemix.net.
Requests forwarded by the load balancer will have an http header called x-forwarded-proto set to https or http. You can use this to affect the behavior of your application with regard to SSL termination.
We currently have a set up with a load balancer carrying out SSL offloading, an http server and a websphere app server. Having got over the initial hurdle of the offloading preventing CAS from thinking it was running under https (which we got around by using the httpsIndicatorHeader variable), we now have another issue. Despite the fact we can see CAS redirecting to the target application, the 'handshake' seems to fail, showing a loop of tickets being generated and tried, but never actually validating, and the target application is never reached. There do not seem to be any errors being generated however.
Has anyone experienced anything similar before?
Cheers,
Rob
After investigation, the problem was that the application redirect url set up in websphere was pointing to the original url, rather than suffixing /j_spring_cas_security_check. This caused the circular loop to occur without any attempt to validate the ticket.
I'm setting up omniauth (just trying to get the facebook provider working for now).
I'm on my local computer running nginx on port 80. I route all requests to port 8080 and run the default webrick server on 8080.
I've set up omniauth pretty far, but now things only go smoothly in certain instances.
If my browser hits http://localhost/auth/facebook I get an error saying:
URI::InvalidURIError, the scheme http does not accept registry part: app_server (or bad hostname?)
If I hit however http://localhost:8080/auth/facebook, then facebook gives me an error message like Invalid redirect_uri: Given URL is not allowed by the Application configuration.". This makes sense since my site url is set to http://localhost not http://localhost:8080.
If I change the site url to http://localhost:8080, then things start to work (at least this far into the authorization process)
By the way, it's not just localhost by itself that is causing the problem. If I edit /etc/hosts and try something like dev.example.com it acts the same way, with dev.example.com not working and dev.example.com:8080 working.
Why can't I get it to work with just localhost? Is it something wrong with the way nginx and webrick talk to each other? I can't imagine that'd be the problem, but it's the only difference I see in what works and what doesn't. Any ideas why the URI error is occuring?
You need to edit the domain names for your facebook application. Go into https://developers.facebook.com/apps and edit the settings for that application. Set the site domain and app domains to whatever domain you want to allow redirection to (eg. example.dev)
One of my rails apps (using passenger and apache) is changing server hosts. I've got the app running on both servers (the new one in testing) and the DNS TTL to 5 minutes. I've been told (and experienced something like this myself) by a colleague that sometimes DNS resolvers slightly ignore the TTL and may have the old IP cached for some time after I update DNS to the new server.
So, after I've thrown the switch on DNS, what I'd like to do is hack the old server to issue a forced redirect to the IP address of the new server for all visitors. Obviously I can do a number of redirects (301, 302) in either Apache or the app itself. I'd like to avoid the app method since I don't want to do a checkin and deploy of code just for this one instance so I was thinking a basic http url redirect would work. Buuttt, there are SEO implications should google visit the old site etc. etc.
How best to achieve the re-direct whilst maintaining search engine niceness?
I guess the question is - where would you redirect to? If you are redirecting to the domain name, the browser (or bot) would just get the same old IP address and end up in a redirect loop.
If you redirect to an IP address.. well, that's not going to look very user friendly in someone's browser.
Personally, I wouldn't do anything. There may be some short period where bots get errors trying to access your site, but it should all work itself out in a couple days without any "SEO damage"
One solution might be to use Mod_Proxy instead of a rewrite to proxy traffic to the new host. This way you shouldn't see any "SEO damage".
I used rinetd to redirect the IP traffic from the old server to the new one on IP level. No web server or virtual hosts config needed. Runs very smoothly and absolutely transparent to any client.