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? Rails redirect with https - Stack Overflow

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? >Rails redirect with https - Stack Overflow

> 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