diff options
author | Jay Doane <jay.s.doane@gmail.com> | 2017-08-07 14:49:57 -0700 |
---|---|---|
committer | Jay Doane <jay.s.doane@gmail.com> | 2017-08-07 14:49:57 -0700 |
commit | 3d6c294eec8363575ac82c256a9a6b82d31d1673 (patch) | |
tree | 2c3f3b46445ea0c31b403d82be221a5d08701edb | |
parent | bb1744ea78b36059f9291921a77490774b2fdd55 (diff) | |
download | couchdb-3d6c294eec8363575ac82c256a9a6b82d31d1673.tar.gz |
Move key cache to epep application
-rw-r--r-- | src/jwks.erl | 162 | ||||
-rw-r--r-- | src/jwtf.app.src | 3 | ||||
-rw-r--r-- | src/jwtf_app.erl | 26 | ||||
-rw-r--r-- | src/jwtf_sup.erl | 60 |
4 files changed, 0 insertions, 251 deletions
diff --git a/src/jwks.erl b/src/jwks.erl deleted file mode 100644 index 458a4cf3e..000000000 --- a/src/jwks.erl +++ /dev/null @@ -1,162 +0,0 @@ -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - -% @doc -% This module fetches and parses JSON Web Key Sets (JWKS). - --module(jwks). - --export([ - get_key/3, - get_keyset/1 -]). - --include_lib("public_key/include/public_key.hrl"). - -get_key(Url, Kty, Kid) -> - case lookup(Url, Kty, Kid) of - {ok, Key} -> - {ok, Key}; - {error, not_found} -> - case update_cache(Url) of - ok -> - lookup(Url, Kty, Kid); - {error, Reason} -> - {error, Reason} - end - end. - - -lookup(Url, Kty, Kid) -> - case ets_lru:lookup_d(jwks_cache_lru, {Url, Kty, Kid}) of - {ok, Key} -> - {ok, Key}; - not_found -> - {error, not_found} - end. - - -update_cache(Url) -> - case get_keyset(Url) of - {ok, KeySet} -> - [ets_lru:insert(jwks_cache_lru, {Url, Kty, Kid}, Key) - || {{Kty, Kid}, Key} <- KeySet], - ok; - {error, Reason} -> - {error, Reason} - end. - - -get_keyset(Url) -> - ReqHeaders = [], - case ibrowse:send_req(Url, ReqHeaders, get) of - {ok, "200", _RespHeaders, RespBody} -> - {ok, parse_keyset(RespBody)}; - {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. - - -parse_keyset(Body) -> - {Props} = jiffy:decode(Body), - Keys = proplists:get_value(<<"keys">>, Props), - lists:flatmap(fun parse_key/1, Keys). - - -parse_key({Props}) -> - Alg = proplists:get_value(<<"alg">>, Props), - Kty = proplists:get_value(<<"kty">>, Props), - Kid = proplists:get_value(<<"kid">>, Props), - case {Alg, Kty} of - {<<"RS256">>, <<"RSA">>} -> - E = proplists:get_value(<<"e">>, Props), - N = proplists:get_value(<<"n">>, Props), - [{{Kty, Kid}, #'RSAPublicKey'{ - modulus = decode_number(N), - publicExponent = decode_number(E)}}]; - {<<"ES256">>, <<"EC">>} -> - Crv = proplists:get_value(<<"crv">>, Props), - case Crv of - <<"P-256">> -> - X = proplists:get_value(<<"x">>, Props), - Y = proplists:get_value(<<"y">>, Props), - Point = <<4:8, - (b64url:decode(X))/binary, - (b64url:decode(Y))/binary>>, - [{{Kty, Kid}, { - #'ECPoint'{point = Point}, - {namedCurve,{1,2,840,10045,3,1,7}} - }}]; - _ -> - [] - end; - _ -> - [] - end. - - -decode_number(Base64) -> - crypto:bytes_to_integer(b64url:decode(Base64)). - - --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). - -jwks_test() -> - application:ensure_all_started(ibrowse), - application:ensure_all_started(ssl), - ?assertMatch({ok, _}, get_keyset("https://iam.eu-gb.bluemix.net/oidc/keys")). - -rs_test() -> - Ejson = {[ - {<<"kty">>, <<"RSA">>}, - {<<"n">>, <<"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx" - "4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs" - "tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2" - "QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI" - "SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb" - "w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw">>}, - {<<"e">>, <<"AQAB">>}, - {<<"alg">>, <<"RS256">>}, - {<<"kid">>, <<"2011-04-29">>} - ]}, - ?assertMatch([{{<<"RSA">>, <<"2011-04-29">>}, {'RSAPublicKey', _, 65537}}], - parse_key(Ejson)). - - -ec_test() -> - PrivateKey = #'ECPrivateKey'{ - version = 1, - parameters = {namedCurve,{1,2,840,10045,3,1,7}}, - privateKey = b64url:decode("870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"), - publicKey = <<4:8, - (b64url:decode("MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4"))/binary, - (b64url:decode("4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"))/binary>>}, - Ejson = {[ - {<<"kty">>, <<"EC">>}, - {<<"crv">>, <<"P-256">>}, - {<<"x">>, <<"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4">>}, - {<<"y">>, <<"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM">>}, - {<<"alg">>, <<"ES256">>}, - {<<"kid">>, <<"1">>} - ]}, - ?assertMatch([{_Key, _Value}], parse_key(Ejson)), - [{_, ECPublicKey}] = parse_key(Ejson), - Msg = <<"foo">>, - Sig = public_key:sign(Msg, sha256, PrivateKey), - ?assert(public_key:verify(Msg, sha256, Sig, ECPublicKey)). - --endif. diff --git a/src/jwtf.app.src b/src/jwtf.app.src index 2ff221309..304bb9e0a 100644 --- a/src/jwtf.app.src +++ b/src/jwtf.app.src @@ -14,14 +14,11 @@ {description, "JSON Web Token Functions"}, {vsn, git}, {registered, []}, - {mod, { jwtf_app, []}}, {applications, [ kernel, stdlib, b64url, crypto, - ets_lru, - ibrowse, jiffy, public_key ]}, diff --git a/src/jwtf_app.erl b/src/jwtf_app.erl deleted file mode 100644 index 92a26d558..000000000 --- a/src/jwtf_app.erl +++ /dev/null @@ -1,26 +0,0 @@ -%%%------------------------------------------------------------------- -%% @doc jwtf public API -%% @end -%%%------------------------------------------------------------------- - --module(jwtf_app). - --behaviour(application). - -%% Application callbacks --export([start/2, stop/1]). - -%%==================================================================== -%% API -%%==================================================================== - -start(_StartType, _StartArgs) -> - jwtf_sup:start_link(). - -%%-------------------------------------------------------------------- -stop(_State) -> - ok. - -%%==================================================================== -%% Internal functions -%%==================================================================== diff --git a/src/jwtf_sup.erl b/src/jwtf_sup.erl deleted file mode 100644 index 7cf56e84f..000000000 --- a/src/jwtf_sup.erl +++ /dev/null @@ -1,60 +0,0 @@ -%%%------------------------------------------------------------------- -%% @doc epep top level supervisor. -%% @end -%%%------------------------------------------------------------------- - --module(jwtf_sup). - --behaviour(supervisor). - -%% API --export([start_link/0]). - -%% Supervisor callbacks --export([init/1]). - --define(SERVER, ?MODULE). - -%%==================================================================== -%% API functions -%%==================================================================== - -start_link() -> - supervisor:start_link({local, ?SERVER}, ?MODULE, []). - -%%==================================================================== -%% Supervisor callbacks -%%==================================================================== - -%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules} -init([]) -> - Children = [ - {jwks_cache_lru, - {ets_lru, start_link, [jwks_cache_lru, lru_opts()]}, - permanent, 5000, worker, [ets_lru]} - ], - {ok, { {one_for_all, 5, 10}, Children} }. - -%%==================================================================== -%% Internal functions -%%==================================================================== - -lru_opts() -> - case config:get_integer("jwtf_cache", "max_objects", 50) of - MxObjs when MxObjs > 0 -> - [{max_objects, MxObjs}]; - _ -> - [] - end ++ - case config:get_integer("jwtf_cache", "max_size", 0) of - MxSize when MxSize > 0 -> - [{max_size, MxSize}]; - _ -> - [] - end ++ - case config:get_integer("jwtf_cache", "max_lifetime", 0) of - MxLT when MxLT > 0 -> - [{max_lifetime, MxLT}]; - _ -> - [] - end. |