* src/ejabberd_sm.erl: SASL Anonymous + Anonymous login support

(thanks to Mickael Remond and Magnus Henoch)
* src/ejabberd_c2s.erl: Likewise
* src/ejabberd_auth.erl: Likewise
* src/ejabberd_auth_anonymous.erl: Likewise
* src/cyrsasl.erl: Likewise
* src/cyrsasl_anonymous.erl: Likewise
* src/ejabberd.cfg.example: Likewise

SVN Revision: 527
This commit is contained in:
Alexey Shchepin 2006-04-07 00:39:24 +00:00
parent a5a978946d
commit 9a44fdffab
9 changed files with 154 additions and 52 deletions

View File

@ -1,3 +1,14 @@
2006-04-07 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_sm.erl: SASL Anonymous + Anonymous login support
(thanks to Mickael Remond and Magnus Henoch)
* src/ejabberd_c2s.erl: Likewise
* src/ejabberd_auth.erl: Likewise
* src/ejabberd_auth_anonymous.erl: Likewise
* src/cyrsasl.erl: Likewise
* src/cyrsasl_anonymous.erl: Likewise
* src/ejabberd.cfg.example: Likewise
2006-04-06 Alexey Shchepin <alexey@sevcom.net>
* src/expat_erl.c: Use binaries for CDATA

View File

