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 2014/06/02 13:09:05 UTC
chttpd commit: updated refs/heads/master to 018837c
Repository: couchdb-chttpd
Updated Branches:
refs/heads/master 002a90813 -> 018837c95
Add auth cache for clustered _users
Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/018837c9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/018837c9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/018837c9
Branch: refs/heads/master
Commit: 018837c957b20786cb1ecba80e1af33c31128890
Parents: 002a908
Author: Robert Newson <rn...@apache.org>
Authored: Mon Jun 2 11:58:54 2014 +0100
Committer: Robert Newson <rn...@apache.org>
Committed: Mon Jun 2 12:00:07 2014 +0100
----------------------------------------------------------------------
src/chttpd.app.src | 6 +-
src/chttpd.erl | 6 +-
src/chttpd_auth.erl | 26 ++++++++
src/chttpd_auth_cache.erl | 138 +++++++++++++++++++++++++++++++++++++++++
src/chttpd_sup.erl | 26 +++++++-
5 files changed, 197 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/018837c9/src/chttpd.app.src
----------------------------------------------------------------------
diff --git a/src/chttpd.app.src b/src/chttpd.app.src
index 3ce0c72..f24716d 100644
--- a/src/chttpd.app.src
+++ b/src/chttpd.app.src
@@ -16,6 +16,7 @@
{modules, [
chttpd,
chttpd_app,
+ chttpd_auth_cache,
chttpd_config_listener,
chttpd_db,
chttpd_external,
@@ -27,7 +28,9 @@
]},
{registered, [
chttpd_sup,
- chttpd
+ chttpd,
+ chttpd_auth_cache,
+ chttpd_auth_cache_lru
]},
{applications, [
kernel,
@@ -35,6 +38,7 @@
couch_log,
config,
couch,
+ ets_lru,
fabric
]},
{mod, {chttpd_app,[]}}
http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/018837c9/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 8618811..c556fa7 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -132,8 +132,8 @@ handle_request(MochiReq) ->
end,
AuthenticationFuns = [
- fun couch_httpd_auth:cookie_authentication_handler/1,
- fun couch_httpd_auth:default_authentication_handler/1
+ fun chttpd_auth:cookie_authentication_handler/1,
+ fun chttpd_auth:default_authentication_handler/1
],
% for the path, use the raw path with the query string and fragment
@@ -357,7 +357,7 @@ url_handler("_replicate") -> fun chttpd_misc:handle_replicate_req/1;
url_handler("_uuids") -> fun chttpd_misc:handle_uuids_req/1;
url_handler("_log") -> fun chttpd_misc:handle_log_req/1;
url_handler("_sleep") -> fun chttpd_misc:handle_sleep_req/1;
-url_handler("_session") -> fun couch_httpd_auth:handle_session_req/1;
+url_handler("_session") -> fun chttpd_auth:handle_session_req/1;
url_handler("_oauth") -> fun couch_httpd_oauth:handle_oauth_req/1;
url_handler("_up") -> fun chttpd_misc:handle_up_req/1;
url_handler("_membership") -> fun mem3_httpd:handle_membership_req/1;
http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/018837c9/src/chttpd_auth.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_auth.erl b/src/chttpd_auth.erl
new file mode 100644
index 0000000..1046538
--- /dev/null
+++ b/src/chttpd_auth.erl
@@ -0,0 +1,26 @@
+% 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.
+
+-module(chttpd_auth).
+
+-export([default_authentication_handler/1]).
+-export([cookie_authentication_handler/1]).
+-export([handle_session_req/1]).
+
+default_authentication_handler(Req) ->
+ couch_httpd_auth:default_authentication_handler(Req, chttpd_auth_cache).
+
+cookie_authentication_handler(Req) ->
+ couch_httpd_auth:cookie_authentication_handler(Req, chttpd_auth_cache).
+
+handle_session_req(Req) ->
+ couch_httpd_auth:handle_session_req(Req, chttpd_auth_cache).
http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/018837c9/src/chttpd_auth_cache.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_auth_cache.erl b/src/chttpd_auth_cache.erl
new file mode 100644
index 0000000..e0c403b
--- /dev/null
+++ b/src/chttpd_auth_cache.erl
@@ -0,0 +1,138 @@
+% 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.
+
+-module(chttpd_auth_cache).
+-behaviour(gen_server).
+
+-export([start_link/0, get_user_creds/1]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+-export([listen_for_changes/1, changes_callback/2]).
+
+-include_lib("couch/include/couch_db.hrl").
+
+-define(ADMIN_CTX, {user_ctx, #user_ctx{roles = [<<"_admin">>]}}).
+-define(CACHE, chttpd_auth_cache_lru).
+
+-record(state, {
+ changes_pid,
+ last_seq="0"
+}).
+
+%% public functions
+
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+get_user_creds(UserName) when is_list(UserName) ->
+ get_user_creds(?l2b(UserName));
+get_user_creds(UserName) when is_binary(UserName) ->
+ try ets_lru:lookup_d(?CACHE, UserName) of
+ {ok, Props} ->
+ couch_stats_collector:increment({chttpd, auth_cache_hits}),
+ couch_log:debug("cache hit for ~s", [UserName]),
+ Props;
+ _ ->
+ Props = load_user_from_db(UserName),
+ couch_stats_collector:increment({chttpd, auth_cache_misses}),
+ couch_log:debug("cache miss for ~s", [UserName]),
+ ets_lru:insert(?CACHE, UserName, Props),
+ Props
+ catch
+ error:badarg ->
+ couch_stats_collector:increment({chttpd, auth_cache_misses}),
+ couch_log:debug("cache miss for ~s", [UserName]),
+ load_user_from_db(UserName)
+ end.
+
+%% gen_server callbacks
+
+init([]) ->
+ {ok, #state{changes_pid = spawn_changes(0)}}.
+
+handle_call(_Call, _From, State) ->
+ {noreply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info({'DOWN', _, _, Pid, Reason}, #state{changes_pid=Pid} = State) ->
+ Seq = case Reason of
+ {seq, EndSeq} ->
+ EndSeq;
+ _ ->
+ couch_log:notice("~p changes listener died ~p", [?MODULE, Reason]),
+ 0
+ end,
+ erlang:send_after(5000, self(), {start_listener, Seq}),
+ {noreply, State#state{last_seq=Seq}};
+handle_info({start_listener, Seq}, State) ->
+ {noreply, State#state{changes_pid = spawn_changes(Seq)}};
+handle_info(_Msg, State) ->
+ {noreply, State}.
+
+terminate(_Reason, #state{changes_pid = Pid}) ->
+ exit(Pid, kill).
+
+code_change(_OldVsn, #state{}=State, _Extra) ->
+ {ok, State}.
+
+%% private functions
+
+spawn_changes(Since) ->
+ {Pid, _} = spawn_monitor(?MODULE, listen_for_changes, [Since]),
+ Pid.
+
+listen_for_changes(Since) ->
+ CBFun = fun ?MODULE:changes_callback/2,
+ Args = #changes_args{
+ feed = "continuous",
+ since = Since,
+ heartbeat = true,
+ filter = {default, main_only}
+ },
+ fabric:changes(dbname(), CBFun, Since, Args).
+
+changes_callback(start, Since) ->
+ {ok, Since};
+changes_callback({stop, EndSeq, _Pending}, _) ->
+ exit({seq, EndSeq});
+changes_callback({change, {Change}}, _) ->
+ UserName = username(couch_util:get_value(id, Change)),
+ couch_log:debug("Invalidating cached credentials for ~s", [UserName]),
+ ets_lru:remove(?CACHE, UserName),
+ {ok, couch_util:get_value(seq, Change)};
+changes_callback(timeout, EndSeq) ->
+ exit({seq, EndSeq});
+changes_callback({error, _}, EndSeq) ->
+ exit({seq, EndSeq}).
+
+load_user_from_db(UserName) ->
+ try fabric:open_doc(dbname(), docid(UserName), [?ADMIN_CTX, ejson_body]) of
+ {ok, Doc} ->
+ {Props} = couch_doc:to_json_obj(Doc, []),
+ Props;
+ _Else ->
+ couch_log:warning("no record of user ~s", [UserName]),
+ nil
+ catch error:database_does_not_exist ->
+ nil
+ end.
+
+dbname() ->
+ config:get("chttpd_auth", "authentication_db", "_users").
+
+docid(UserName) ->
+ <<"org.couchdb.user:", UserName/binary>>.
+
+username(<<"org.couchdb.user:", UserName/binary>>) ->
+ UserName.
http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/018837c9/src/chttpd_sup.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_sup.erl b/src/chttpd_sup.erl
index 69283a9..498491a 100644
--- a/src/chttpd_sup.erl
+++ b/src/chttpd_sup.erl
@@ -25,5 +25,29 @@ start_link(Args) ->
init([]) ->
{ok, {{one_for_one, 3, 10}, [
?CHILD(chttpd, worker),
- ?CHILD(chttpd_config_listener, worker)
+ ?CHILD(chttpd_config_listener, worker),
+ ?CHILD(chttpd_auth_cache, worker),
+ {chttpd_auth_cache_lru,
+ {ets_lru, start_link, [chttpd_auth_cache_lru, lru_opts()]},
+ permanent, 5000, worker, [ets_lru]}
]}}.
+
+lru_opts() ->
+ case config:get("chttpd_auth_cache", "max_objects") of
+ MxObjs when is_integer(MxObjs), MxObjs > 0 ->
+ [{max_objects, MxObjs}];
+ _ ->
+ []
+ end ++
+ case config:get("chttpd_auth_cache", "max_size", "104857600") of
+ MxSize when is_integer(MxSize), MxSize > 0 ->
+ [{max_size, MxSize}];
+ _ ->
+ []
+ end ++
+ case config:get("chttpd_auth_cache", "max_lifetime", "600000") of
+ MxLT when is_integer(MxLT), MxLT > 0 ->
+ [{max_lifetime, MxLT}];
+ _ ->
+ []
+ end.