comparison mail_oauth.t @ 1985:b5e2609d34a3

Tests: added tests for OAUTHBEARER and XOAUTH2 auth methods. Based on a patch by Rob Mueller.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 03 Jun 2024 18:15:28 +0300
parents
children
comparison
equal deleted inserted replaced
1984:81519d01f238 1985:b5e2609d34a3
1 #!/usr/bin/perl
2
3 # (C) Maxim Dounin
4
5 # Tests for mail module, XOAUTH2 and OAUTHBEARER authentication.
6
7 ###############################################################################
8
9 use warnings;
10 use strict;
11
12 use Test::More;
13
14 use MIME::Base64;
15 use Socket qw/ CRLF /;
16
17 BEGIN { use FindBin; chdir($FindBin::Bin); }
18
19 use lib 'lib';
20 use Test::Nginx;
21 use Test::Nginx::IMAP;
22 use Test::Nginx::POP3;
23 use Test::Nginx::SMTP;
24
25 ###############################################################################
26
27 select STDERR; $| = 1;
28 select STDOUT; $| = 1;
29
30 local $SIG{PIPE} = 'IGNORE';
31
32 my $t = Test::Nginx->new()->has(qw/mail imap pop3 smtp http map rewrite/)
33 ->write_file_expand('nginx.conf', <<'EOF');
34
35 %%TEST_GLOBALS%%
36
37 daemon off;
38
39 events {
40 }
41
42 mail {
43 proxy_pass_error_message on;
44 proxy_timeout 15s;
45 timeout 2s;
46 auth_http http://127.0.0.1:8080/mail/auth;
47
48 server {
49 listen 127.0.0.1:8143;
50 protocol imap;
51 imap_auth plain oauthbearer xoauth2;
52 }
53 server {
54 listen 127.0.0.1:8110;
55 protocol pop3;
56 pop3_auth plain oauthbearer xoauth2;
57 }
58 server {
59 listen 127.0.0.1:8025;
60 protocol smtp;
61 smtp_auth plain oauthbearer xoauth2;
62 }
63 }
64
65 http {
66 %%TEST_GLOBALS_HTTP%%
67
68 map $http_auth_protocol $proxy_port {
69 imap %%PORT_8144%%;
70 pop3 %%PORT_8111%%;
71 smtp %%PORT_8026%%;
72 }
73
74 map $http_auth_user:$http_auth_pass $reply {
75 test@example.com:secretok OK;
76 test=,@example.com:secretok OK;
77 default auth-failed;
78 }
79
80 map $http_auth_pass $passw {
81 secretok secret;
82 }
83
84 map $http_auth_pass $sasl {
85 saslfail "eyJzY2hlbWVzIjoiQmVhcmVyIiwic3RhdHVzIjoiNDAwIn0=";
86 }
87
88 server {
89 listen 127.0.0.1:8080;
90 server_name localhost;
91
92 location = /mail/auth {
93 add_header Auth-Status $reply;
94 add_header Auth-Server 127.0.0.1;
95 add_header Auth-Port $proxy_port;
96 add_header Auth-Pass $passw;
97 add_header Auth-Wait 1;
98 add_header Auth-Error-SASL $sasl;
99 return 204;
100 }
101 }
102 }
103
104 EOF
105
106 $t->run_daemon(\&Test::Nginx::IMAP::imap_test_daemon);
107 $t->run_daemon(\&Test::Nginx::POP3::pop3_test_daemon);
108 $t->run_daemon(\&Test::Nginx::SMTP::smtp_test_daemon);
109 $t->try_run('no oauth support')->plan(48);
110
111 $t->waitforsocket('127.0.0.1:' . port(8144));
112 $t->waitforsocket('127.0.0.1:' . port(8111));
113 $t->waitforsocket('127.0.0.1:' . port(8026));
114
115 ###############################################################################
116
117 # AUTHBEARER SASL mechanism
118 # https://datatracker.ietf.org/doc/html/rfc7628
119
120 # XOAUTH2 SASL mechanism
121 # https://developers.google.com/gmail/imap/xoauth2-protocol
122
123 my $s;
124 my $token = encode_base64(
125 "n,a=test\@example.com,\001auth=Bearer secretok\001\001", '');
126 my $token_escaped = encode_base64(
127 "n,a=test=3D=2C\@example.com,\001auth=Bearer secretok\001\001", '');
128 my $token_saslfail = encode_base64(
129 "n,a=test\@example.com,\001auth=Bearer saslfail\001\001", '');
130 my $token_bad = encode_base64(
131 "n,a=test\@example.com,\001auth=Bearer bad\001\001", '');
132
133 my $token_xoauth2 = encode_base64(
134 "user=test\@example.com\001auth=Bearer secretok\001\001", '');
135 my $token_xoauth2_saslfail = encode_base64(
136 "user=test\@example.com\001auth=Bearer saslfail\001\001", '');
137 my $token_xoauth2_bad = encode_base64(
138 "user=test\@example.com\001auth=Bearer bad\001\001", '');
139
140 # IMAP
141
142 $s = Test::Nginx::IMAP->new();
143 $s->read();
144 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token);
145 $s->ok('imap oauthbearer success');
146
147 $s = Test::Nginx::IMAP->new();
148 $s->read();
149 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token_escaped);
150 $s->ok('imap oauthbearer escaped login');
151
152 $s = Test::Nginx::IMAP->new();
153 $s->read();
154 $s->send('1 AUTHENTICATE OAUTHBEARER');
155 $s->check(qr/\+ /, 'imap oauthbearer challenge');
156 $s->send($token);
157 $s->ok('imap oauthbearer success after challenge');
158
159 $s = Test::Nginx::IMAP->new();
160 $s->read();
161 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token_bad);
162 $s->check(qr/^1 NO auth-failed/, 'imap oauthbearer non-sasl error');
163
164 sleep(3);
165
166 my @ready = $s->can_read(0);
167 is(scalar @ready, 1, "imap ready for reading");
168 ok($s->eof(), "imap session closed");
169
170 # fail, sasl failure method
171
172 $s = Test::Nginx::IMAP->new();
173 $s->read();
174 my $start = time;
175 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token_saslfail);
176 $s->check(qr/^\+ eyJz/, 'imap oauthbearer sasl failure');
177 my $wait_time = time - $start;
178 ok($wait_time >= 1, 'imap oauthbearer error delayed');
179 $s->send('AQ==');
180 $s->check(qr/^1 NO auth-failed/,
181 'imap oauthbearer auth failure after dummy response');
182
183 # fail, sasl failure method, invalid client response
184
185 $s = Test::Nginx::IMAP->new();
186 $s->read();
187 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token_saslfail);
188 $s->check(qr/^\+ eyJz/, 'imap oauthbearer sasl failure');
189 $s->send('foo');
190 $s->check(qr/^1 BAD /, 'imap oauthbearer invalid command after invalid line');
191
192 # fail, sasl failure method, multiple attempts, then success
193
194 $s = Test::Nginx::IMAP->new();
195 $s->read();
196
197 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token_saslfail);
198 $s->check(qr/^\+ eyJz/, 'imap oauthbearer sasl failure');
199 $s->send('AQ==');
200 $s->check(qr/^1 NO auth-failed/,
201 'imap oauthbearer auth failure after dummy response');
202
203 $s->send('1 AUTHENTICATE OAUTHBEARER ' . $token_saslfail);
204 $s->check(qr/^\+ eyJz/, 'imap oauthbearer sasl failure next');
205 $s->send('foo');
206 $s->check(qr/^1 BAD/, 'imap oauthbearer invalid command after invalid line');
207
208 $s->send('1 AUTHENTICATE OAUTHBEARER');
209 $s->check(qr/\+ /, 'imap oauthbearer challenge after fail');
210 $s->send($token);
211 $s->ok('imap oauthbearer success after fail');
212
213 # IMAP XOAUTH2
214
215 $s = Test::Nginx::IMAP->new();
216 $s->read();
217 $s->send('1 AUTHENTICATE XOAUTH2 ' . $token_xoauth2);
218 $s->ok('imap xoauth2 success');
219
220 $s = Test::Nginx::IMAP->new();
221 $s->read();
222 $s->send('1 AUTHENTICATE XOAUTH2');
223 $s->check(qr/^\+ /, 'imap xoauth2 challenge');
224 $s->send($token_xoauth2);
225 $s->ok('imap xoauth2 success after challenge');
226
227 $s = Test::Nginx::IMAP->new();
228 $s->read();
229 $s->send('1 AUTHENTICATE XOAUTH2 ' . $token_xoauth2_saslfail);
230 $s->check(qr/^\+ eyJz/, 'imap xoauth2 with bad token');
231 $s->send('');
232 $s->check(qr/^1 NO auth-failed/, 'imap xoauth2 auth failure after empty line');
233
234 $s->send('1 AUTHENTICATE XOAUTH2 ' . $token_xoauth2_saslfail);
235 $s->check(qr/^\+ eyJz/, 'imap xoauth2 with bad token next');
236 $s->send('foo');
237 $s->check(qr/^1 BAD/, 'imap xoauth2 invalid command after invalid line');
238
239 $s->send('1 AUTHENTICATE XOAUTH2 ' . $token_xoauth2);
240 $s->ok('imap xoauth2 success after fail');
241
242 # POP3
243
244 $s = Test::Nginx::POP3->new();
245 $s->read();
246 $s->send('AUTH OAUTHBEARER ' . $token);
247 $s->ok('pop3 oauthbearer success');
248
249 $s = Test::Nginx::POP3->new();
250 $s->read();
251 $s->send('AUTH OAUTHBEARER');
252 $s->check(qr/^\+ /, 'pop3 oauthbearer challenge');
253 $s->send($token);
254 $s->ok('pop3 oauthbearer success after challenge');
255
256 $s = Test::Nginx::POP3->new();
257 $s->read();
258 $s->send('AUTH OAUTHBEARER ' . $token_saslfail);
259 $s->check(qr/^\+ eyJz/, 'pop3 oauthbearer sasl failure');
260 $s->send('AQ==');
261 $s->check(qr/^-ERR /, 'pop3 oauthbearer auth failure after dummy response');
262
263 $s->send('AUTH OAUTHBEARER ' . $token_saslfail);
264 $s->check(qr/^\+ eyJz/, 'pop3 oauthbearer sasl failure next');
265 $s->send('');
266 $s->check(qr/^-ERR /, 'pop3 oauthbearer invalid command after invalid line');
267
268 $s->send('AUTH OAUTHBEARER ' . $token);
269 $s->ok('pop3 oauthbearer success after fail');
270
271 # POP3 XOAUTH2
272
273 $s = Test::Nginx::POP3->new();
274 $s->read();
275 $s->send('AUTH XOAUTH2 ' . $token_xoauth2);
276 $s->ok('pop3 xoauth2 success');
277
278 $s = Test::Nginx::POP3->new();
279 $s->read();
280 $s->send('AUTH XOAUTH2');
281 $s->check(qr/^\+ /, 'pop3 xoauth2 challenge');
282 $s->send($token_xoauth2);
283 $s->ok('pop3 xoauth2 success after challenge');
284
285 # SMTP
286
287 $s = Test::Nginx::SMTP->new();
288 $s->read();
289 $s->send('EHLO example.com');
290 $s->read();
291 $s->send('AUTH OAUTHBEARER ' . $token);
292 $s->authok('smtp oauthbearer success');
293
294 $s = Test::Nginx::SMTP->new();
295 $s->read();
296 $s->send('EHLO example.com');
297 $s->read();
298 $s->send('AUTH OAUTHBEARER');
299 $s->check(qr/^334 /, 'smtp oauthbearer challenge');
300 $s->send($token);
301 $s->authok('smtp oauthbearer success after challenge');
302
303 $s = Test::Nginx::SMTP->new();
304 $s->read();
305 $s->send('EHLO example.com');
306 $s->read();
307 $s->send('AUTH OAUTHBEARER ' . $token_saslfail);
308 $s->check(qr/^334 eyJz/, 'smtp oauthbearer sasl failure');
309 $s->send('AQ==');
310 $s->check(qr/^535 /, 'smtp oauthbearer auth failure after dummy response');
311
312 $s->send('AUTH OAUTHBEARER ' . $token_saslfail);
313 $s->check(qr/^334 eyJz/, 'smtp oauthbearer sasl failure next');
314 $s->send('foo');
315 $s->check(qr/^500 /, 'smtp oauthbearer invalid command after invalid line');
316
317 $s->send('AUTH OAUTHBEARER ' . $token);
318 $s->authok('smtp oauthbearer success after fail');
319
320 # SMTP XOAUTH2
321
322 $s = Test::Nginx::SMTP->new();
323 $s->read();
324 $s->send('EHLO example.com');
325 $s->read();
326 $s->send('AUTH XOAUTH2 ' . $token_xoauth2);
327 $s->authok('smtp xoauth2 success');
328
329 $s = Test::Nginx::SMTP->new();
330 $s->read();
331 $s->send('EHLO example.com');
332 $s->read();
333 $s->send('AUTH XOAUTH2');
334 $s->check(qr/^334 /, 'smtp xoauth2 challenge');
335 $s->send($token_xoauth2);
336 $s->authok('smtp xoauth2 success after challenge');
337
338 ###############################################################################