SSL on Rails & nginx: Filter chain halted

Hi,
I'm sending a simple Ajax HTTP POST with username/password to Rails. It
lands in SessionsController, which requires SSL on 'create' action using
ssl_requirement plug-in. However, Rails can't render and browser(Chrome)
says "Failed to load resource" while the following log is dumped at
production log:

Processing SessionsController#create [POST]
  Parameters: {"action"=>"create", "controller"=>"sessions",
"login"=>"my_user", "password"=>"[FILTERED]"}
Redirected to https://mysite.com/sessions
Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
Completed in 3ms (DB: 1) | 302 Found [http://mysite.com/sessions]

Is it trying to render's Sessions Controller's view?? I don't have a
view for it, SessionController:create should authenticate the user and
render back an ACK to the Javascript client.

Below is my HTTPS server block at nginx:
    server {
        listen 443;
        server_name www.mysite.com;
  proxy_set_header X_FORWARDED_PROTO https;
        ssl on;
        ssl_certificate /srv/ssl/mysite.com.combined.crt;
        ssl_certificate_key /srv/ssl/mysite.com.key;
        keepalive_timeout 70;
     }

I could not figure out if the problem is with NGINX - SSL setup or
Rails-SSL_requirement issue. Any ideas? I have Rails 2.3.8,
ssl_requirement plug-in and passenger 3.02 + nginx 0.8.53.

Thanks in advance.

Below is my HTTPS server block at nginx:
server {
listen 443;
server_name www.mysite.com;
proxy_set_header X_FORWARDED_PROTO https;

It looks like rails thinks your https post was an http one, and it's
probably because this proxy_set_header is getting ignored: the docs
for nginx say "proxy_set_header directives issued at higher levels are
only inherited when no proxy_set_header directives have been issued at
a given level". Try sticking this in the location block instead.

Fred

Hi Fred,
Tried it, though no change. I'm thinking the issue may be more
fundamental, hope it proves me wrong!

My xhr POST is actually being sent as an HTTP POST request, I send it
from Javascript client as XMLHTTPRequest. The first problem is: I should
not send login/password plain text before SSL channel is setup. The
question becomes how do I set up SSL before that? Am I getting too
confused here?

Secondly, I'm not using Rails' url/path helpers as Javascript client can
not understand those. My communication with Rails is over xhr's hence my
post with login/password. Therefore, I think Rails will fail with
redirects (in the SSL_requirement plugin) even if I send in HTTPs
protocol. Is that right? Hope that's not the case, what do you think?

Thanks,

Frederick Cheung wrote in post #971864:

Just to clarify is the page from which the ajax request also loaded
over https? When making an ajax request, the single origin policy
restricts you to the same host and protocol as that of the page you're
on: if the page is loaded over http then ajax requests can only be
made over http

Fred

I am on http when I send the Ajax request. About the same origin policy,
I thought Rails/Nginx would switch it over to HTTPS protocol as the
request is being sent to an action that requires SSL(ie.
SessionsController:create is set up with ssl_required).

If my above understanding is not correct, then should I be first
switching the page to HTTPs and then send the Ajax request? To test
that, I issued “location.href=location.href.replace(‘http:’,‘https:’);”
at browser’s console to switch, which does switch to https://mysite.com;
but the page is empty and has only “Welcome to nginx!”.

I added "root /my_public_dir; passenger_enabled on;" in nginx.conf and
reloaded https://mysite.com. The result was "403 Forbidden" this time!
Am I on the right track here? How do I get the Rails/nginx to show the
same page when I switch to https?

If you or anyone else can shed some light on my questions here and
previous post on this thread, it will be much appreciated. A good
tutorial on Ajax + SSL for Rails/Javascript is much needed, there is a
huge info gap on this on the web.

Many thanks.

I am on http when I send the Ajax request. About the same origin policy,
I thought Rails/Nginx would switch it over to HTTPS protocol as the
request is being sent to an action that requires SSL(ie.
SessionsController:create is set up with ssl_required).

The single origin policy is a client side thing, not a server side
thing: the browser simply won't let you make requests that wouldn't be
compliant.

Besides, posts across redirects are a messy business. Even if they
worked you would have already sent the data over the wire unencrypted,
so it would be pointless to then send it a second time encrypted.

If my above understanding is not correct, then should I be first
switching the page to HTTPs and then send the Ajax request? To test
that, I issued “location.href=location.href.replace(‘http:’,‘https:’);”
at browser’s console to switch, which does switch tohttps://mysite.com;
but the page is empty and has only “Welcome to nginx!”.

That sounds like you haven't got ssl setup properly yet. Independantly
of ajax etc. you need to get your app running on ssl. There should be
plenty of tutorials covering that.
You might also want to take a step back - what are you trying to
achieve (ie what do these requests do) ?

Fred

Hi Fred,
You're right, I fixed the SSL setup issue now.

Now.. While I am on https://mysite.com/, I send the XMLHttpRequest to
Rails SessionsController. I added a 'before_filter: require_ssl' to it,
so it should redirect to https.

  def require_ssl
    redirect_to :protocol => "https://"
  end

It gives me the same error as it did with SSL requirement before:
"Redirected to https://mysite.com/sessions Filter chain halted as
[:require_ssl] rendered_or_redirected."

Login works on https:// if I comment out the before filter. Why is it
failing on https when the require_ssl is on? I checked, it request.ssl?
is true, so the browser sends an SSL. It's got something to do with the
redirection. A better understanding of redirect_to can help here. Any
views?

Fred, regarding posts across redirects that you mention, what do you
suggest? One option is to switch the page to HTTPS before sending the
login/password; is there any other way? I need SSL for the login
initially, so will it work if I switch back to HTTP after login is done?

Regards

Have you looked at this page? http://stackoverflow.com/questions/1662262/rails-redirect-with-https

Walter

Have you looked at this page?
http://stackoverflow.com/questions/1662262/rails-redirect-with-https

Walter

Hi Walter,
Thanks. I had seen it; it made sense to revisit it at this point.
However, it still doesn't cure my problem. I put in the below code:
  def require_ssl
    if request.ssl?
      return true
    else
      redirect_to :protocol => "https://"
    end

And at http://mysite.com ; when I attempt a login, I get following:
Processing SessionsController#create [POST]
  Parameters: {"action"=>"create", "controller"=>"sessions",
"login"=>"my_user", "password"=>"[FILTERED]"}
Redirected to https://mysite.com/sessions
Filter chain halted as [:require_ssl] rendered_or_redirected.

It behaves similarly with the following path as well:
redirect_to :protocol => "https://", :controller => "home", :action =>
"index".

I am not clear how redirect_to works. Rails code says "It redirects the
browser to the target specified in +options+". My client is Javascript,
how does it ask the browser to redirect, so I can handle that? There
seems to be a lower level retry mechanism, which doesn't reach up to
Javascript??

Regarding my second question above, ie. messy redirects, I'm thinking it
should normally be pretty straight-forward to switch to HTTPS at the
browser and send the XHR while in HTTPS. But changing back to HTTP will
be a pain, all the magic of Ajax will be lost if I reload the entire
page.

This looks like an uphill battle... I'm sure this has been done before
using Rails + Javascript.

> Have you looked at this page?
>http://stackoverflow.com/questions/1662262/rails-redirect-with-https

> Walter

Hi Walter,
Thanks. I had seen it; it made sense to revisit it at this point.
However, it still doesn't cure my problem. I put in the below code:
def require_ssl
if request.ssl?
return true
else
redirect_to :protocol => "https://"
end

And athttp://mysite.com; when I attempt a login, I get following:
Processing SessionsController#create [POST]
Parameters: {"action"=>"create", "controller"=>"sessions",
"login"=>"my_user", "password"=>"[FILTERED]"}
Redirected tohttps://mysite.com/sessions
Filter chain halted as [:require_ssl] rendered_or_redirected.

Redirecting halts the filter chain - this is entirely normal

It behaves similarly with the following path as well:
redirect_to :protocol => "https://", :controller => "home", :action =>
"index".

I am not clear how redirect_to works. Rails code says "It redirects the
browser to the target specified in +options+". My client is Javascript,
how does it ask the browser to redirect, so I can handle that? There
seems to be a lower level retry mechanism, which doesn't reach up to
Javascript??

The browser handles the redirect - your javascript won't be aware of
it at all.

Fred

If you're trying to run an Ajax request in https, then the surrounding page must also be https or you will hit the same-origin trap. So you need to ensure first that this outer page is always requested through https, and also confirm that the inner Ajax request is also coming through https (although that will probably take care of itself if the outer page can only be requested through https).

Walter