You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by wi...@apache.org on 2020/01/14 11:45:38 UTC

[couchdb] 02/02: Add SameSite support to auth cookie

This is an automated email from the ASF dual-hosted git repository.

willholley pushed a commit to branch samesite_cookie
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 50cd470296732e2b75919eaeb68d3398b48c3e42
Author: Will Holley <wi...@gmail.com>
AuthorDate: Mon Jan 13 19:57:19 2020 +0000

    Add SameSite support to auth cookie
    
    Adds a new configuration field, `couch_httpd_auth.same_site` which
    sets the `SameSite` attribute of the CouchDB auth cookie. If no
    value is set (the default), no `SameSite` attribute is added.
    
    Refs #2221
---
 .vscode/settings.json                            |  3 ++
 rel/overlay/etc/default.ini                      | 18 +++++-----
 src/couch/src/couch_httpd_auth.erl               | 18 ++++++++--
 src/couch/test/exunit/same_site_cookie_tests.exs | 44 ++++++++++++++++++++++++
 4 files changed, 73 insertions(+), 10 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..aa0a1ad
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+    "python.pythonPath": ".venv/bin/python3"
+}
\ No newline at end of file
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 5fc8e07..85e4002 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -168,8 +168,8 @@ enable_xframe_options = false
 ; CouchDB can optionally enforce a maximum uri length;
 ; max_uri_length = 8000
 ; changes_timeout = 60000
-; config_whitelist = 
-; max_uri_length = 
+; config_whitelist =
+; max_uri_length =
 ; rewrite_limit = 100
 ; x_forwarded_host = X-Forwarded-Host
 ; x_forwarded_proto = X-Forwarded-Proto
@@ -178,7 +178,7 @@ enable_xframe_options = false
 max_http_request_size = 4294967296 ; 4GB
 
 ; [httpd_design_handlers]
-; _view = 
+; _view =
 
 ; [ioq]
 ; concurrency = 10
@@ -192,7 +192,7 @@ port = 6984
 
 ; [chttpd_auth_cache]
 ; max_lifetime = 600000
-; max_objects = 
+; max_objects =
 ; max_size = 104857600
 
 ; [mem3]
@@ -203,7 +203,7 @@ port = 6984
 
 ; [fabric]
 ; all_docs_concurrency = 10
-; changes_duration = 
+; changes_duration =
 ; shard_timeout_factor = 2
 ; uuid_prefix_len = 7
 ; request_timeout = 60000
@@ -242,9 +242,11 @@ iterations = 10 ; iterations for password hashing
 ; proxy_use_secret = false
 ; comma-separated list of public fields, 404 if empty
 ; public_fields =
-; secret = 
+; secret =
 ; users_db_public = false
 ; cookie_domain = example.com
+; Set the SameSite cookie property for the auth cookie. If empty, the SameSite property is not set.
+; same_site =
 
 ; CSP (Content Security Policy) Support for _utils
 [csp]
@@ -320,7 +322,7 @@ os_process_limit = 100
 couch_mrview = true
 
 [feature_flags]
