-
Notifications
You must be signed in to change notification settings - Fork 428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Riak base #378
Merged
Riak base #378
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
d1e82fe
add riak client as a dep
michalwski 7bbf351
use cuesport from esl's branch
michalwski af323b6
base riak pool
michalwski 1740f1c
add abstraction over riak_pb_socket API
michalwski 020ef6d
remove notification address from .travis.yml
michalwski 2f87741
do not auto import put/2
michalwski 9f1233a
compile riakc in prehook
michalwski b15f903
test riak on travis
michalwski 3db064f
test mysql on travis
michalwski c519c29
simplify setup_riak script
michalwski 6b1217f
add more helpers to mongoose_riak module
michalwski 1e77e66
add basic riak auth backend
michalwski c7a9258
add riak_config to ejabberd.cfg file
michalwski 1df679a
add more helpers to mongoose_riak
michalwski a387754
implement some not implemented functions for riak auth
michalwski 1e43b8c
restore ldap and external presets on travis
michalwski 7faba25
do not prepare username and server in auth_riak
michalwski f829b05
implement more functions defined by the gen_auth behaviour
michalwski 66f1888
restore other jobs on travis
michalwski 11e3f15
add possibility to specify more than on riak pool
michalwski 1cd0337
ignore riak_pools_count local config option during conf reload
michalwski f226072
keep pools count in riak_sup protected ets table
michalwski 5153fdd
rename config options and use one riak pool
5c9f2dc
[skip ci] describe how to setup riak and other databases
d0ad70a
try to override riak config
3d0f5ff
make riak pool reloadable
ed05733
[skip ci] typo in docs
4e1e861
set auto_reconnect and keepalive options
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
%%============================================================================== | ||
%% Copyright 2015 Erlang Solutions Ltd. | ||
%% | ||
%% 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(ejabberd_auth_riak). | ||
|
||
-behaviour(ejabberd_gen_auth). | ||
|
||
-include("ejabberd.hrl"). | ||
|
||
%% API | ||
-export([start/1, | ||
stop/1, | ||
store_type/1, | ||
login/2, | ||
set_password/3, | ||
check_password/3, | ||
check_password/5, | ||
try_register/3, | ||
dirty_get_registered_users/0, | ||
get_vh_registered_users/1, | ||
get_vh_registered_users/2, | ||
get_vh_registered_users_number/1, | ||
get_vh_registered_users_number/2, | ||
get_password/2, | ||
get_password_s/2, | ||
get_password/3, | ||
does_user_exist/2, | ||
remove_user/2, | ||
remove_user/3, | ||
plain_password_required/0]). | ||
|
||
-export([bucket_type/1]). | ||
|
||
-spec start(ejabberd:lserver()) -> ok. | ||
start(_Host) -> | ||
ok. | ||
|
||
-spec stop(ejabberd:lserver()) -> ok. | ||
stop(_Host) -> | ||
ok. | ||
|
||
-spec store_type(ejabberd:lserver()) -> plain | scram. | ||
store_type(Host) -> | ||
case scram:enabled(Host) of | ||
false -> plain; | ||
true -> scram | ||
end. | ||
|
||
-spec set_password(ejabberd:luser(),ejabberd:lserver(), binary()) | ||
-> ok | {error, not_allowed | invalid_jid}. | ||
set_password(LUser, LServer, Password) -> | ||
case prepare_password(LServer, Password) of | ||
false -> | ||
{error, invalid_password}; | ||
Password -> | ||
User = mongoose_riak:fetch_type(bucket_type(LServer), LUser), | ||
do_set_password(User, LUser, LServer, Password) | ||
end. | ||
|
||
-spec check_password(ejabberd:luser(), ejabberd:lserver(), binary()) -> boolean(). | ||
check_password(LUser, LServer, Password) -> | ||
case do_get_password(LUser, LServer) of | ||
false -> | ||
false; | ||
#scram{} = Scram -> | ||
scram:check_password(Password, Scram); | ||
Password when is_binary(Password) -> | ||
Password /= <<"">>; | ||
_ -> | ||
false | ||
end. | ||
|
||
-spec check_password(ejabberd:luser(), | ||
ejabberd:lserver(), | ||
binary(), | ||
binary(), | ||
fun()) -> boolean(). | ||
check_password(LUser, LServer, Password, Digest, DigestGen) -> | ||
case do_get_password(LUser, LServer) of | ||
false -> | ||
false; | ||
#scram{} = Scram -> | ||
scram:check_digest(Scram, Digest, DigestGen, Password); | ||
PassRiak when is_binary(PassRiak) -> | ||
ejabberd_auth:check_digest(Digest, DigestGen, Password, PassRiak) | ||
end. | ||
|
||
try_register(LUser, LServer, Password) -> | ||
try_register_if_does_not_exist(LUser, LServer, Password). | ||
|
||
-spec dirty_get_registered_users() -> [ejabberd:simple_jid()]. | ||
dirty_get_registered_users() -> | ||
Servers = ejabberd_config:get_vh_by_auth_method(riak), | ||
lists:flatmap( | ||
fun(Server) -> | ||
get_vh_registered_users(Server) | ||
end, Servers). | ||
|
||
-spec get_vh_registered_users(ejabberd:lserver()) -> | ||
[ejabberd:simple_jid()]. | ||
get_vh_registered_users(LServer) -> | ||
case mongoose_riak:list_keys(bucket_type(LServer)) of | ||
{ok, Users} -> | ||
[{User, LServer} || User <- Users]; | ||
_ -> | ||
[] | ||
end. | ||
|
||
-spec get_vh_registered_users(ejabberd:lserver(), list()) -> | ||
[ejabberd:simple_jid()]. | ||
get_vh_registered_users(LServer, _Opts) -> | ||
get_vh_registered_users(LServer). | ||
|
||
-spec get_vh_registered_users_number(ejabberd:lserver()) -> non_neg_integer(). | ||
get_vh_registered_users_number(LServer) -> | ||
length(get_vh_registered_users(LServer)). | ||
|
||
-spec get_vh_registered_users_number(ejabberd:lserver(), list()) -> non_neg_integer(). | ||
get_vh_registered_users_number(LServer, _Opts) -> | ||
get_vh_registered_users_number(LServer). | ||
|
||
-spec get_password(ejabberd:luser(), ejabberd:lserver()) -> binary() | false | scram(). | ||
get_password(LUser, LServer) -> | ||
case do_get_password(LUser, LServer) of | ||
false -> | ||
false; | ||
#scram{} = Scram -> | ||
scram:scram_to_tuple(Scram); | ||
Password -> | ||
Password | ||
end. | ||
|
||
get_password_s(LUser, LServer) -> | ||
case get_password(LUser, LServer) of | ||
Password when is_binary(Password) -> | ||
Password; | ||
_ -> | ||
<<"">> | ||
end. | ||
|
||
get_password(_LUser, _LServer, _DefaultValue) -> | ||
erlang:error(not_implemented). | ||
|
||
-spec does_user_exist(ejabberd:luser(), ejabberd:lserver()) -> boolean(). | ||
does_user_exist(LUser, LServer) -> | ||
case mongoose_riak:fetch_type(bucket_type(LServer), LUser) of | ||
{ok, _} -> | ||
true; | ||
{error, {notfound, map}} -> | ||
false | ||
end. | ||
|
||
-spec remove_user(ejabberd:luser(), ejabberd:lserver()) -> | ||
ok | {error, term()}. | ||
remove_user(LUser, LServer) -> | ||
mongoose_riak:delete(bucket_type(LServer), LUser). | ||
|
||
remove_user(_LUser, _LServer, _Password) -> | ||
erlang:error(not_implemented). | ||
|
||
plain_password_required() -> | ||
false. | ||
|
||
login(_LUser, _LServer) -> | ||
erlang:error(not_implemented). | ||
|
||
-spec bucket_type(ejabberd:lserver()) -> {binary(), ejabberd:lserver()}. | ||
bucket_type(LServer) -> | ||
{<<"users">>, LServer}. | ||
|
||
%% ----------------------------------------------------------------------------- | ||
%% Internal functions | ||
%% ----------------------------------------------------------------------------- | ||
|
||
try_register_if_does_not_exist(LUser, LServer, _) | ||
when LUser =:= error; LServer =:= error -> | ||
{error, invalid_jid}; | ||
try_register_if_does_not_exist(LUser, LServer, PasswordIn) -> | ||
case does_user_exist(LUser, LServer) of | ||
false -> | ||
Password = prepare_password(LServer, PasswordIn), | ||
try_register_with_password(LUser, LServer, Password); | ||
true -> | ||
{error, exists} | ||
end. | ||
|
||
try_register_with_password(LUser, LServer, Password) -> | ||
Now = integer_to_binary(now_to_seconds(os:timestamp())), | ||
Ops = [{{<<"created">>, register}, | ||
fun(R) -> riakc_register:set(Now, R) end}, | ||
set_password_map_op(Password)], | ||
UserMap = mongoose_riak:create_new_map(Ops), | ||
case mongoose_riak:update_type(bucket_type(LServer), LUser, | ||
riakc_map:to_op(UserMap)) of | ||
{ok, _Map} -> | ||
ok; | ||
Error -> | ||
Error | ||
end. | ||
|
||
do_get_password(LUser, LServer) -> | ||
case mongoose_riak:fetch_type(bucket_type(LServer), LUser) of | ||
{ok, Map} -> | ||
extract_password(Map); | ||
_ -> | ||
false | ||
end. | ||
|
||
do_set_password({ok, Map}, LUser, LServer, Password) -> | ||
Ops = [set_password_map_op(Password)], | ||
UpdateMap = mongoose_riak:update_map(Map, Ops), | ||
case mongoose_riak:update_type(bucket_type(LServer), LUser, | ||
riakc_map:to_op(UpdateMap)) of | ||
ok -> | ||
ok; | ||
Reason -> | ||
Reason | ||
end. | ||
|
||
prepare_password(Iterations, Password) when is_integer(Iterations) -> | ||
Scram = scram:password_to_scram(Password, Iterations), | ||
PassDetails = scram:serialize(Scram), | ||
{<<"">>, PassDetails}; | ||
|
||
prepare_password(Server, Password) -> | ||
case scram:enabled(Server) of | ||
true -> | ||
prepare_password(scram:iterations(Server), Password); | ||
_ -> | ||
Password | ||
end. | ||
|
||
set_password_map_op({_, Scram}) -> | ||
{{<<"scram">>, register}, fun(R) -> riakc_register:set(Scram, R) end}; | ||
set_password_map_op(Password) -> | ||
{{<<"password">>, register}, fun(R) -> riakc_register:set(Password, R) end}. | ||
|
||
extract_password(Map) -> | ||
case riakc_map:find({<<"password">>, register}, Map) of | ||
error -> | ||
maybe_extract_scram_password(riakc_map:find({<<"scram">>, register}, Map)); | ||
{ok, Password} -> | ||
Password | ||
end. | ||
|
||
maybe_extract_scram_password(false) -> | ||
false; | ||
maybe_extract_scram_password({ok, ScramSerialised}) -> | ||
case scram:deserialize(ScramSerialised) of | ||
{ok, Scram} -> | ||
Scram; | ||
_ -> | ||
false | ||
end. | ||
|
||
now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> | ||
MegaSecs * 1000000 + Secs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check_password/3 function has
_
clause. Do we need the same clause here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't, it's covered in
do_get_password/2
.