diff options
author | Robert Newson <rnewson@apache.org> | 2017-06-15 11:05:46 +0100 |
---|---|---|
committer | Robert Newson <rnewson@apache.org> | 2017-06-15 19:22:03 +0100 |
commit | f9c1f336974ae2d2b923065f92f35126ecb14313 (patch) | |
tree | 07c3fd592fa9682965a878f363c95b9d39a17a91 | |
parent | a3b6661d50337ad50e065a660006ab7afd0125ea (diff) | |
download | couchdb-f9c1f336974ae2d2b923065f92f35126ecb14313.tar.gz |
throw errors that chttpd:error_info can understand
-rw-r--r-- | src/jwks.erl | 8 | ||||
-rw-r--r-- | src/jwtf.erl | 76 |
2 files changed, 44 insertions, 40 deletions
diff --git a/src/jwks.erl b/src/jwks.erl index 87fc4abdd..4022e4184 100644 --- a/src/jwks.erl +++ b/src/jwks.erl @@ -61,8 +61,12 @@ get_keyset(Url) -> case ibrowse:send_req(Url, ReqHeaders, get) of {ok, "200", _RespHeaders, RespBody} -> {ok, parse_keyset(RespBody)}; - _Else -> - {error, get_keyset_failed} + {ok, Code, _RespHeaders, _RespBody} -> + couch_log:warning("get_keyset failed with code ~p", [Code]), + {error, {service_unavailable, <<"JWKS service unavailable">>}}; + {error, Reason} -> + couch_log:warning("get_keyset failed with reason ~p", [Reason]), + {error, {service_unavailable, <<"JWKS service unavailable">>}} end. diff --git a/src/jwtf.erl b/src/jwtf.erl index ed0ce92f6..bfecaccf4 100644 --- a/src/jwtf.erl +++ b/src/jwtf.erl @@ -44,7 +44,7 @@ encode(Header = {HeaderProps}, Claims, Key) -> try Alg = case prop(<<"alg">>, HeaderProps) of undefined -> - throw(missing_alg); + throw({bad_request, <<"Missing alg header parameter">>}); Val -> Val end, @@ -90,7 +90,7 @@ verification_algorithm(Alg) -> {Alg, Val} -> Val; false -> - throw(invalid_alg) + throw({bad_request, <<"Invalid alg header parameter">>}) end. @@ -118,11 +118,11 @@ validate_typ(Props, Checks) -> {undefined, _} -> ok; {true, undefined} -> - throw(missing_typ); + throw({bad_request, <<"Missing typ header parameter">>}); {true, <<"JWT">>} -> ok; {true, _} -> - throw(invalid_typ) + throw({bad_request, <<"Invalid typ header parameter">>}) end. @@ -133,13 +133,13 @@ validate_alg(Props, Checks) -> {undefined, _} -> ok; {true, undefined} -> - throw(missing_alg); + throw({bad_request, <<"Missing alg header parameter">>}); {true, Alg} -> case lists:member(Alg, ?VALID_ALGS) of true -> ok; false -> - throw(invalid_alg) + throw({bad_request, <<"Invalid alg header parameter">>}) end end. @@ -161,11 +161,11 @@ validate_iss(Props, Checks) -> {undefined, _} -> ok; {_ISS, undefined} -> - throw(missing_iss); + throw({bad_request, <<"Missing iss claim">>}); {ISS, ISS} -> ok; {_, _} -> - throw(invalid_iss) + throw({bad_request, <<"Invalid iss claim">>}) end. @@ -177,11 +177,11 @@ validate_iat(Props, Checks) -> {undefined, _} -> ok; {true, undefined} -> - throw(missing_iat); + throw({bad_request, <<"Missing iat claim">>}); {true, IAT} when is_integer(IAT) -> ok; {true, _} -> - throw(invalid_iat) + throw({bad_request, <<"Invalid iat claim">>}) end. @@ -193,7 +193,7 @@ validate_nbf(Props, Checks) -> {undefined, _} -> ok; {true, undefined} -> - throw(missing_nbf); + throw({bad_request, <<"Missing nbf claim">>}); {true, IAT} -> assert_past(<<"nbf">>, IAT) end. @@ -207,7 +207,7 @@ validate_exp(Props, Checks) -> {undefined, _} -> ok; {true, undefined} -> - throw(missing_exp); + throw({bad_request, <<"Missing exp claim">>}); {true, EXP} -> assert_future(<<"exp">>, EXP) end. @@ -219,7 +219,7 @@ key(Props, Checks, KS) -> KID = prop(<<"kid">>, Props), case {Required, KID} of {true, undefined} -> - throw(missing_kid); + throw({bad_request, <<"Missing kid claim">>}); {_, KID} -> KS(Alg, KID) end. @@ -242,7 +242,7 @@ public_key_verify(Algorithm, Message, Signature, PublicKey) -> true -> ok; false -> - throw(bad_signature) + throw({bad_request, <<"Bad signature">>}) end. @@ -251,21 +251,21 @@ hmac_verify(Algorithm, Message, HMAC, SecretKey) -> HMAC -> ok; _ -> - throw(bad_hmac) + throw({bad_request, <<"Bad HMAC">>}) end. split(EncodedToken) -> case binary:split(EncodedToken, <<$.>>, [global]) of [_, _, _] = Split -> Split; - _ -> throw(malformed_token) + _ -> throw({bad_request, <<"Malformed token">>}) end. decode_json(Encoded) -> case b64url:decode(Encoded) of {error, Reason} -> - throw(Reason); + throw({bad_request, Reason}); Decoded -> jiffy:decode(Decoded) end. @@ -274,7 +274,7 @@ props({Props}) -> Props; props(_) -> - throw(not_object). + throw({bad_request, <<"Not an object">>}). assert_past(Name, Time) -> @@ -282,7 +282,7 @@ assert_past(Name, Time) -> true -> ok; false -> - throw(<<Name/binary, " not in past">>) + throw({unauthorized, <<Name/binary, " not in past">>}) end. assert_future(Name, Time) -> @@ -290,7 +290,7 @@ assert_future(Name, Time) -> true -> ok; false -> - throw(<<Name/binary, " not in future">>) + throw({unauthorized, <<Name/binary, " not in future">>}) end. @@ -328,67 +328,67 @@ jwt_io_pubkey() -> missing_typ_test() -> Encoded = encode({[]}, []), - ?assertEqual({error, missing_typ}, decode(Encoded, [typ], nil)). + ?assertEqual({error, {bad_request,<<"Missing typ header parameter">>}}, decode(Encoded, [typ], nil)). invalid_typ_test() -> Encoded = encode({[{<<"typ">>, <<"NOPE">>}]}, []), - ?assertEqual({error, invalid_typ}, decode(Encoded, [typ], nil)). + ?assertEqual({error, {bad_request,<<"Invalid typ header parameter">>}}, decode(Encoded, [typ], nil)). missing_alg_test() -> Encoded = encode({[{<<"typ">>, <<"NOPE">>}]}, []), - ?assertEqual({error, missing_alg}, decode(Encoded, [alg], nil)). + ?assertEqual({error, {bad_request,<<"Missing alg header parameter">>}}, decode(Encoded, [alg], nil)). invalid_alg_test() -> Encoded = encode({[{<<"typ">>, <<"JWT">>}, {<<"alg">>, <<"NOPE">>}]}, []), - ?assertEqual({error, invalid_alg}, decode(Encoded, [alg], nil)). + ?assertEqual({error, {bad_request,<<"Invalid alg header parameter">>}}, decode(Encoded, [alg], nil)). missing_iss_test() -> Encoded = encode(valid_header(), {[]}), - ?assertEqual({error, missing_iss}, decode(Encoded, [{iss, right}], nil)). + ?assertEqual({error, {bad_request,<<"Missing iss claim">>}}, decode(Encoded, [{iss, right}], nil)). invalid_iss_test() -> Encoded = encode(valid_header(), {[{<<"iss">>, <<"wrong">>}]}), - ?assertEqual({error, invalid_iss}, decode(Encoded, [{iss, right}], nil)). + ?assertEqual({error, {bad_request,<<"Invalid iss claim">>}}, decode(Encoded, [{iss, right}], nil)). missing_iat_test() -> Encoded = encode(valid_header(), {[]}), - ?assertEqual({error, missing_iat}, decode(Encoded, [iat], nil)). + ?assertEqual({error, {bad_request,<<"Missing iat claim">>}}, decode(Encoded, [iat], nil)). invalid_iat_test() -> Encoded = encode(valid_header(), {[{<<"iat">>, <<"hello">>}]}), - ?assertEqual({error, invalid_iat}, decode(Encoded, [iat], nil)). + ?assertEqual({error, {bad_request,<<"Invalid iat claim">>}}, decode(Encoded, [iat], nil)). missing_nbf_test() -> Encoded = encode(valid_header(), {[]}), - ?assertEqual({error, missing_nbf}, decode(Encoded, [nbf], nil)). + ?assertEqual({error, {bad_request,<<"Missing nbf claim">>}}, decode(Encoded, [nbf], nil)). invalid_nbf_test() -> Encoded = encode(valid_header(), {[{<<"nbf">>, 32503680000}]}), - ?assertEqual({error, <<"nbf not in past">>}, decode(Encoded, [nbf], nil)). + ?assertEqual({error, {unauthorized, <<"nbf not in past">>}}, decode(Encoded, [nbf], nil)). missing_exp_test() -> Encoded = encode(valid_header(), {[]}), - ?assertEqual({error, missing_exp}, decode(Encoded, [exp], nil)). + ?assertEqual({error, {bad_request, <<"Missing exp claim">>}}, decode(Encoded, [exp], nil)). invalid_exp_test() -> Encoded = encode(valid_header(), {[{<<"exp">>, 0}]}), - ?assertEqual({error, <<"exp not in future">>}, decode(Encoded, [exp], nil)). + ?assertEqual({error, {unauthorized, <<"exp not in future">>}}, decode(Encoded, [exp], nil)). missing_kid_test() -> Encoded = encode({[]}, {[]}), - ?assertEqual({error, missing_kid}, decode(Encoded, [kid], nil)). + ?assertEqual({error, {bad_request, <<"Missing kid claim">>}}, decode(Encoded, [kid], nil)). public_key_not_found_test() -> @@ -405,7 +405,7 @@ bad_rs256_sig_test() -> {[{<<"typ">>, <<"JWT">>}, {<<"alg">>, <<"RS256">>}]}, {[]}), KS = fun(<<"RS256">>, undefined) -> jwt_io_pubkey() end, - ?assertEqual({error, bad_signature}, decode(Encoded, [], KS)). + ?assertEqual({error, {bad_request, <<"Bad signature">>}}, decode(Encoded, [], KS)). bad_hs256_sig_test() -> @@ -413,11 +413,11 @@ bad_hs256_sig_test() -> {[{<<"typ">>, <<"JWT">>}, {<<"alg">>, <<"HS256">>}]}, {[]}), KS = fun(<<"HS256">>, undefined) -> <<"bad">> end, - ?assertEqual({error, bad_hmac}, decode(Encoded, [], KS)). + ?assertEqual({error, {bad_request, <<"Bad HMAC">>}}, decode(Encoded, [], KS)). malformed_token_test() -> - ?assertEqual({error, malformed_token}, decode(<<"a.b.c.d">>, [], nil)). + ?assertEqual({error, {bad_request, <<"Malformed token">>}}, decode(<<"a.b.c.d">>, [], nil)). %% jwt.io generated @@ -475,12 +475,12 @@ rs256_test() -> encode_missing_alg_test() -> - ?assertEqual({error, missing_alg}, + ?assertEqual({error, {bad_request, <<"Missing alg header parameter">>}}, encode({[]}, {[]}, <<"foo">>)). encode_invalid_alg_test() -> - ?assertEqual({error, invalid_alg}, + ?assertEqual({error, {bad_request, <<"Invalid alg header parameter">>}}, encode({[{<<"alg">>, <<"BOGUS">>}]}, {[]}, <<"foo">>)). |