blob: a2b20398917796462f3a67de70a3f0416fbe6a1c [file] [log] [blame]
Akron33f5c672019-06-24 19:40:47 +02001use Mojo::Base -strict;
2use Test::More;
Akron6a228db2021-10-14 15:57:00 +02003use Mojo::ByteStream 'b';
Akroncdfd9d52019-07-23 11:35:00 +02004use Test::Mojo::WithRoles 'Session';
Akron66ef3b52022-11-22 14:25:15 +01005use Mojo::File qw/path tempfile/;
Akron33f5c672019-06-24 19:40:47 +02006use Data::Dumper;
7
8
9#####################
10# Start Fake server #
11#####################
Akron63d963b2019-07-05 15:35:51 +020012my $mount_point = '/realapi/';
Akron33f5c672019-06-24 19:40:47 +020013$ENV{KALAMAR_API} = $mount_point;
14
Akroncdfd9d52019-07-23 11:35:00 +020015my $t = Test::Mojo::WithRoles->new('Kalamar' => {
Akron33f5c672019-06-24 19:40:47 +020016 Kalamar => {
17 plugins => ['Auth']
18 },
19 'Kalamar-Auth' => {
20 client_id => 2,
21 client_secret => 'k414m4r-s3cr3t',
Akron59992122019-10-29 11:28:45 +010022 oauth2 => 1,
23 experimental_client_registration => 1
Akron33f5c672019-06-24 19:40:47 +020024 }
25});
26
27# Mount fake backend
28# Get the fixture path
29my $fixtures_path = path(Mojo::File->new(__FILE__)->dirname, '..', 'server');
30my $fake_backend = $t->app->plugin(
31 Mount => {
32 $mount_point =>
33 $fixtures_path->child('mock.pl')
34 }
35);
36# Configure fake backend
Akroncdfd9d52019-07-23 11:35:00 +020037my $fake_backend_app = $fake_backend->pattern->defaults->{app};
38
39# Set general app logger for simplicity
40$fake_backend_app->log($t->app->log);
41
42my $access_token = $fake_backend_app->get_token('access_token');
43my $refresh_token = $fake_backend_app->get_token('refresh_token');
44my $access_token_2 = $fake_backend_app->get_token('access_token_2');
45my $refresh_token_2 = $fake_backend_app->get_token('refresh_token_2');
46
47# Some routes to modify the session
48# This expires the session
49$t->app->routes->get('/x/expire')->to(
50 cb => sub {
51 my $c = shift;
52 $c->session(auth_exp => 0);
53 return $c->render(text => 'okay')
54 }
55);
56
57# This expires the session and removes the refresh token
58$t->app->routes->get('/x/expire-no-refresh')->to(
59 cb => sub {
60 my $c = shift;
61 $c->session(auth_exp => 0);
62 delete $c->session->{auth_r};
63 return $c->render(text => 'okay')
64 }
65);
66
67# This sets an invalid token
68$t->app->routes->get('/x/invalid')->to(
69 cb => sub {
70 my $c = shift;
71 $c->session(auth_exp => time + 1000);
72 $c->session(auth_r => $refresh_token_2);
73 $c->session(auth => 'Bearer inv4lid');
74 return $c->render(text => 'okay')
75 }
76);
77
78
79# This sets an invalid token
80$t->app->routes->get('/x/invalid-no-refresh')->to(
81 cb => sub {
82 my $c = shift;
83 $c->session(auth_exp => time + 1000);
84 delete $c->session->{auth_r};
85 $c->session(auth => 'Bearer inv4lid');
86 return $c->render(text => 'okay')
87 }
88);
89
90# This sets an invalid refresh token
91$t->app->routes->get('/x/expired-with-wrong-refresh')->to(
92 cb => sub {
93 my $c = shift;
94 $c->session(auth_exp => 0);
95 $c->session(auth => 'Bearer inv4lid');
96 $c->session(auth_r => 'inv4lid');
97 return $c->render(text => 'okay')
98 }
99);
100
Akronbc6b3f22021-01-13 14:53:12 +0100101my $q = qr!(?:\"|")!;
Akron33f5c672019-06-24 19:40:47 +0200102
Akron63d963b2019-07-05 15:35:51 +0200103$t->get_ok('/realapi/v1.0')
Akron33f5c672019-06-24 19:40:47 +0200104 ->status_is(200)
105 ->content_is('Fake server available');
106
107$t->get_ok('/?q=Baum')
108 ->status_is(200)
109 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
110 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100111 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200112 ->element_exists_not('div.button.top a')
113 ->element_exists_not('aside.active')
114 ->element_exists_not('aside.off')
115 ;
116
117$t->get_ok('/')
118 ->status_is(200)
Akron9fa7cc52022-05-12 11:17:20 +0200119 ->element_exists('form[action=/user/login] input[name=handle_or_email]')
Akron33f5c672019-06-24 19:40:47 +0200120 ->element_exists('aside.active')
121 ->element_exists_not('aside.off')
122 ;
123
Akronff088112021-06-15 15:26:04 +0200124$t->get_ok('/settings/oauth')
125 ->status_is(401)
126 ->text_is('p.no-results', 'Not authenticated')
127 ;
128
Akron3e0fdc12020-05-15 16:17:21 +0200129# Test for bug with long password
130$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200131 handle_or_email => 'test',
Akron3e0fdc12020-05-15 16:17:21 +0200132 pwd => 'kjskjhndkjndqknaskjnakjdnkjdankajdnkjdsankjdsakjdfkjahzroiuqzriudjoijdmlamdlkmdsalkmdl' })
133 ->status_is(302)
134 ->header_is('Location' => '/');
135
Akron9fa7cc52022-05-12 11:17:20 +0200136$t->post_ok('/user/login' => form => { handle_or_email => 'test', pwd => 'fail' })
Akron33f5c672019-06-24 19:40:47 +0200137 ->status_is(302)
138 ->header_is('Location' => '/');
139
140$t->get_ok('/')
141 ->status_is(200)
142 ->element_exists('div.notify-error')
143 ->text_is('div.notify-error', 'Bad CSRF token')
Akron9fa7cc52022-05-12 11:17:20 +0200144 ->element_exists('input[name=handle_or_email][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200145 ->element_exists_not('div.button.top a')
146 ;
147
Akron9fa7cc52022-05-12 11:17:20 +0200148$t->post_ok('/user/login' => form => { handle_or_email => 'test', pwd => 'pass' })
Akron33f5c672019-06-24 19:40:47 +0200149 ->status_is(302)
150 ->header_is('Location' => '/');
151
152my $csrf = $t->get_ok('/')
153 ->status_is(200)
154 ->element_exists('div.notify-error')
155 ->text_is('div.notify-error', 'Bad CSRF token')
156 ->element_exists_not('div.button.top a')
157 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
158 ;
159
160$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200161 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200162 pwd => 'ldaperr',
163 csrf_token => $csrf
164})
165 ->status_is(302)
166 ->content_is('')
167 ->header_is('Location' => '/');
168
169$csrf = $t->get_ok('/')
170 ->status_is(200)
171 ->element_exists('div.notify-error')
172 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akron9fa7cc52022-05-12 11:17:20 +0200173 ->element_exists('input[name=handle_or_email][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200174 ->element_exists_not('div.button.top a')
Akron3b3c7af2020-05-15 16:23:55 +0200175 ->element_exists_not('div.notify-success')
Akron33f5c672019-06-24 19:40:47 +0200176 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
177 ;
178
179$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200180 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200181 pwd => 'unknown',
182 csrf_token => $csrf
183})
184 ->status_is(302)
185 ->content_is('')
186 ->header_is('Location' => '/');
187
188$csrf = $t->get_ok('/')
189 ->status_is(200)
190 ->element_exists('div.notify-error')
Akron8bbbecf2019-07-01 18:57:30 +0200191 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akron9fa7cc52022-05-12 11:17:20 +0200192 ->element_exists('input[name=handle_or_email][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200193 ->element_exists_not('div.button.top a')
194 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
195 ;
196
197$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200198 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200199 pwd => 'pass',
200 csrf_token => $csrf
201})
202 ->status_is(302)
203 ->content_is('')
204 ->header_is('Location' => '/');
205
206$t->get_ok('/')
207 ->status_is(200)
208 ->element_exists_not('div.notify-error')
209 ->element_exists('div.notify-success')
210 ->text_is('div.notify-success', 'Login successful')
Akron1d09b532021-06-15 18:18:25 +0200211 ->element_exists_not('aside.off')
Akrondc0b3ab2021-06-18 11:52:43 +0200212 ->element_exists_not('aside.active')
Akron1d09b532021-06-15 18:18:25 +0200213 ->element_exists('aside.settings')
Akron33f5c672019-06-24 19:40:47 +0200214 ;
215
Akron33f5c672019-06-24 19:40:47 +0200216# Now the user is logged in and should be able to
217# search with authorization
218$t->get_ok('/?q=Baum')
219 ->status_is(200)
Akron4cefe1f2019-09-04 10:11:28 +0200220 ->session_has('/auth')
221 ->session_is('/auth', 'Bearer ' . $access_token)
222 ->session_is('/auth_r', $refresh_token)
223 ->session_is('/user', 'test')
Akron33f5c672019-06-24 19:40:47 +0200224 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
225 ->text_like('#total-results', qr/\d+$/)
226 ->element_exists_not('div.notify-error')
Akronbc6b3f22021-01-13 14:53:12 +0100227 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron33f5c672019-06-24 19:40:47 +0200228 ->element_exists('div.button.top a')
229 ->element_exists('div.button.top a.logout[title~="test"]')
230 ;
231
Akron27031aa2020-04-28 14:57:10 +0200232$t->get_ok('/?q=Paum')
233 ->status_is(200)
234 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
235 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100236 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron27031aa2020-04-28 14:57:10 +0200237 ->element_exists_not('p.hint')
238 ;
239
Akroncce055c2021-07-02 12:18:03 +0200240# Query with error
241$t->get_ok('/?q=error')
242 ->status_is(400)
243 ->text_is('#notifications .notify-error','500: Internal Server Error')
244;
Akron27031aa2020-04-28 14:57:10 +0200245
Akron33f5c672019-06-24 19:40:47 +0200246# Logout
247$t->get_ok('/user/logout')
248 ->status_is(302)
Akron4cefe1f2019-09-04 10:11:28 +0200249 ->session_hasnt('/auth')
250 ->session_hasnt('/auth_r')
251 ->session_hasnt('/user')
Akron33f5c672019-06-24 19:40:47 +0200252 ->header_is('Location' => '/');
253
254$t->get_ok('/')
255 ->status_is(200)
256 ->element_exists_not('div.notify-error')
257 ->element_exists('div.notify-success')
258 ->text_is('div.notify-success', 'Logout successful')
Akron9fa7cc52022-05-12 11:17:20 +0200259 ->element_exists("input[name=handle_or_email]")
260 ->element_exists("input[name=handle_or_email][value=test]")
Akron33f5c672019-06-24 19:40:47 +0200261 ;
262
263$t->get_ok('/?q=Baum')
264 ->status_is(200)
265 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
266 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100267 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200268 ;
269
Akron27031aa2020-04-28 14:57:10 +0200270$t->get_ok('/?q=Paum')
271 ->status_is(200)
272 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
273 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100274 ->content_like(qr/${q}authorized${q}:null/)
Akron27031aa2020-04-28 14:57:10 +0200275 ->text_is('p.hint', 'Maybe you need to log in first?')
276 ;
277
278
Akron33f5c672019-06-24 19:40:47 +0200279# Get redirect
280my $fwd = $t->get_ok('/?q=Baum&ql=poliqarp')
281 ->status_is(200)
282 ->element_exists_not('div.notify-error')
283 ->tx->res->dom->at('input[name=fwd]')->attr('value')
284 ;
285
286is($fwd, '/?q=Baum&ql=poliqarp', 'Redirect is valid');
287
288$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200289 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200290 pwd => 'pass',
291 csrf_token => $csrf,
292 fwd => 'http://bad.example.com/test'
293})
294 ->status_is(302)
295 ->header_is('Location' => '/');
296
297$t->get_ok('/')
298 ->status_is(200)
299 ->element_exists('div.notify-error')
300 ->element_exists_not('div.notify-success')
301 ->text_is('div.notify-error', 'Redirect failure')
302 ;
303
304$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200305 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200306 pwd => 'pass',
307 csrf_token => $csrf,
308 fwd => $fwd
309})
310 ->status_is(302)
311 ->header_is('Location' => '/?q=Baum&ql=poliqarp');
312
Akron8bbbecf2019-07-01 18:57:30 +0200313$t->get_ok('/?q=Baum&ql=poliqarp')
314 ->status_is(200)
315 ->element_exists_not('div.notify-error')
316 ->element_exists('div.notify-success')
317 ->text_is('div.notify-success', 'Login successful')
Akroncdfd9d52019-07-23 11:35:00 +0200318 ->session_has('/auth')
319 ->session_is('/auth', 'Bearer ' . $access_token)
320 ->session_is('/auth_r', $refresh_token)
321 ->header_isnt('X-Kalamar-Cache', 'true')
Akron8bbbecf2019-07-01 18:57:30 +0200322 ;
323
Akroncdfd9d52019-07-23 11:35:00 +0200324# Expire the session
325# (makes the token be marked as expired - though it isn't serverside)
326$t->get_ok('/x/expire')
Akron8bbbecf2019-07-01 18:57:30 +0200327 ->status_is(200)
Akroncdfd9d52019-07-23 11:35:00 +0200328 ->content_is('okay')
329 ;
330
331## It may be a problem, but the cache is still valid
332$t->get_ok('/?q=Baum')
333 ->status_is(200)
334 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
335 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100336 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200337 ->header_is('X-Kalamar-Cache', 'true')
338 ;
339
340# Query without partial cache (unfortunately) (but no total results)
Akron58c60992021-09-07 13:11:43 +0200341my $err = $t->get_ok('/?q=baum&cutoff=true')
Akroncdfd9d52019-07-23 11:35:00 +0200342 ->status_is(200)
343 ->session_is('/auth', 'Bearer ' . $access_token_2)
344 ->session_is('/auth_r', $refresh_token_2)
Akroncdfd9d52019-07-23 11:35:00 +0200345 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
346 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
347 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100348 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200349 ->header_isnt('X-Kalamar-Cache', 'true')
Akronbc6b3f22021-01-13 14:53:12 +0100350 ->content_like(qr!${q}cutOff${q}:true!)
Akroncdfd9d52019-07-23 11:35:00 +0200351 ->element_exists_not('#total-results')
Akron58c60992021-09-07 13:11:43 +0200352 ->tx->res->dom->at('#error')
Akroncdfd9d52019-07-23 11:35:00 +0200353 ;
Akron58c60992021-09-07 13:11:43 +0200354is(defined $err ? $err->text : '', '');
Akroncdfd9d52019-07-23 11:35:00 +0200355
356# Expire the session and remove the refresh option
357$t->get_ok('/x/expire-no-refresh')
358 ->status_is(200)
359 ->content_is('okay')
360 ;
361
362$t->app->defaults(no_cache => 1);
363
364
365$t->get_ok('/x/invalid-no-refresh')
366 ->status_is(200)
367 ->content_is('okay')
368 ;
369
370# Query without cache
371# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200372$err = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200373 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200374 ->session_hasnt('/auth')
375 ->session_hasnt('/auth_r')
Akroncdfd9d52019-07-23 11:35:00 +0200376 ->text_is('div.notify-error','Access token invalid')
377 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
378 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
379 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100380 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200381 ->header_isnt('X-Kalamar-Cache', 'true')
382 ->element_exists('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200383 ->tx->res->dom->at('#error')
Akroncdfd9d52019-07-23 11:35:00 +0200384 ;
Akron58c60992021-09-07 13:11:43 +0200385is(defined $err ? $err->text : '', '');
386
Akroncdfd9d52019-07-23 11:35:00 +0200387
388$t->get_ok('/x/invalid')
389 ->status_is(200)
390 ->content_is('okay')
391 ;
392
393# Query without cache
394# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200395$err = $t->get_ok('/?q=baum&cutoff=true')
Akroncdfd9d52019-07-23 11:35:00 +0200396 ->status_is(200)
397 ->session_is('/auth', 'Bearer ' . $access_token_2)
398 ->session_is('/auth_r', $refresh_token_2)
Akroncdfd9d52019-07-23 11:35:00 +0200399 ->element_exists_not('div.notify-error','Access token invalid')
400 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
401 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
402 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100403 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200404 ->header_isnt('X-Kalamar-Cache', 'true')
405 ->element_exists_not('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200406 ->tx->res->dom->at('#error')
Akron8bbbecf2019-07-01 18:57:30 +0200407 ;
Akron58c60992021-09-07 13:11:43 +0200408is(defined $err ? $err->text : '', '');
Akron8bbbecf2019-07-01 18:57:30 +0200409
Akron33f5c672019-06-24 19:40:47 +0200410
Akroncdfd9d52019-07-23 11:35:00 +0200411$t->get_ok('/x/expired-with-wrong-refresh')
412 ->status_is(200)
413 ->content_is('okay')
414 ;
Akron4796e002019-07-05 10:13:15 +0200415
Akron4796e002019-07-05 10:13:15 +0200416
Akroncdfd9d52019-07-23 11:35:00 +0200417# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200418my $dom = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200419 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200420 ->session_hasnt('/auth')
421 ->session_hasnt('/auth_r')
Akroncdfd9d52019-07-23 11:35:00 +0200422 ->text_is('div.notify-error','Refresh token is expired')
423 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
Akronbc6b3f22021-01-13 14:53:12 +0100424 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200425 ->element_exists('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200426 ->tx->res->dom;
427
428$csrf = $dom->at('input[name="csrf_token"]')
Akron59992122019-10-29 11:28:45 +0100429 ->attr('value')
Akroncdfd9d52019-07-23 11:35:00 +0200430 ;
Akron4796e002019-07-05 10:13:15 +0200431
Akron58c60992021-09-07 13:11:43 +0200432$err = $dom->at('#error');
433is(defined $err ? $err->text : '', '');
434
435
Akron6a228db2021-10-14 15:57:00 +0200436# This should fail
437my $wide_char_login = "\x{61}\x{E5}\x{61}"; # "\x{443}\x{434}";
Akron59992122019-10-29 11:28:45 +0100438$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200439 handle_or_email => $wide_char_login,
Akron6a228db2021-10-14 15:57:00 +0200440 pwd => 'pass',
441 csrf_token => $csrf,
442 fwd => $fwd
443})
444 ->status_is(302)
445 ->header_is('Location' => '/');
446
447$t->get_ok('/')
448 ->status_is(200)
449 ->element_exists('div.notify-error')
450 ->text_is('div.notify-error', 'Invalid character in request')
Akron9fa7cc52022-05-12 11:17:20 +0200451 ->element_exists('input[name=handle_or_email]:not([value])')
Akron6a228db2021-10-14 15:57:00 +0200452 ->element_exists_not('div.button.top a')
453 ;
454
455# Login:
456# UTF8 request
457my $username = b('täst')->encode;
458$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200459 handle_or_email => $username,
Akron59992122019-10-29 11:28:45 +0100460 pwd => 'pass',
461 csrf_token => $csrf
462})
463 ->status_is(302)
464 ->content_is('')
465 ->header_is('Location' => '/');
466
467$t->get_ok('/')
468 ->status_is(200)
469 ->element_exists_not('div.notify-error')
470 ->element_exists('div.notify-success')
471 ->text_is('div.notify-success', 'Login successful')
Akron6a228db2021-10-14 15:57:00 +0200472 ->attr_is('a.logout', 'title', "Logout: $username")
Akron1d09b532021-06-15 18:18:25 +0200473 ->element_exists_not('aside.off')
Akrondc0b3ab2021-06-18 11:52:43 +0200474 ->element_exists_not('aside.active')
Akron1d09b532021-06-15 18:18:25 +0200475 ->element_exists('aside.settings')
Akron59992122019-10-29 11:28:45 +0100476 ;
477
478$t->get_ok('/settings/oauth')
479 ->text_is('form.form-table legend', 'Register new client application')
480 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
Akron9f2ad342022-05-04 16:16:40 +0200481 ->text_is('label[for=name]','Name of the client application')
482 ->text_is('label[for=type]','Type of the client application')
483 ->text_is('label[for=desc]','Short description')
484 ->text_is('label[for=url]','Homepage')
485 ->text_is('label[for=redirect_uri]','Redirect URI')
486 ->text_is('label[for=src]','Declaration of the plugin (*.json file)')
Akron1a9d5be2020-03-19 17:28:33 +0100487 ->element_exists('ul.client-list')
488 ->element_exists_not('ul.client-list > li')
Akronad011bb2021-06-10 12:16:36 +0200489 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
490 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
491 ->header_is('Pragma','no-cache')
Akron59992122019-10-29 11:28:45 +0100492 ;
Akronad011bb2021-06-10 12:16:36 +0200493
Akron59992122019-10-29 11:28:45 +0100494$csrf = $t->post_ok('/settings/oauth/register' => form => {
495 name => 'MyApp',
496 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200497 desc => 'This is my plugin application'
Akron59992122019-10-29 11:28:45 +0100498})
499 ->text_is('div.notify-error', 'Bad CSRF token')
500 ->tx->res->dom->at('input[name="csrf_token"]')
501 ->attr('value')
502 ;
503
504$t->post_ok('/settings/oauth/register' => form => {
505 name => 'MyApp',
Akron99968a92022-06-03 12:32:07 +0200506 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200507 desc => 'This is my plugin application',
Akron9f2ad342022-05-04 16:16:40 +0200508 csrf_token => $csrf,
509 src => {
510 filename => '',
511 content => ''
512 }
Akron59992122019-10-29 11:28:45 +0100513})
514 ->status_is(200)
515 ->element_exists('div.notify-success')
516 ->text_is('legend', 'Client Credentials')
517 ->text_is('label[for=client_id]', 'ID of the client application')
518 ->element_exists('input[name=client_id][readonly][value]')
Akron99968a92022-06-03 12:32:07 +0200519 ->element_exists_not('input[name=client_secret][readonly][value]')
Akronad011bb2021-06-10 12:16:36 +0200520 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
521 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
522 ->header_is('Pragma','no-cache')
Akron59992122019-10-29 11:28:45 +0100523 ;
Akron4796e002019-07-05 10:13:15 +0200524
Akron58c60992021-09-07 13:11:43 +0200525my $anchor = $t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200526 ->text_is('.form-table legend', 'Register new client application')
527 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron17de86e2020-04-16 16:03:40 +0200528 ->text_is('ul.client-list > li > span.client-name a', 'MyApp')
Akron6b75d122022-05-12 17:39:05 +0200529 ->text_is('ul.client-list > li > p.client-desc', 'This is my plugin application')
Akronad011bb2021-06-10 12:16:36 +0200530 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
531 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
532 ->header_is('Pragma','no-cache')
Akronb6b156e2022-03-31 14:57:49 +0200533 ->tx->res->dom->at('ul.client-list > li > p.client-url a')
Akron17de86e2020-04-16 16:03:40 +0200534 ;
Akron58c60992021-09-07 13:11:43 +0200535is(defined $anchor ? $anchor->text : '', '');
Akron17de86e2020-04-16 16:03:40 +0200536
Akron041ca4d2021-06-10 11:52:51 +0200537$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akron17de86e2020-04-16 16:03:40 +0200538 ->status_is(200)
Akronc1aaf932021-06-09 12:19:15 +0200539 ->text_is('ul.client-list > li.client > span.client-name', 'MyApp')
Akron6b75d122022-05-12 17:39:05 +0200540 ->text_is('ul.client-list > li.client > p.client-desc', 'This is my plugin application')
Akron17de86e2020-04-16 16:03:40 +0200541 ->text_is('a.client-unregister', 'Unregister')
Akron041ca4d2021-06-10 11:52:51 +0200542 ->attr_is('a.client-unregister', 'href', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100543 ;
544
Akron041ca4d2021-06-10 11:52:51 +0200545$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100546 ->content_like(qr!Do you really want to unregister \<span class="client-name"\>MyApp\<\/span\>?!)
Akronc1aaf932021-06-09 12:19:15 +0200547 ->attr_is('.form-table input[name=client-name]', 'value', 'MyApp')
Akronad011bb2021-06-10 12:16:36 +0200548 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
549 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
550 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100551 ->tx->res->dom->at('input[name="csrf_token"]')
552 ->attr('value')
553 ;
554
Akron041ca4d2021-06-10 11:52:51 +0200555$t->post_ok('/settings/oauth/xxxx==/unregister' => form => {
Akron1a9d5be2020-03-19 17:28:33 +0100556 'client-name' => 'MyApp',
Akron1a9d5be2020-03-19 17:28:33 +0100557 'csrf_token' => $csrf
558})->status_is(302)
559 ->content_is('')
560 ->header_is('Location' => '/settings/oauth')
561 ;
562
563$t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200564 ->text_is('.form-table legend', 'Register new client application')
565 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100566 ->element_exists('ul.client-list > li')
567 ->text_is('div.notify', 'Unknown client with xxxx==.')
Akronad011bb2021-06-10 12:16:36 +0200568 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
569 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
570 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100571 ;
572
Akron041ca4d2021-06-10 11:52:51 +0200573$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister' => form => {
Akron1a9d5be2020-03-19 17:28:33 +0100574 'client-name' => 'MyApp',
Akron1a9d5be2020-03-19 17:28:33 +0100575 'csrf_token' => $csrf
576})->status_is(302)
577 ->content_is('')
578 ->header_is('Location' => '/settings/oauth')
579 ;
580
581$t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200582 ->text_is('.form-table legend', 'Register new client application')
583 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100584 ->element_exists_not('ul.client-list > li')
585 ->text_is('div.notify-success', 'Successfully deleted MyApp')
Akronad011bb2021-06-10 12:16:36 +0200586 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
587 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
588 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100589 ;
590
Akron83209f72021-01-29 17:54:15 +0100591$t->post_ok('/settings/oauth/register' => form => {
592 name => 'MyApp2',
593 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200594 desc => 'This is my plugin application',
Akron83209f72021-01-29 17:54:15 +0100595 csrf_token => $csrf
596})->status_is(200)
597 ->element_exists('div.notify-success')
598 ->text_is('legend', 'Client Credentials')
599 ->text_is('label[for=client_id]', 'ID of the client application')
600 ->element_exists('input[name=client_id][readonly][value]')
601 ->element_exists_not('input[name=client_secret][readonly][value]')
Akronad011bb2021-06-10 12:16:36 +0200602 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
603 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
604 ->header_is('Pragma','no-cache')
Akronb6b156e2022-03-31 14:57:49 +0200605 ->element_exists('.client-issue-token')
Akron83209f72021-01-29 17:54:15 +0100606 ;
607
Akron041ca4d2021-06-10 11:52:51 +0200608$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akron83209f72021-01-29 17:54:15 +0100609 ->text_is('.client-name', 'MyApp2')
Akron6b75d122022-05-12 17:39:05 +0200610 ->text_is('.client-desc', 'This is my plugin application')
Akrone997bb52021-06-11 16:44:06 +0200611 ->text_is('.client-issue-token', 'Issue new token')
Akron041ca4d2021-06-10 11:52:51 +0200612 ->attr_is('.client-issue-token', 'href', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?name=MyApp2')
Akronad011bb2021-06-10 12:16:36 +0200613 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
614 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
615 ->header_is('Pragma','no-cache')
Akrone997bb52021-06-11 16:44:06 +0200616 ->text_is('ul.token-list label[for=token]', 'Access Token')
617 ->text_is('p[name=created]', 'Created at ')
618 ->text_is('p[name=expires]', 'Expires in 31533851 seconds.')
Akronb6b156e2022-03-31 14:57:49 +0200619 ->element_exists('.client-issue-token')
Akron83209f72021-01-29 17:54:15 +0100620 ;
621
Akron041ca4d2021-06-10 11:52:51 +0200622$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?name=MyApp2')
Akron83209f72021-01-29 17:54:15 +0100623 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200624 ->attr_is('#issue-token','action', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token')
Akron83209f72021-01-29 17:54:15 +0100625 ->attr_is('input[name=client-id]', 'value', 'fCBbQkA2NDA3MzM1Yw==')
626 ->attr_is('input[name=name]', 'value', 'MyApp2')
Akronad011bb2021-06-10 12:16:36 +0200627 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
628 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
629 ->header_is('Pragma','no-cache')
Akrone997bb52021-06-11 16:44:06 +0200630 ->text_is('a.button-abort', 'Abort')
631 ->attr_is('#issue-token input[type=submit]', 'value', 'Issue new token')
632 ->content_like(qr!Issue a new token for!)
Akron83209f72021-01-29 17:54:15 +0100633 ->tx->res->dom->at('input[name="csrf_token"]')
634 ->attr('value')
635 ;
636
Akron041ca4d2021-06-10 11:52:51 +0200637$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token' => form => {
Akron83209f72021-01-29 17:54:15 +0100638 csrf_token => $csrf,
639 name => 'MyApp2',
640 'client-id' => 'fCBbQkA2NDA3MzM1Yw=='
641})
Akronbc94a9c2021-04-15 00:07:35 +0200642 ->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200643 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronbc94a9c2021-04-15 00:07:35 +0200644 ;
645
Akron041ca4d2021-06-10 11:52:51 +0200646$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
647 ->status_is(200)
Akronbc94a9c2021-04-15 00:07:35 +0200648 ->text_is('div.notify-success', 'New access token created')
Akronad011bb2021-06-10 12:16:36 +0200649 ->status_is(200)
650 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
651 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
652 ->header_is('Pragma','no-cache')
Akron83209f72021-01-29 17:54:15 +0100653 ;
654
Akron041ca4d2021-06-10 11:52:51 +0200655$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200656 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200657 ->attr_is('form.token-revoke', 'action', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token/revoke')
Akronc1aaf932021-06-09 12:19:15 +0200658 ->attr_is('form.token-revoke input[name=token]', 'value', 'jhkhkjhk_hjgjsfz67i')
659 ->attr_is('form.token-revoke input[name=name]', 'value', 'MyApp2')
660 ->tx->res->dom->at('input[name="csrf_token"]')
661 ->attr('value')
662 ;
663
Akron041ca4d2021-06-10 11:52:51 +0200664$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token/revoke' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200665 csrf_token => $csrf,
666 name => 'MyApp2',
667 token => 'jhkhkjhk_hjgjsfz67i'
668})
669 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200670 ->attr_is('form#revoke-token','action','/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE')
Akronc1aaf932021-06-09 12:19:15 +0200671 ->attr_is('form#revoke-token','method','POST')
672 ->attr_is('form#revoke-token input[name=token]','value','jhkhkjhk_hjgjsfz67i')
Akrone997bb52021-06-11 16:44:06 +0200673 ->text_is('a.button-abort', 'Abort')
674 ->attr_is('#revoke-token input[type=submit]', 'value', 'Revoke')
675 ->content_like(qr!Revoke a token for!)
Akronc1aaf932021-06-09 12:19:15 +0200676;
677
678
679# CSRF missing
Akron041ca4d2021-06-10 11:52:51 +0200680$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200681 name => 'MyApp2',
682 token => 'jhkhkjhk_hjgjsfz67i'
683})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200684 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200685 ;
686
Akron041ca4d2021-06-10 11:52:51 +0200687$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200688 ->element_exists_not('div.notify-success')
689 ->text_is('div.notify-error', 'Bad CSRF token')
690 ;
691
692# Token missing
Akron041ca4d2021-06-10 11:52:51 +0200693$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200694 name => 'MyApp2',
695 csrf_token => $csrf,
696})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200697 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200698 ;
699
Akron041ca4d2021-06-10 11:52:51 +0200700$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200701 ->element_exists_not('div.notify-success')
702 ->text_is('div.notify-error', 'Some fields are invalid')
703 ;
704
Akron041ca4d2021-06-10 11:52:51 +0200705$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200706 name => 'MyApp2',
707 csrf_token => $csrf,
708 token => 'jhkhkjhk_hjgjsfz67i'
709})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200710 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200711 ;
712
Akron041ca4d2021-06-10 11:52:51 +0200713$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200714 ->element_exists_not('div.notify-error')
715 ->text_is('div.notify-success', 'Token was revoked successfully')
716 ;
Akron83209f72021-01-29 17:54:15 +0100717
Akronb6b156e2022-03-31 14:57:49 +0200718$t->app->routes->get('/x/redirect-target')->to(
719 cb => sub {
720 my $c = shift;
721 return $c->render(text => 'redirected');
722 }
723);
724
725$csrf = $t->post_ok('/settings/oauth/register' => form => {
726 name => 'MyConfApp',
727 type => 'CONFIDENTIAL',
Akron6b75d122022-05-12 17:39:05 +0200728 desc => 'This is my plugin application',
Akronb6b156e2022-03-31 14:57:49 +0200729})
730 ->text_is('div.notify-error', 'Bad CSRF token')
731 ->tx->res->dom->at('input[name="csrf_token"]')
732 ->attr('value')
733 ;
734
735$t->post_ok('/settings/oauth/register' => form => {
736 name => 'MyConfApp',
737 type => 'CONFIDENTIAL',
738 desc => 'This is my confidential application',
739 csrf_token => $csrf,
740 redirect_uri => 'http://localhost/redirect-target'
741})
742 ->text_is('div.notify-error', undef)
743 ->text_is('li.client span.client-name', 'MyConfApp')
744 ->text_is('li.client p.client-desc', 'This is my confidential application')
745 ->text_is('li.client .client-redirect-uri tt', 'http://localhost/redirect-target')
746 ->text_is('li.client .client-type tt', 'CONFIDENTIAL')
747 ->element_exists_not('.client-issue-token')
748 ;
749
750$t->post_ok('/settings/oauth/register' => form => {
751 name => 'MyConfApp2',
752 type => 'CONFIDENTIAL',
753 desc => 'This is my second confidential application',
754 csrf_token => $csrf,
755 redirect_uri => 'http://localhost/FAIL'
756})
757 ->status_is(302)
758 ->header_is('location','/settings/oauth/')
759 ;
760
761$t->get_ok('/settings/oauth/')
762 ->text_is('div.notify-error', 'invalid_request: http://localhost/FAIL is invalid.')
763 ;
764
Akrona8efaa92022-04-09 14:45:43 +0200765# OAuth client authorization flow
766$t->get_ok(Mojo::URL->new('/settings/oauth/authorize'))
767 ->status_is(302)
768 ->header_is('location','/settings/oauth/authorize')
769 ;
770
771# Logout
772$t->get_ok('/x/expired-with-wrong-refresh');
773
774$t->get_ok('/user/logout')
775 ->status_is(302)
776 ->session_hasnt('/auth')
777 ->session_hasnt('/auth_r')
778 ->session_hasnt('/user')
779 ->header_is('Location' => '/');
780
781$csrf = $t->get_ok('/')
782 ->status_is(200)
783 ->element_exists_not('div.notify-error')
784 ->element_exists('div.notify-success')
785 ->text_is('div.notify-success', 'Logout successful')
Akron9fa7cc52022-05-12 11:17:20 +0200786 ->element_exists("input[name=handle_or_email]")
Akrona8efaa92022-04-09 14:45:43 +0200787 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
788 ;
789
Akron408bc7c2022-04-28 15:46:43 +0200790$fake_backend_app->add_client({
791 "client_id" => 'xyz',
792 "client_name" => 'New added client',
793 "client_description" => 'This is a new client',
794 "client_url" => 'http://example.com',
795 "client_type" => 'CONFIDENTIAL'
796# "client_redirect_uri" => $redirect_uri
797});
798
Akrona8efaa92022-04-09 14:45:43 +0200799$fwd = $t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
800 client_id => 'xyz',
801 state => 'abcde',
802 scope => 'search match',
803 redirect_uri => 'http://test.com/',
804}))
805 ->status_is(200)
806 ->attr_is('input[name=client_id]','value','xyz')
807 ->attr_is('input[name=state]','value','abcde')
Akrona8efaa92022-04-09 14:45:43 +0200808 ->attr_like('input[name=fwd]','value',qr!test\.com!)
Akron408bc7c2022-04-28 15:46:43 +0200809 ->text_is('span.client-name','New added client')
Akrona8efaa92022-04-09 14:45:43 +0200810 ->text_is('div.intro p:nth-child(2)', 'Please log in!')
811 ->tx->res->dom->at('input[name=fwd]')->attr('value')
812 ;
813
814$fwd = $t->post_ok(Mojo::URL->new('/user/login')->query({
815 csrf_token => $csrf,
816 client_id => 'xyz',
817 state => 'abcde',
818 scope => 'search match',
819 redirect_uri => 'http://test.com/',
Akron9fa7cc52022-05-12 11:17:20 +0200820 handle_or_email => 'test',
Akrona8efaa92022-04-09 14:45:43 +0200821 pwd => 'pass',
822 fwd => $fwd
823}))
824 ->status_is(302)
825 ->header_like('location', qr!/settings/oauth/authorize!)
826 ->tx->res->headers->header('location')
827 ;
828
829$t->get_ok($fwd)
830 ->status_is(200)
831 ->attr_is('input[name=client_id]','value','xyz')
832 ->attr_is('input[name=state]','value','abcde')
Akrona8efaa92022-04-09 14:45:43 +0200833 ->text_is('ul#scopes li:nth-child(1)','search')
834 ->text_is('ul#scopes li:nth-child(2)','match')
Akron408bc7c2022-04-28 15:46:43 +0200835 ->text_is('span.client-name','New added client')
Akrona8efaa92022-04-09 14:45:43 +0200836 ->attr_is('a.form-button','href','http://test.com/')
837 ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
838 ;
839
840$t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
841 client_id => 'xyz',
842 state => 'abcde',
843 scope => 'search match',
844 redirect_uri => 'http://test.com/'
845}))
846 ->status_is(200)
847 ->attr_is('input[name=client_id]','value','xyz')
848 ->attr_is('input[name=state]','value','abcde')
Akrona8efaa92022-04-09 14:45:43 +0200849 ->text_is('ul#scopes li:nth-child(1)','search')
850 ->text_is('ul#scopes li:nth-child(2)','match')
Akron408bc7c2022-04-28 15:46:43 +0200851 ->text_is('span.client-name','New added client')
Akrona8efaa92022-04-09 14:45:43 +0200852 ->attr_is('a.form-button','href','http://test.com/')
853 ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
854 ;
855
856$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
857 client_id => 'xyz',
858 state => 'abcde',
859 scope => 'search match',
860 redirect_uri => 'http://test.com/'
861}))
862 ->status_is(302)
863 ->header_is('location', '/?error_description=Bad+CSRF+token')
864 ;
865
866$fwd = $t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
867 client_id => 'xyz',
868 state => 'abcde',
869 scope => 'search match',
870 redirect_uri_server => 'http://example.com/',
871 redirect_uri => $fake_backend_app->url_for('return_uri')->to_abs,
872 csrf_token => $csrf,
873}))
874 ->status_is(302)
875 ->header_like('location', qr!/realapi/fakeclient/return!)
876 ->tx->res->headers->header('location')
877 ;
878
879$t->get_ok($fwd)
880 ->status_is(200)
881 ->content_like(qr'welcome back! \[(.+?)\]')
882 ;
883
884$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
885 client_id => 'xyz',
886 state => 'fail',
887 scope => 'search match',
888 redirect_uri_server => 'http://example.com/',
889 redirect_uri => $fake_backend_app->url_for('return_uri')->to_abs,
890 csrf_token => $csrf,
891}))
892 ->status_is(302)
893 ->header_is('location', 'http://example.com/?error_description=FAIL')
894 ;
895
Akron9f2ad342022-05-04 16:16:40 +0200896my $json_post = {
897 name => 'Funny',
898 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200899 desc => 'This is my plugin application 2',
Akron9f2ad342022-05-04 16:16:40 +0200900 csrf_token => $csrf,
901 src => 'hMMM'
902};
903
904$t->post_ok('/settings/oauth/register' => form => $json_post)
905 ->status_is(200)
906 ->element_exists('div.notify-error')
Akron99968a92022-06-03 12:32:07 +0200907 ->text_is('div.notify-error', 'Plugin declarations need to be json files')
908 ;
909
910$json_post->{src} = {
911 content => 'jjjjjj',
912 filename => 'fun.txt'
913};
914
915$t->post_ok('/settings/oauth/register' => form => $json_post)
916 ->status_is(200)
917 ->element_exists('div.notify-error')
Akron9f2ad342022-05-04 16:16:40 +0200918 ->text_is('div.notify-error', 'Plugins need to be confidential')
919 ;
920
921$json_post->{type} = 'CONFIDENTIAL';
922
Akron99968a92022-06-03 12:32:07 +0200923# This somehow gets removed in the last form send ...
Akron9f2ad342022-05-04 16:16:40 +0200924$json_post->{src} = {
925 content => 'jjjjjj',
926 filename => 'fun.txt'
927};
928
929$t->post_ok('/settings/oauth/register' => form => $json_post)
930 ->status_is(200)
931 ->element_exists('div.notify-error')
932 ->text_is('div.notify-error', 'Plugin declarations need to be json files')
933 ;
934
935$json_post->{src} = {
936 content => '{"name":"example"}',
937 filename => 'fun.txt'
938};
939
940$t->post_ok('/settings/oauth/register' => form => $json_post)
941 ->status_is(200)
942 ->element_exists_not('div.notify-error')
943 ->element_exists('div.notify-success')
944 ->text_is('div.notify-success', 'Registration successful')
945 ;
946
Akron6b75d122022-05-12 17:39:05 +0200947$t->get_ok('/settings/oauth/jh0gfjhjbfdsgzjghj==')
948 ->status_is(200)
949 ->text_is('div.notify-error', undef)
950 ->text_is('li.client #client_source', '{"name":"example"}')
951 ->text_is('li.client span.client-name', 'Funny')
952 ->text_is('li.client p.client-desc', 'This is my plugin application 2')
953 ->element_exists_not('li.client .client-redirect-uri tt')
954 ->text_is('li.client .client-type tt', 'CONFIDENTIAL')
955 ;
Akron9f2ad342022-05-04 16:16:40 +0200956
Akronb6b156e2022-03-31 14:57:49 +0200957
Akron66ef3b52022-11-22 14:25:15 +0100958# Retest client with super_client_file
959my $client_file = tempfile;
960
961$client_file->spurt(
962 '{"client_id":"2","client_secret":"k414m4r-s3cr3t"}'
963);
964
965$t = Test::Mojo::WithRoles->new('Kalamar' => {
966 Kalamar => {
967 plugins => ['Auth']
968 },
969 'Kalamar-Auth' => {
970 client_file => $client_file,
971 oauth2 => 1
972 }
973});
974
975$t->app->plugin(
976 Mount => {
977 $mount_point =>
978 $fixtures_path->child('mock.pl')
979 }
980);
981
982$csrf = $t->get_ok('/')
983 ->status_is(200)
984 ->element_exists_not('div.button.top a')
985 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
986 ;
987
988$t->post_ok('/user/login' => form => {
989 handle_or_email => 'test',
990 pwd => 'pass',
991 csrf_token => $csrf
992})
993 ->status_is(302)
994 ->header_is('Location' => '/')
995 ->content_is('');
996
997$t->get_ok('/')
998 ->status_is(200)
999 ->element_exists_not('div.notify-error')
1000 ->element_exists('div.notify-success')
1001 ->text_is('div.notify-success', 'Login successful')
1002 ->element_exists_not('aside.off')
1003 ->element_exists_not('aside.active')
1004 ->element_exists('aside.settings')
1005 ;
1006
1007
Akron33f5c672019-06-24 19:40:47 +02001008done_testing;
1009__END__
Akrona8efaa92022-04-09 14:45:43 +02001010
1011