summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2020-03-30 12:42:21 +0100
committerRobert Newson <rnewson@apache.org>2020-03-30 21:04:23 +0100
commit6b6ddf0f257eba27596b42bc8978551b7a53e59a (patch)
tree25f4031c3ddb3fc9f9d3a47f9398adf5738784b4
parent1ab4ff362b08a09b2b95c08805c2f5027ffa7b59 (diff)
downloadcouchdb-jwt-controls-2.tar.gz
Verify all presented claimsjwt-controls-2
All claims in the header and payload are verified if present. The required_claims config setting is now separate and only causes CouchDB to reject JWT tokens without those claims.
-rw-r--r--rel/overlay/etc/default.ini2
-rw-r--r--src/jwtf/src/jwtf.erl24
-rw-r--r--src/jwtf/test/jwtf_tests.erl2
-rw-r--r--test/elixir/test/jwtauth_test.exs18
4 files changed, 31 insertions, 15 deletions
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 24f504726..6fe2260b4 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -142,7 +142,7 @@ max_db_number_for_dbs_info_req = 100
;[jwt_auth]
; List of claims to validate
-; required_claims = exp
+; required_claims =
;
; [jwt_keys]
; Configure at least one key here if using the JWT auth handler.
diff --git a/src/jwtf/src/jwtf.erl b/src/jwtf/src/jwtf.erl
index d7fb2e7d4..247f2b508 100644
--- a/src/jwtf/src/jwtf.erl
+++ b/src/jwtf/src/jwtf.erl
@@ -159,11 +159,11 @@ validate_typ(Props, Checks) ->
Required = prop(typ, Checks),
TYP = prop(<<"typ">>, Props),
case {Required, TYP} of
- {undefined, _} ->
+ {undefined, undefined} ->
ok;
{true, undefined} ->
throw({bad_request, <<"Missing typ header parameter">>});
- {true, <<"JWT">>} ->
+ {_, <<"JWT">>} ->
ok;
{true, _} ->
throw({bad_request, <<"Invalid typ header parameter">>})
@@ -174,11 +174,11 @@ validate_alg(Props, Checks) ->
Required = prop(alg, Checks),
Alg = prop(<<"alg">>, Props),
case {Required, Alg} of
- {undefined, _} ->
+ {undefined, undefined} ->
ok;
{true, undefined} ->
throw({bad_request, <<"Missing alg header parameter">>});
- {true, Alg} ->
+ {_, Alg} ->
case lists:member(Alg, valid_algorithms()) of
true ->
ok;
@@ -202,9 +202,9 @@ validate_iss(Props, Checks) ->
ActualISS = prop(<<"iss">>, Props),
case {ExpectedISS, ActualISS} of
- {undefined, _} ->
+ {undefined, undefined} ->
ok;
- {_ISS, undefined} ->
+ {ISS, undefined} when ISS /= undefined ->
throw({bad_request, <<"Missing iss claim">>});
{ISS, ISS} ->
ok;
@@ -218,11 +218,11 @@ validate_iat(Props, Checks) ->
IAT = prop(<<"iat">>, Props),
case {Required, IAT} of
- {undefined, _} ->
+ {undefined, undefined} ->
ok;
{true, undefined} ->
throw({bad_request, <<"Missing iat claim">>});
- {true, IAT} when is_integer(IAT) ->
+ {_, IAT} when is_integer(IAT) ->
ok;
{true, _} ->
throw({bad_request, <<"Invalid iat claim">>})
@@ -234,11 +234,11 @@ validate_nbf(Props, Checks) ->
NBF = prop(<<"nbf">>, Props),
case {Required, NBF} of
- {undefined, _} ->
+ {undefined, undefined} ->
ok;
{true, undefined} ->
throw({bad_request, <<"Missing nbf claim">>});
- {true, IAT} ->
+ {_, IAT} ->
assert_past(<<"nbf">>, IAT)
end.
@@ -248,11 +248,11 @@ validate_exp(Props, Checks) ->
EXP = prop(<<"exp">>, Props),
case {Required, EXP} of
- {undefined, _} ->
+ {undefined, undefined} ->
ok;
{true, undefined} ->
throw({bad_request, <<"Missing exp claim">>});
- {true, EXP} ->
+ {_, EXP} ->
assert_future(<<"exp">>, EXP)
end.
diff --git a/src/jwtf/test/jwtf_tests.erl b/src/jwtf/test/jwtf_tests.erl
index 9f232241e..ba944f7c7 100644
--- a/src/jwtf/test/jwtf_tests.erl
+++ b/src/jwtf/test/jwtf_tests.erl
@@ -275,7 +275,7 @@ header(Alg) ->
claims() ->
- EpochSeconds = 1496205841,
+ EpochSeconds = os:system_time(second),
{[
{<<"iat">>, EpochSeconds},
{<<"exp">>, EpochSeconds + 3600}
diff --git a/test/elixir/test/jwtauth_test.exs b/test/elixir/test/jwtauth_test.exs
index c50225cbd..2fb89c3af 100644
--- a/test/elixir/test/jwtauth_test.exs
+++ b/test/elixir/test/jwtauth_test.exs
@@ -103,7 +103,23 @@ defmodule JwtAuthTest do
end
def test_fun(alg, key) do
- {:ok, token} = :jwtf.encode({[{"alg", alg}, {"typ", "JWT"}]}, {[{"sub", "couch@apache.org"}, {"_couchdb.roles", ["testing"]}]}, key)
+ now = DateTime.to_unix(DateTime.utc_now())
+ {:ok, token} = :jwtf.encode(
+ {
+ [
+ {"alg", alg},
+ {"typ", "JWT"}
+ ]
+ },
+ {
+ [
+ {"nbf", now - 60},
+ {"exp", now + 60},
+ {"sub", "couch@apache.org"},
+ {"_couchdb.roles", ["testing"]
+ }
+ ]
+ }, key)
resp = Couch.get("/_session",
headers: [authorization: "Bearer #{token}"]