-; This enables any database to be created as a partitioned databases (except system db's). 
+; This enables any database to be created as a partitioned databases (except system db's).
 ; Setting this to false will stop the creation of paritioned databases.
 ; paritioned||allowed* = true will scope the creation of partitioned databases
 ; to databases with 'allowed' prefix.
@@ -563,7 +565,7 @@ compaction = false
 ; The default number of results returned from a search on a partition
 ; of a database.
 ; limit_partitions = 2000
- 
+
 ; The maximum number of results that can be returned from a global
 ; search query (or any search query on a database without user-defined
 ; partitions). Attempts to set ?limit=N higher than this value will
diff --git a/src/couch/src/couch_httpd_auth.erl b/src/couch/src/couch_httpd_auth.erl
index 515ce61..9b7bda5 100644
--- a/src/couch/src/couch_httpd_auth.erl
+++ b/src/couch/src/couch_httpd_auth.erl
@@ -156,7 +156,7 @@ proxy_authentication_handler(Req) ->
 %% @deprecated
 proxy_authentification_handler(Req) ->
     proxy_authentication_handler(Req).
-    
+
 proxy_auth_user(Req) ->
     XHeaderUserName = config:get("couch_httpd_auth", "x_auth_username",
                                 "X-Auth-CouchDB-UserName"),
@@ -273,7 +273,7 @@ cookie_auth_cookie(Req, User, Secret, TimeStamp) ->
     Hash = crypto:hmac(sha, Secret, SessionData),
     mochiweb_cookies:cookie("AuthSession",
         couch_util:encodeBase64Url(SessionData ++ ":" ++ ?b2l(Hash)),
-        [{path, "/"}] ++ cookie_scheme(Req) ++ max_age() ++ cookie_domain()).
+        [{path, "/"}] ++ cookie_scheme(Req) ++ max_age() ++ cookie_domain() ++ same_site()).
 
 ensure_cookie_auth_secret() ->
     case config:get("couch_httpd_auth", "secret", undefined) of
@@ -457,6 +457,20 @@ cookie_domain() ->
         _ -> [{domain, Domain}]
     end.
 
+
+same_site() ->
+    SameSite = config:get("couch_httpd_auth", "same_site", ""),
+    case string:to_lower(SameSite) of
+        "" -> [];
+        "none" -> [{same_site, none}];
+        "lax" -> [{same_site, lax}];
+        "strict" -> [{same_site, strict}];
+        _ ->
+            couch_log:error("invalid config value couch_httpd_auth.same_site: ~p ",[SameSite]),
+            []
+    end.
+
+
 reject_if_totp(User) ->
     case get_totp_config(User) of
         undefined ->
diff --git a/src/couch/test/exunit/same_site_cookie_tests.exs b/src/couch/test/exunit/same_site_cookie_tests.exs
new file mode 100644
index 0000000..bad32ad
--- /dev/null
+++ b/src/couch/test/exunit/same_site_cookie_tests.exs
@@ -0,0 +1,44 @@
+defmodule SameSiteCookieTests do
+  use CouchTestCase
+
+  @moduletag :authentication
+
+  def get_cookie(user, pass) do
+    resp = Couch.post("/_session", body: %{:username => user, :password => pass})
+
+    true = resp.body["ok"]
+    resp.headers[:"set-cookie"]
+  end
+
+  @tag config: [{"admins", "jan", "apple"}, {"couch_httpd_auth", "same_site", "None"}]
+  test "Set same_site None" do
+    cookie = get_cookie("jan", "apple")
+    assert cookie =~ "; SameSite=None"
+  end
+
+  @tag config: [{"admins", "jan", "apple"}, {"couch_httpd_auth", "same_site", ""}]
+  test "same_site not set" do
+    cookie = get_cookie("jan", "apple")
+    assert cookie
+    refute cookie =~ "; SameSite="
+  end
+
+  @tag config: [{"admins", "jan", "apple"}, {"couch_httpd_auth", "same_site", "Strict"}]
+  test "Set same_site Strict" do
+    cookie = get_cookie("jan", "apple")
+    assert cookie =~ "; SameSite=Strict"
+  end
+
+  @tag config: [{"admins", "jan", "apple"}, {"couch_httpd_auth", "same_site", "Lax"}]
+  test "Set same_site Lax" do
+    cookie = get_cookie("jan", "apple")
+    assert cookie =~ "; SameSite=Lax"
+  end
+
+  @tag config: [{"admins", "jan", "apple"}, {"couch_httpd_auth", "same_site", "Invalid"}]
+  test "Set same_site invalid" do
+    cookie = get_cookie("jan", "apple")
+    assert cookie
+    refute cookie =~ "; SameSite="
+  end
+end