You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2020/05/14 16:23:53 UTC

[couchdb] 01/01: allow configurability of JWT claims that require a value

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

rnewson pushed a commit to branch jwtf-iss-configurability
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 07854fa93785bc93980a8f7b4531471c1525739d
Author: Robert Newson <rn...@apache.org>
AuthorDate: Thu May 14 16:17:58 2020 +0100

    allow configurability of JWT claims that require a value
    
    e.g;
    
    [jwt]
    required_claims = {iss, <<"hello">>}
    
    required_claims is now a comma-separated list of claims in erlang language
    format.
---
 src/couch/src/couch_httpd_auth.erl | 11 +++---
 test/elixir/test/jwtauth_test.exs  | 77 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/src/couch/src/couch_httpd_auth.erl b/src/couch/src/couch_httpd_auth.erl
index 2383be7..5d207f2 100644
--- a/src/couch/src/couch_httpd_auth.erl
+++ b/src/couch/src/couch_httpd_auth.erl
@@ -209,11 +209,12 @@ jwt_authentication_handler(Req) ->
 
 get_configured_claims() ->
     Claims = config:get("jwt_auth", "required_claims", ""),
-    case re:split(Claims, "\s*,\s*", [{return, list}]) of
-        [[]] ->
-            []; %% if required_claims is the empty string.
-        List ->
-            [list_to_existing_atom(C) || C <- List]
+    case Claims of
+        "" ->
+            [];
+        Claims ->
+            {ok, Parsed} = couch_util:parse_term("[" ++ Claims ++ "]"),
+            Parsed
     end.
 
 cookie_authentication_handler(Req) ->
diff --git a/test/elixir/test/jwtauth_test.exs b/test/elixir/test/jwtauth_test.exs
index 2fb89c3..fd9be14 100644
--- a/test/elixir/test/jwtauth_test.exs
+++ b/test/elixir/test/jwtauth_test.exs
@@ -137,4 +137,81 @@ defmodule JwtAuthTest do
     assert resp.body["userCtx"]["name"] == "adm"
     assert resp.body["info"]["authenticated"] == "default"
   end
+
+  test "jwt auth with required iss claim", _context do
+
+    secret = "zxczxc12zxczxc12"
+
+    server_config = [
+      %{
+        :section => "jwt_auth",
+        :key => "required_claims",
+        :value => "{iss, <<\"hello\">>}"
+      },
+      %{
+        :section => "jwt_keys",
+        :key => "hmac:_default",
+        :value => :base64.encode(secret)
+      },
+      %{
+        :section => "jwt_auth",
+        :key => "allowed_algorithms",
+        :value => "HS256, HS384, HS512"
+      }
+    ]
+
+    run_on_modified_server(server_config, fn -> good_iss("HS256", secret) end)
+    run_on_modified_server(server_config, fn -> bad_iss("HS256", secret) end)
+  end
+
+  def good_iss(alg, key) do
+    {:ok, token} = :jwtf.encode(
+      {
+        [
+          {"alg", alg},
+          {"typ", "JWT"}
+        ]
+      },
+      {
+        [
+          {"iss", "hello"},
+          {"sub", "couch@apache.org"},
+          {"_couchdb.roles", ["testing"]
+          }
+        ]
+      }, key)
+
+    resp = Couch.get("/_session",
+      headers: [authorization: "Bearer #{token}"]
+    )
+
+    assert resp.body["userCtx"]["name"] == "couch@apache.org"
+    assert resp.body["userCtx"]["roles"] == ["testing"]
+    assert resp.body["info"]["authenticated"] == "jwt"
+  end
+
+  def bad_iss(alg, key) do
+    {:ok, token} = :jwtf.encode(
+      {
+        [
+          {"alg", alg},
+          {"typ", "JWT"}
+        ]
+      },
+      {
+        [
+          {"iss", "goodbye"},
+          {"sub", "couch@apache.org"},
+          {"_couchdb.roles", ["testing"]
+          }
+        ]
+      }, key)
+
+    resp = Couch.get("/_session",
+      headers: [authorization: "Bearer #{token}"]
+    )
+
+    assert resp.status_code == 400
+  end
+
 end