./ct_report/coverage/cyrsasl.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : cyrsasl.erl
3 %%% Author : Alexey Shchepin <alexey@process-one.net>
4 %%% Purpose : Cyrus SASL-like library
5 %%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%----------------------------------------------------------------------
25
26 -module(cyrsasl).
27 -author('alexey@process-one.net').
28
29 -export([listmech/1,
30 server_new/6,
31 server_start/4,
32 server_step/2,
33 default_modules/0]).
34
35 -ignore_xref([behaviour_info/1]).
36
37 -type sasl_module() :: module().
38 -type mechanism() :: binary().
39
40 -record(sasl_state, {service :: binary(),
41 myname :: jid:server(),
42 host_type :: binary(),
43 realm :: binary(),
44 mech_mod :: sasl_module(),
45 mech_state :: any(),
46 creds :: mongoose_credentials:t()
47 }).
48 -type sasl_state() :: #sasl_state{}.
49
50 % Either a simple error tag or an error tag + <text> field
51 -type error() :: {error, binary() | {binary(), binary()}}
52 | {error, binary() | {binary(), binary()}, jid:user()}.
53
54 -type sasl_result() :: {ok, mongoose_credentials:t()}
55 | {continue, binary(), sasl_state()}
56 | error().
57
58 -export_type([sasl_module/0, mechanism/0, error/0, sasl_result/0, sasl_state/0]).
59
60 -callback mechanism() -> mechanism().
61
62 -callback mech_new(Host :: jid:server(),
63 Creds :: mongoose_credentials:t()) -> {ok, tuple()}.
64
65 -callback mech_step(State :: tuple(),
66 ClientIn :: binary()) -> {ok, mongoose_credentials:t()}
67 | cyrsasl:error().
68
69 -optional_callbacks([mechanism/0, mech_new/2]).
70
71 -spec check_credentials(sasl_state(), mongoose_credentials:t()) -> R when
72 R :: {'ok', mongoose_credentials:t()}
73 | {'error', binary()}.
74 check_credentials(_State, Creds) ->
75 6612 case jid:nodeprep(mongoose_credentials:get(Creds, username, <<>>)) of
76 error ->
77
:-(
{error, <<"not-authorized">>};
78 <<>> ->
79
:-(
{error, <<"not-authorized">>};
80 _LUser ->
81 6612 {ok, Creds}
82 end.
83
84 -spec listmech(binary()) -> [mechanism()].
85 listmech(HostType) ->
86 13735 [M:mechanism() || M <- get_modules(HostType), is_module_supported(HostType, M)].
87
88 -spec server_new(Service :: binary(),
89 ServerFQDN :: jid:server(),
90 HostType :: binary(),
91 UserRealm :: binary(),
92 _SecFlags :: [any()],
93 Creds :: mongoose_credentials:t()) -> sasl_state().
94 server_new(Service, ServerFQDN, HostType, UserRealm, _SecFlags, Creds) ->
95 7070 #sasl_state{service = Service,
96 myname = ServerFQDN,
97 host_type = HostType,
98 realm = UserRealm,
99 creds = Creds}.
100
101 -spec server_start(State, Mech, ClientIn, SocketData) -> Result when
102 State :: sasl_state(),
103 Mech :: mechanism(),
104 ClientIn :: binary(),
105 SocketData :: map(),
106 Result :: sasl_result().
107 server_start(#sasl_state{myname = Host, host_type = HostType} = State,
108 Mech, ClientIn, SocketData) ->
109 6685 case [M || M <- get_modules(HostType), M:mechanism() =:= Mech,
110 6684 is_module_supported(HostType, M)] of
111 [Module] ->
112 6679 {ok, MechState} = Module:mech_new(Host, State#sasl_state.creds, SocketData),
113 6679 server_step(State#sasl_state{mech_mod = Module,
114 mech_state = MechState},
115 ClientIn);
116 [] ->
117 6 {error, <<"no-mechanism">>}
118 end.
119
120 is_module_supported(HostType, cyrsasl_oauth) ->
121 13544 gen_mod:is_loaded(HostType, mod_auth_token);
122 is_module_supported(HostType, Module) ->
123 169319 mongoose_fips:supports_sasl_module(Module) andalso ejabberd_auth:supports_sasl_module(HostType, Module).
124
125 -spec server_step(State :: sasl_state(), ClientIn :: binary()) -> Result when
126 Result :: sasl_result().
127 server_step(State, ClientIn) ->
128 6727 Module = State#sasl_state.mech_mod,
129 6727 MechState = State#sasl_state.mech_state,
130 6727 case Module:mech_step(MechState, ClientIn) of
131 {ok, Creds} ->
132 6612 check_credentials(State, Creds);
133 {continue, ServerOut, NewMechState} ->
134 51 {continue, ServerOut,
135 State#sasl_state{mech_state = NewMechState}};
136 {error, Error, Username} ->
137 21 {error, Error, Username};
138 {error, Error} ->
139 43 {error, Error}
140 end.
141
142 -spec get_modules(binary()) -> [sasl_module()].
143 get_modules(HostType) ->
144 20420 mongoose_config:get_opt([{auth, HostType}, sasl_mechanisms], default_modules()).
145
146 default_modules() ->
147 20628 [cyrsasl_scram_sha512_plus,
148 cyrsasl_scram_sha512,
149 cyrsasl_scram_sha384_plus,
150 cyrsasl_scram_sha384,
151 cyrsasl_scram_sha256_plus,
152 cyrsasl_scram_sha256,
153 cyrsasl_scram_sha224_plus,
154 cyrsasl_scram_sha224,
155 cyrsasl_scram_sha1_plus,
156 cyrsasl_scram_sha1,
157 cyrsasl_plain,
158 cyrsasl_anonymous,
159 cyrsasl_oauth].
Line Hits Source