./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 -export_type([mechanism/0,
55 error/0]).
56
57 -callback mechanism() -> mechanism().
58
59 -callback mech_new(Host :: jid:server(),
60 Creds :: mongoose_credentials:t()) -> {ok, tuple()}.
61
62 -callback mech_step(State :: tuple(),
63 ClientIn :: binary()) -> {ok, mongoose_credentials:t()}
64 | cyrsasl:error().
65
66 -optional_callbacks([mechanism/0, mech_new/2]).
67
68 -spec check_credentials(sasl_state(), mongoose_credentials:t()) -> R when
69 R :: {'ok', mongoose_credentials:t()}
70 | {'error', binary()}.
71 check_credentials(_State, Creds) ->
72 2732 case jid:nodeprep(mongoose_credentials:get(Creds, username, <<>>)) of
73 error ->
74
:-(
{error, <<"not-authorized">>};
75 <<>> ->
76
:-(
{error, <<"not-authorized">>};
77 _LUser ->
78 2732 {ok, Creds}
79 end.
80
81 -spec listmech(binary()) -> [mechanism()].
82 listmech(HostType) ->
83 5938 [M:mechanism() || M <- get_modules(HostType), is_module_supported(HostType, M)].
84
85 -spec server_new(Service :: binary(),
86 ServerFQDN :: jid:server(),
87 HostType :: binary(),
88 UserRealm :: binary(),
89 _SecFlags :: [any()],
90 Creds :: mongoose_credentials:t()) -> sasl_state().
91 server_new(Service, ServerFQDN, HostType, UserRealm, _SecFlags, Creds) ->
92 3155 #sasl_state{service = Service,
93 myname = ServerFQDN,
94 host_type = HostType,
95 realm = UserRealm,
96 creds = Creds}.
97
98 -spec server_start(State, Mech, ClientIn, SocketData) -> Result when
99 State :: sasl_state(),
100 Mech :: mechanism(),
101 ClientIn :: binary(),
102 SocketData :: map(),
103 Result :: {ok, mongoose_credentials:t()}
104 | {'continue', _, sasl_state()}
105 | error().
106 server_start(#sasl_state{myname = Host, host_type = HostType} = State,
107 Mech, ClientIn, SocketData) ->
108 2783 case [M || M <- get_modules(HostType), M:mechanism() =:= Mech,
109 2783 is_module_supported(HostType, M)] of
110 [Module] ->
111 2783 {ok, MechState} = Module:mech_new(Host, State#sasl_state.creds, SocketData),
112 2783 server_step(State#sasl_state{mech_mod = Module,
113 mech_state = MechState},
114 ClientIn);
115 [] ->
116
:-(
{error, <<"no-mechanism">>}
117 end.
118
119 is_module_supported(HostType, cyrsasl_oauth) ->
120 5726 gen_mod:is_loaded(HostType, mod_auth_token);
121 is_module_supported(HostType, Module) ->
122 71707 mongoose_fips:supports_sasl_module(Module) andalso ejabberd_auth:supports_sasl_module(HostType, Module).
123
124 -spec server_step(State :: sasl_state(), ClientIn :: binary()) -> Result when
125 Result :: {ok, mongoose_credentials:t()}
126 | {'continue', _, sasl_state()}
127 | error().
128 server_step(State, ClientIn) ->
129 2783 Module = State#sasl_state.mech_mod,
130 2783 MechState = State#sasl_state.mech_state,
131 2783 case Module:mech_step(MechState, ClientIn) of
132 {ok, Creds} ->
133 2732 check_credentials(State, Creds);
134 {continue, ServerOut, NewMechState} ->
135
:-(
{continue, ServerOut,
136 State#sasl_state{mech_state = NewMechState}};
137 {error, Error, Username} ->
138 16 {error, Error, Username};
139 {error, Error} ->
140 35 {error, Error}
141 end.
142
143 -spec get_modules(binary()) -> [sasl_module()].
144 get_modules(HostType) ->
145 8721 mongoose_config:get_opt([{auth, HostType}, sasl_mechanisms], default_modules()).
146
147 default_modules() ->
148 8885 [cyrsasl_scram_sha512_plus,
149 cyrsasl_scram_sha512,
150 cyrsasl_scram_sha384_plus,
151 cyrsasl_scram_sha384,
152 cyrsasl_scram_sha256_plus,
153 cyrsasl_scram_sha256,
154 cyrsasl_scram_sha224_plus,
155 cyrsasl_scram_sha224,
156 cyrsasl_scram_sha1_plus,
157 cyrsasl_scram_sha1,
158 cyrsasl_plain,
159 cyrsasl_anonymous,
160 cyrsasl_oauth].
Line Hits Source