pax_global_header00006660000000000000000000000064131024046240014506gustar00rootroot0000000000000052 comment=a13a48da6ee7b69f387e7e2837a40037b5de60da ring-ssl-0.3.0/000077500000000000000000000000001310240462400132445ustar00rootroot00000000000000ring-ssl-0.3.0/.gitignore000066400000000000000000000001311310240462400152270ustar00rootroot00000000000000/target /classes /checkouts /doc pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port ring-ssl-0.3.0/.travis.yml000066400000000000000000000000501310240462400153500ustar00rootroot00000000000000language: clojure script: lein test-all ring-ssl-0.3.0/LICENSE000066400000000000000000000020521310240462400142500ustar00rootroot00000000000000Copyright (c) 2013-2014 James Conroy-Finn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ring-ssl-0.3.0/README.md000066400000000000000000000016421310240462400145260ustar00rootroot00000000000000# Ring-SSL [![Build Status](https://secure.travis-ci.org/ring-clojure/ring-ssl.png)](http://travis-ci.org/ring-clojure/ring-ssl) Ring middleware for managing HTTPS requests. This library includes middleware to parse the `X-Forwarded-Proto` header, middleware that redirects HTTP requests to HTTPS URLs, and middleware that adds the [Strict-Transport-Security][1] header to responses. [1]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security ## Installation Add the following dependency to your `project.clj`: [ring/ring-ssl "0.3.0"] ## Documentation * [API Docs](http://ring-clojure.github.io/ring-ssl/ring.middleware.ssl.html) ## Thanks This project was originally conceived and developed by [James Conroy-Finn][2] at [Listora][3]. [2]: http://jamesconroyfinn.com/ [3]: http://www.listora.com/ ## License Copyright © 2017 James Conroy-Finn, James Reeves Released under the MIT license, same as Ring. ring-ssl-0.3.0/project.clj000066400000000000000000000014461310240462400154110ustar00rootroot00000000000000(defproject ring/ring-ssl "0.3.0" :description "Ring middleware for managing HTTPS requests" :url "https://github.com/ring-clojure/ring-ssl" :license {:name "The MIT License" :url "http://opensource.org/licenses/MIT"} :dependencies [[org.clojure/clojure "1.5.1"] [ring/ring-core "1.6.0"]] :plugins [[lein-codox "0.10.3"]] :codox {:project {:name "Ring-SSL"} :output-path "codox"} :aliases {"test-all" ["with-profile" "default:+1.6:+1.7:+1.8:+1.9" "test"]} :profiles {:dev {:dependencies [[ring/ring-mock "0.3.0"]]} :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} :1.9 {:dependencies [[org.clojure/clojure "1.9.0-alpha10"]]}}) ring-ssl-0.3.0/src/000077500000000000000000000000001310240462400140335ustar00rootroot00000000000000ring-ssl-0.3.0/src/ring/000077500000000000000000000000001310240462400147725ustar00rootroot00000000000000ring-ssl-0.3.0/src/ring/middleware/000077500000000000000000000000001310240462400171075ustar00rootroot00000000000000ring-ssl-0.3.0/src/ring/middleware/ssl.clj000066400000000000000000000073261310240462400204120ustar00rootroot00000000000000(ns ring.middleware.ssl "Middleware for managing handlers operating over HTTPS." (:require [ring.util.response :as resp] [ring.util.request :as req] [clojure.string :as str])) (def default-scheme-header "The default header used in wrap-forwarded-scheme (x-forwarded-proto)." "x-forwarded-proto") (defn forwarded-scheme-request "Change the :scheme of the request to the value present in a request header. See: wrap-forwarded-scheme." ([request] (forwarded-scheme-request request default-scheme-header)) ([request header] (let [header (str/lower-case header) default (name (:scheme request)) scheme (str/lower-case (get-in request [:headers header] default))] (if (#{"http" "https"} scheme) (assoc request :scheme (keyword scheme)) request)))) (defn wrap-forwarded-scheme "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." ([handler] (wrap-forwarded-scheme handler default-scheme-header)) ([handler header] (fn ([request] (handler (forwarded-scheme-request request header))) ([request respond raise] (handler (forwarded-scheme-request request header) respond raise))))) (defn- get-request? [{method :request-method}] (or (= method :head) (= method :get))) (defn- https-url [url-string port] (let [url (java.net.URL. url-string)] (str (java.net.URL. "https" (.getHost url) (or port -1) (.getFile url))))) (defn ssl-redirect-response "Given a HTTP request, return a redirect response to the equivalent HTTPS URL. See: wrap-ssl-redirect." [request options] (-> (resp/redirect (https-url (req/request-url request) (:ssl-port options))) (resp/status (if (get-request? request) 301 307)))) (defn wrap-ssl-redirect "Middleware that redirects any HTTP request to the equivalent HTTPS URL. Accepts the following options: :ssl-port - the SSL port to use for redirects, defaults to 443." ([handler] (wrap-ssl-redirect handler {})) ([handler options] (fn ([request] (if (= (:scheme request) :https) (handler request) (ssl-redirect-response request options))) ([request respond raise] (if (= (:scheme request) :https) (handler request respond raise) (respond (ssl-redirect-response request options))))))) (defn- build-hsts-header [{:keys [max-age include-subdomains?] :or {max-age 31536000, include-subdomains? true}}] (str "max-age=" max-age (if include-subdomains? "; includeSubDomains"))) (defn hsts-response "Add the Strict-Transport-Security header to the response. See: wrap-hsts." ([response] (hsts-response response {})) ([response options] (some-> response (resp/header "Strict-Transport-Security" (build-hsts-header options))))) (defn wrap-hsts "Middleware that adds the Strict-Transport-Security header to the response from the handler. This ensures the browser will only use HTTPS for future requests to the domain. Accepts the following options: :max-age - the max time in seconds the HSTS policy applies (defaults to 31536000 seconds, or 1 year) :include-subdomains? - true if subdomains should be included in the HSTS policy (defaults to true) See RFC 6797 for more information (https://tools.ietf.org/html/rfc6797)." ([handler] (wrap-hsts handler {})) ([handler options] (fn ([request] (hsts-response (handler request) options)) ([request respond raise] (handler request #(respond (hsts-response % options)) raise))))) ring-ssl-0.3.0/test/000077500000000000000000000000001310240462400142235ustar00rootroot00000000000000ring-ssl-0.3.0/test/ring/000077500000000000000000000000001310240462400151625ustar00rootroot00000000000000ring-ssl-0.3.0/test/ring/middleware/000077500000000000000000000000001310240462400172775ustar00rootroot00000000000000ring-ssl-0.3.0/test/ring/middleware/ssl_test.clj000066400000000000000000000141331310240462400216330ustar00rootroot00000000000000(ns ring.middleware.ssl-test (:use clojure.test ring.middleware.ssl [ring.mock.request :only (request header)] [ring.util.response :only (response get-header)])) (deftest test-wrap-forwarded-scheme (let [handler #(response (name (:scheme %)))] (let [handler (wrap-forwarded-scheme handler)] (testing "no header" (let [response (handler (request :get "/"))] (is (= (:body response) "http"))) (let [response (handler (request :get "https://localhost/"))] (is (= (:body response) "https")))) (testing "default header" (let [response (handler (-> (request :get "/") (header "x-forwarded-proto" "https")))] (is (= (:body response) "https"))) (let [response (handler (-> (request :get "https://localhost/") (header "x-forwarded-proto" "http")))] (is (= (:body response) "http"))))) (testing "custom header" (let [handler (wrap-forwarded-scheme handler "X-Foo") response (handler (-> (request :get "/") (header "x-foo" "https")))] (is (= (:body response) "https")))))) (deftest test-wrap-forwarded-scheme-cps (testing "default header" (let [handler (wrap-forwarded-scheme (fn [req respond _] (respond (-> req :scheme name response)))) req (-> (request :get "/") (header "x-forwarded-proto" "https")) resp (promise) ex (promise)] (handler req resp ex) (is (not (realized? ex))) (is (= (:body @resp) "https")))) (testing "custom header" (let [handler (wrap-forwarded-scheme (fn [req respond _] (respond (-> req :scheme name response))) "X-Foo") req (-> (request :get "/") (header "x-foo" "https")) resp (promise) ex (promise)] (handler req resp ex) (is (not (realized? ex))) (is (= (:body @resp) "https"))))) (deftest test-wrap-ssl-redirect (let [handler (wrap-ssl-redirect (constantly (response "")))] (testing "HTTP GET request" (let [response (handler (request :get "/"))] (is (= (:status response) 301)) (is (= (get-header response "location") "https://localhost/")))) (testing "HTTP POST request" (let [response (handler (request :post "/"))] (is (= (:status response) 307)) (is (= (get-header response "location") "https://localhost/")))) (testing "HTTPS request" (let [response (handler (request :get "https://localhost/"))] (is (= (:status response) 200)) (is (nil? (get-header response "location")))))) (let [handler (wrap-ssl-redirect (constantly (response "")) {:ssl-port 8443})] (testing "HTTP GET request with custom SSL port" (let [response (handler (request :get "/"))] (is (= (:status response) 301)) (is (= (get-header response "location") "https://localhost:8443/")))) (testing "HTTP POST request with custom SSL port" (let [response (handler (request :post "/"))] (is (= (:status response) 307)) (is (= (get-header response "location") "https://localhost:8443/"))))) (testing "HTTP POST request doesn't call handler" (let [effect (promise) handler (wrap-ssl-redirect (fn [req] (effect "performed") (response "")))] (handler (request :post "/")) (is (not (realized? effect)))))) (deftest test-wrap-ssl-redirect-cps (testing "HTTP GET request" (let [effect (promise) handler (wrap-ssl-redirect (fn [_ respond _] (effect "performed") (respond (response "")))) resp (promise) ex (promise)] (handler (request :get "/") resp ex) (is (not (realized? effect))) (is (not (realized? ex))) (is (= (:status @resp) 301)) (is (= (get-header @resp "location") "https://localhost/")))) (testing "HTTP GET request with custom SSL port" (let [handler (wrap-ssl-redirect (fn [_ respond _] (respond (response ""))) {:ssl-port 8443}) resp (promise) ex (promise)] (handler (request :get "/") resp ex) (is (not (realized? ex))) (is (= (:status @resp) 301)) (is (= (get-header @resp "location") "https://localhost:8443/"))))) (deftest test-wrap-hsts (testing "no matching handler" (let [handler (wrap-hsts (constantly nil)) response (handler (request :get "/not-found"))] (is (nil? response)))) (testing "defaults" (let [handler (wrap-hsts (constantly (response ""))) response (handler (request :get "/"))] (is (= (get-header response "strict-transport-security") "max-age=31536000; includeSubDomains")))) (testing "custom max-age" (let [handler (wrap-hsts (constantly (response "")) {:max-age 0}) response (handler (request :get "/"))] (is (= (get-header response "strict-transport-security") "max-age=0; includeSubDomains")))) (testing "don't include subdomains" (let [handler (wrap-hsts (constantly (response "")) {:include-subdomains? false}) response (handler (request :get "/"))] (is (= (get-header response "strict-transport-security") "max-age=31536000"))))) (deftest test-wrap-hsts-cps (testing "defaults" (let [handler (wrap-hsts (fn [_ respond _] (respond (response "")))) resp (promise) ex (promise)] (handler (request :get "/") resp ex) (is (not (realized? ex))) (is (= (get-header @resp "strict-transport-security") "max-age=31536000; includeSubDomains")))) (testing "custom max-age" (let [handler (wrap-hsts (fn [_ respond _] (respond (response ""))) {:max-age 0}) resp (promise) ex (promise)] (handler (request :get "/") resp ex) (is (not (realized? ex))) (is (= (get-header @resp "strict-transport-security") "max-age=0; includeSubDomains")))))