@ -25,8 +25,7 @@
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
[{mech_new, 2},
{mech_step, 2}];
[{mech_new, 3}, {mech_step, 2}];
behaviour_info(Other) ->
undefined.
@ -36,6 +35,7 @@ start() ->
{keypos, #sasl_mechanism.mechanism}]),
cyrsasl_plain:start([]),
cyrsasl_digest:start([]),
cyrsasl_anonymous:start([]),
ok.
register_mechanism(Mechanism, Module, RequirePlainPassword) ->
@ -81,18 +81,19 @@ check_credentials(State, Props) ->
listmech(Host) ->
RequirePlainPassword = ejabberd_auth:plain_password_required(Host),
ets:select(sasl_mechanism,
[{#sasl_mechanism{mechanism = '$1',
require_plain_password = '$2',
_ = '_'},
if
RequirePlainPassword ->
[{'==', '$2', false}];
true ->
[]
end,
['$1']}]).
Mechs = ets:select(sasl_mechanism,
[{#sasl_mechanism{mechanism = '$1',
require_plain_password = '$2',
_ = '_'},
if
RequirePlainPassword ->
[{'==', '$2', false}];
true ->
[]
end,
['$1']}]),
filter_anonymous(Host, Mechs).
server_new(Service, ServerFQDN, UserRealm, SecFlags,
GetPassword, CheckPassword) ->
@ -105,8 +106,10 @@ server_new(Service, ServerFQDN, UserRealm, SecFlags,
server_start(State, Mech, ClientIn) ->
case ets:lookup(sasl_mechanism, Mech) of
[#sasl_mechanism{module = Module}] ->
{ok, MechState} = Module:mech_new(State#sasl_state.get_password,
State#sasl_state.check_password),
{ok, MechState} = Module:mech_new(
State#sasl_state.myname,
State#sasl_state.get_password,
State#sasl_state.check_password),
server_step(State#sasl_state{mech_mod = Module,
mech_state = MechState},
ClientIn);
@ -132,3 +135,10 @@ server_step(State, ClientIn) ->
{error, Error}
end.
%% Remove the anonymous mechanism from the list if not enabled for the given
%% host
filter_anonymous(Host, Mechs) ->
case ejabberd_auth_anonymous:is_sasl_anonymous_enabled(Host) of
true -> Mechs;
false -> Mechs -- "ANONYMOUS"
end.

View File

@ -12,7 +12,7 @@
-export([start/1,
stop/0,
mech_new/2,
mech_new/3,
mech_step/2]).
-behaviour(cyrsasl).
@ -25,7 +25,7 @@ start(_Opts) ->
stop() ->
ok.
mech_new(GetPassword, _CheckPassword) ->
mech_new(_Host, GetPassword, _CheckPassword) ->
{ok, #state{step = 1,
nonce = randoms:get_string(),
get_password = GetPassword}}.

View File

@ -10,7 +10,7 @@
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-export([start/1, stop/0, mech_new/2, mech_step/2, parse/1]).
-export([start/1, stop/0, mech_new/3, mech_step/2, parse/1]).
-behaviour(cyrsasl).
@ -23,7 +23,7 @@ start(_Opts) ->
stop() ->
ok.
mech_new(_GetPassword, CheckPassword) ->
mech_new(_Host, _GetPassword, CheckPassword) ->
{ok, #state{check_password = CheckPassword}}.
mech_step(State, ClientIn) ->

View File

@ -73,11 +73,11 @@
{access, local, [{allow, local}]}.
% Authentification method. If you want to use internal user base, then use
% Authentication method. If you want to use internal user base, then use
% this line:
{auth_method, internal}.
% For LDAP authentification use these lines instead of above one:
% For LDAP authentication use these lines instead of above one:
%{auth_method, ldap}.
%{ldap_servers, ["localhost"]}. % List of LDAP servers
%{ldap_uidattr, "uid"}. % LDAP attribute that holds user ID
@ -85,11 +85,11 @@
%{ldap_rootdn, "dc=example,dc=com"}. % LDAP manager
%{ldap_password, "******"}. % Password to LDAP manager
% For authentification via external script use the following:
% For authentication via external script use the following:
%{auth_method, external}.
%{extauth_program, "/path/to/authentification/script"}.
%{extauth_program, "/path/to/authentication/script"}.
% For authentification via ODBC use the following:
% For authentication via ODBC use the following:
%{auth_method, odbc}.
%{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
@ -98,6 +98,18 @@
{hosts, ["localhost"]}.
%% Anonymous login support:
%% anonymous_protocol: sasl_anon|login_anon|both
%% allow_multiple_connections: true|false
%% anon_digest_password: "anonymous" (this is the default password that should
%% be use for digest login).
%%{host_config, "public.example.org", [{auth_method, anonymous},
%% {allow_multiple_connections, false},
%% {anonymous_protocol, sasl_anon},
%% {anon_digest_password, "anonymous"}]}.
%% To use both anonymous and internal authentication:
%%{host_config, "public.example.org", [{auth_method, [anonymous, internal]}]}.
% Default language for server messages
{language, "en"}.

View File

@ -3,9 +3,13 @@
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : Authentification
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Updated : 23 Feb 2006 by Mickael Remond <mremond@process-one.net>
%%% for anonymous login support
%%% Id : $Id$
%%%----------------------------------------------------------------------
%% TODO: Use the functions in ejabberd auth to add and remove users.
-module(ejabberd_auth).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
@ -27,6 +31,8 @@
ctl_process_get_registered/3
]).
-export([auth_modules/1]).
-include("ejabberd.hrl").
-include("ejabberd_ctl.hrl").
@ -34,50 +40,102 @@
%%% API
%%%----------------------------------------------------------------------
start() ->
lists:foreach(fun(Host) ->
(auth_module(Host)):start(Host)
end, ?MYHOSTS).
lists:foreach(
fun(Host) ->
lists:foreach(
fun(M) ->
M:start(Host)
end, auth_modules(Host))
end, ?MYHOSTS).
plain_password_required(Server) ->
(auth_module(Server)):plain_password_required().
lists:any(
fun(M) ->
M:plain_password_required()
end, auth_modules(Server)).
check_password(User, Server, Password) ->
(auth_module(Server)):check_password(User, Server, Password).
lists:any(
fun(M) ->
M:check_password(User, Server, Password)
end, auth_modules(Server)).
check_password(User, Server, Password, StreamID, Digest) ->
(auth_module(Server)):check_password(User, Server, Password, StreamID, Digest).
lists:any(
fun(M) ->
M:check_password(User, Server, Password, StreamID, Digest)
end, auth_modules(Server)).
set_password(User, Server, Password) ->
(auth_module(Server)):set_password(User, Server, Password).
lists:foldl(
fun(M, {error, _}) ->
M:set_password(User, Server, Password);
(_M, Res) ->
Res
end, {error, not_allowed}, auth_modules(Server)).
try_register(User, Server, Password) ->
case lists:member(jlib:nameprep(Server), ?MYHOSTS) of
true ->
(auth_module(Server)):try_register(User, Server, Password);
lists:foldl(
fun(_M, {atomic, ok} = Res) ->
Res;
(M, _) ->
M:try_register(User, Server, Password)
end, {error, not_allowed}, auth_modules(Server));
false ->
{error, not_allowed}
end.
%% Registered users list do not include anonymous users logged
dirty_get_registered_users() ->
(auth_module(?MYNAME)):dirty_get_registered_users().
lists:flatmap(
fun(M) ->
M:dirty_get_registered_users()
end, auth_modules(?MYNAME)).
%% Registered users list do not include anonymous users logged
get_vh_registered_users(Server) ->
(auth_module(Server)):get_vh_registered_users(Server).
lists:flatmap(
fun(M) ->
M:get_vh_registered_users(Server)
end, auth_modules(Server)).
get_password(User, Server) ->
(auth_module(Server)):get_password(User, Server).
lists:foldl(
fun(M, false) ->
M:get_password(User, Server);
(_M, Password) ->
Password
end, false, auth_modules(Server)).
get_password_s(User, Server) ->
(auth_module(Server)):get_password_s(User, Server).
case get_password(User, Server) of
false ->
"";
Password ->
Password
end.
%% Returns true if the user exists in the DB or if an anonymous user is logged
%% under the given name
is_user_exists(User, Server) ->
(auth_module(Server)):is_user_exists(User, Server).
lists:any(
fun(M) ->
M:is_user_exists(User, Server)
end, auth_modules(Server)).
remove_user(User, Server) ->
(auth_module(Server)):remove_user(User, Server).
lists:foreach(
fun(M) ->
M:remove_user(User, Server)
end, auth_modules(Server)).
remove_user(User, Server, Password) ->
(auth_module(Server)):remove_user(User, Server, Password).
lists:foreach(
fun(M) ->
M:remove_user(User, Server, Password)
end, auth_modules(Server)).
ctl_process_get_registered(_Val, Host, ["registered-users"]) ->
@ -93,9 +151,11 @@ ctl_process_get_registered(Val, _Host, _Args) ->
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
auth_module(Server) ->
auth_modules(Server) ->
LServer = jlib:nameprep(Server),
Method = ejabberd_config:get_local_option({auth_method, LServer}),
list_to_atom("ejabberd_auth_" ++ atom_to_list(Method)).
Methods = if
is_list(Method) -> Method;
is_atom(Method) -> [Method]
end,
[list_to_atom("ejabberd_auth_" ++ atom_to_list(M)) || M <- Methods].

View File

@ -217,8 +217,8 @@ remove_user(User, Server, Password) ->
LServer = jlib:nameprep(Server),
F = fun() ->
Result = ejabberd_odbc:sql_query_t(
["select password from users where username='",
Username, "';"]),
["select password from users where username='",
Username, "';"]),
ejabberd_odbc:sql_query_t(["delete from users "
"where username='", Username,
"' and password='", Pass, "';"]),

View File

@ -1158,7 +1158,10 @@ terminate(_Reason, StateName, StateData) ->
pres_a = EmptySet,
pres_i = EmptySet,
pres_invis = false} ->
ejabberd_sm:close_session(StateData#state.sid);
ejabberd_sm:close_session(StateData#state.sid,
StateData#state.user,
StateData#state.server,
StateData#state.resource);
_ ->
From = StateData#state.jid,
Packet = {xmlelement, "presence",

View File

@ -15,7 +15,7 @@
%% API
-export([start_link/0,
route/3,
open_session/4, close_session/1,
open_session/4, close_session/4,
bounce_offline_message/3,
disconnect_removed_user/2,
get_user_resources/2,
@ -62,13 +62,19 @@ route(From, To, Packet) ->
end.
open_session(SID, User, Server, Resource) ->
set_session(SID, User, Server, Resource, undefined).
set_session(SID, User, Server, Resource, undefined),
JID = jlib:make_jid(User, Server, Resource),
ejabberd_hooks:run(sm_register_connection_hook, JID#jid.lserver,
[SID, JID]).
close_session(SID) ->
close_session(SID, User, Server, Resource) ->
F = fun() ->
mnesia:delete({session, SID})
end,
mnesia:sync_dirty(F).
mnesia:sync_dirty(F),
JID = jlib:make_jid(User, Server, Resource),
ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver,
[SID, JID]).
bounce_offline_message(From, To, Packet) ->
Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
@ -101,7 +107,7 @@ unset_presence(SID, User, Server, Resource, Status) ->
[User, Server, Resource, Status]).
close_session_unset_presence(SID, User, Server, Resource, Status) ->
close_session(SID),
close_session(SID, User, Server, Resource),
ejabberd_hooks:run(unset_presence_hook, jlib:nameprep(Server),
[User, Server, Resource, Status]).