Skip to content
Snippets Groups Projects
Unverified Commit a4312230 authored by Aleksandr Lesnenko's avatar Aleksandr Lesnenko Committed by GitHub
Browse files

Revert "minimal support for multiple values for Access-Control-Allow-Origin (#42888)" (#43125)

This reverts commit bf6fd9ef.
parent 9194a1ba
No related branches found
No related tags found
No related merge requests found
......@@ -124,65 +124,11 @@
"Content-Security-Policy"
#(format "%s frame-ancestors %s;" % (if allow-iframes? "*" (or (embedding-app-origin) "'none'")))))
(defn parse-url
"Returns an object with protocol, domain and port for the given url"
[url]
(let [pattern #"^(?:(https?)://)?([^:/]+)(?::(\d+|\*))?$"
matches (re-matches pattern url)]
(if matches
(let [[_ protocol domain port] matches]
{:protocol protocol
:domain domain
:port port})
(throw (IllegalArgumentException. "Invalid URL")))))
(defn approved-domain?
"Checks if the domain is compatible with the reference one"
[domain reference-domain]
(if (str/starts-with? reference-domain "*.")
(str/ends-with? domain (str/replace-first reference-domain "*." "."))
(= domain reference-domain)))
(defn approved-protocol?
"Checks if the protocol is compatible with the reference one"
[protocol reference-protocol]
(or (nil? reference-protocol)
(= protocol reference-protocol)))
(defn approved-port?
"Checks if the port is compatible with the reference one"
[port reference-port]
(or
(= reference-port "*")
(= port reference-port)))
(defn approved-origin?
"Returns true if `origin` should be allowed for CORS based on the `approved-origins`"
[raw-origin approved-origins]
(boolean
(when (and (seq raw-origin) (seq approved-origins))
(let [approved-list (str/split approved-origins #" ")
origin (parse-url raw-origin)]
(boolean (some (fn [approved-origin-raw]
(or
(= approved-origin-raw "*")
(let [approved-origin (parse-url approved-origin-raw)]
(and
(approved-domain? (:domain origin) (:domain approved-origin))
(approved-protocol? (:protocol origin) (:protocol approved-origin))
(approved-port? (:port origin) (:port approved-origin))))))
approved-list))))))
(defn- access-control-headers
[origin]
(merge
(when
(approved-origin? origin (embedding-app-origin))
{"Access-Control-Allow-Origin" origin
"Vary" "Origin"})
{"Access-Control-Allow-Headers" "*"
"Access-Control-Expose-Headers" "X-Metabase-Anti-CSRF-Token"}))
[]
{"Access-Control-Allow-Origin" (embedding-app-origin)
"Access-Control-Allow-Headers" "*"
"Access-Control-Expose-Headers" "X-Metabase-Anti-CSRF-Token"})
(defn- first-embedding-app-origin
"Return only the first embedding app origin."
......@@ -193,7 +139,7 @@
(defn security-headers
"Fetch a map of security headers that should be added to a response based on the passed options."
[& {:keys [origin nonce allow-iframes? allow-cache?]
[& {:keys [nonce allow-iframes? allow-cache?]
:or {allow-iframes? false, allow-cache? false}}]
(merge
(if allow-cache?
......@@ -201,7 +147,7 @@
(cache-prevention-headers))
strict-transport-security-header
(content-security-policy-header-with-frame-ancestors allow-iframes? nonce)
(when (embedding-app-origin) (access-control-headers origin))
(when (embedding-app-origin) (access-control-headers))
(when-not allow-iframes?
;; Tell browsers not to render our site as an iframe (prevent clickjacking)
{"X-Frame-Options" (if (embedding-app-origin)
......@@ -217,7 +163,6 @@
(defn- add-security-headers* [request response]
;; merge is other way around so that handler can override headers
(update response :headers #(merge %2 %1) (security-headers
:origin ((:headers request) "origin")
:nonce (:nonce request)
:allow-iframes? ((some-fn req.util/public? req.util/embed?) request)
:allow-cache? (req.util/cacheable? request))))
......
......@@ -91,82 +91,3 @@
(is (str/includes? style-src (str "nonce-" nonce))))
(testing "The same nonce is in the body of the rendered page"
(is (str/includes? (:body response) nonce))))))))
(deftest test-parse-url
(testing "Should parse valid urls"
(is (= (mw.security/parse-url "http://example.com") {:protocol "http" :domain "example.com" :port nil}))
(is (= (mw.security/parse-url "https://example.com") {:protocol "https" :domain "example.com" :port nil}))
(is (= (mw.security/parse-url "http://example.com:8080") {:protocol "http" :domain "example.com" :port "8080"}))
(is (= (mw.security/parse-url "example.com:80") {:protocol nil :domain "example.com" :port "80"}))
(is (= (mw.security/parse-url "example.com:*") {:protocol nil :domain "example.com" :port "*"})))
(testing "Should throw for invalid urls"
(is (thrown-with-msg? IllegalArgumentException #"Invalid URL" (mw.security/parse-url "ftp://example.com")))
(is (thrown-with-msg? IllegalArgumentException #"Invalid URL" (mw.security/parse-url "://example.com")))
(is (thrown-with-msg? IllegalArgumentException #"Invalid URL" (mw.security/parse-url "example:com")))))
(deftest test-approved-domain?
(testing "Exact match"
(is (true? (mw.security/approved-domain? "example.com" "example.com")))
(is (false? (mw.security/approved-domain? "example.com" "example.org"))))
(testing "Should support wildcards for subdomains"
(is (true? (mw.security/approved-domain? "sub.example.com" "*.example.com")))
(is (false? (mw.security/approved-domain? "example.com" "*.example.com")))
(is (false? (mw.security/approved-domain? "sub.example.org" "*.example.com"))))
(testing "Should not allow subdomains if no wildcard is present"
(is (false? (mw.security/approved-domain? "sub.example.com" "example.com")))))
(deftest test-approved-protocol?
(testing "Exact protocol match"
(is (true? (mw.security/approved-protocol? "http" "http")))
(is (true? (mw.security/approved-protocol? "https" "https")))
(is (false? (mw.security/approved-protocol? "http" "https"))))
(testing "Nil reference should allow any protocol"
(is (true? (mw.security/approved-protocol? "http" nil)))
(is (true? (mw.security/approved-protocol? "https" nil)))))
(deftest test-approved-port?
(testing "Exact port match"
(is (true? (mw.security/approved-port? "80" "80")))
(is (false? (mw.security/approved-port? "80" "8080"))))
(testing "Wildcard port match"
(is (true? (mw.security/approved-port? "80" "*")))
(is (true? (mw.security/approved-port? "8080" "*")))))
(deftest test-approved-origin?
(testing "Should return false if parameters are nil"
(is (false? (mw.security/approved-origin? nil "example.com")))
(is (false? (mw.security/approved-origin? "example.com" nil))))
(testing "Approved origins with exact protocol and port match"
(let [approved "http://example1.com http://example2.com:3000 https://example3.com"]
(is (true? (mw.security/approved-origin? "http://example1.com" approved)))
(is (true? (mw.security/approved-origin? "http://example2.com:3000" approved)))
(is (true? (mw.security/approved-origin? "https://example3.com" approved)))))
(testing "Different protocol should fail"
(is (false? (mw.security/approved-origin? "https://example1.com" "http://example1.com"))))
(testing "Origins without protocol should accept both http and https"
(let [approved "example.com"]
(is (true? (mw.security/approved-origin? "http://example.com" approved)))
(is (true? (mw.security/approved-origin? "https://example.com" approved)))))
(testing "Different ports should fail"
(is (false? (mw.security/approved-origin? "http://example.com:3000" "http://example.com:3003"))))
(testing "Should allow anything with *"
(is (true? (mw.security/approved-origin? "http://example.com" "*")))
(is (true? (mw.security/approved-origin? "http://example.com" "http://somethingelse.com *"))))
(testing "Should allow subdomains when *.example.com"
(is (true? (mw.security/approved-origin? "http://subdomain.example.com" "*.example.com")))
(is (false? (mw.security/approved-origin? "http://subdomain.example.com" "*.somethingelse.com"))))
(testing "Should allow any port with example.com:*"
(is (true? (mw.security/approved-origin? "http://example.com" "example.com:*")))
(is (true? (mw.security/approved-origin? "http://example.com:8080" "example.com:*")))))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment