Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: wrap-ssl-redirect on heroku?

I've just tried add this wrapper (-> routes (wrap-ssl-redirect)) for auto redirecting http to https, but when I deploy to heroku, the https:// doesn't get green in my browser, and the website doesn't load.

Isn't the default heroku port 443, which should also be the default from wrap-ssl-redirectfunction?

What is wrong?

Thank you!

EDIT:

My code:

(defn prod-app [routes]
  (-> routes
      (wrap-keyword-params)
      (wrap-params)
      (wrap-ssl-redirect)))

(defn -main []
  (let [port (Integer/parseInt (get (System/getenv) "PORT" "5000"))]
    (jetty/run-jetty (prod-app domain-specific-routes)
                     {:port port :join? false})))

EDIT 2:

I just found this thread which could solve my problem: Clojure / Noir: Force HTTPS, redirect if the request was http:// to https://

Came up with this require-https handler fn:

(defn https-url [request-url]
  (str "https://" 
       (:server-name request-url) 
       ":" 
       (:server-port request-url) 
       (:uri request-url)))

(defn require-https
  [handler]
  (fn [request]
    (if (and (= (:scheme request) :http) 
             (= (get-in request [:headers "host"]) "secure.mydomain.com"))
      (ring.util.response/redirect (https-url request))
      (handler request))))

But when I try to connect to http://secure.mydomain.com, I am seing a port in the browser address bar https://secure.mydomain.com:80/ and got this message ERR_SSL_PROTOCOL_ERROR.

like image 853
leontalbot Avatar asked Sep 28 '22 17:09

leontalbot


1 Answers

On Heroku, you need to bind to the port they give you through an environment variable. Heroku also sit load balancers in front of your app. They will terminate the SSL connection and communicate with your app over HTTP, so the scheme that your app will see will always be HTTP. The standard wrap-ssl-redirect won't work well with this scenario, I don't think it will ever successfully redirect (it would think the user is connecting over HTTP even if they did get redirected to HTTPS).

However Heroku adds x-forwarded-proto to the headers of every request to work around this, so you can see which protocol your client is using. In the same ring.middleware.ssl namespace is a wrap-forwarded-scheme middleware.

"Middleware that changes the :scheme of the request map to the value present in a request header. This is useful if your application sits behind a reverse proxy or load balancer that handles the SSL transport. The header defaults to x-forwarded-proto."

If you wrap your routes with this first, then with wrap-ssl-redirect, that it should redirect to HTTPS correctly. You can also add ring.middleware.ssl/wrap-hsts to enforce HSTS as well:

(wrap-forwarded-scheme (wrap-ssl-redirect (wrap-hsts app)))
like image 86
Daniel Compton Avatar answered Oct 31 '22 10:10

Daniel Compton