blob: cfcfc87b6db4772f432724e523c0a03fd971f729 [file] [log] [blame]
Akron33f5c672019-06-24 19:40:47 +02001use Mojo::Base -strict;
2use Test::More;
Akroncdfd9d52019-07-23 11:35:00 +02003use Test::Mojo::WithRoles 'Session';
Akron33f5c672019-06-24 19:40:47 +02004use Mojo::File qw/path/;
5use Data::Dumper;
6
7
8#####################
9# Start Fake server #
10#####################
Akron63d963b2019-07-05 15:35:51 +020011my $mount_point = '/realapi/';
Akron33f5c672019-06-24 19:40:47 +020012$ENV{KALAMAR_API} = $mount_point;
13
Akroncdfd9d52019-07-23 11:35:00 +020014my $t = Test::Mojo::WithRoles->new('Kalamar' => {
Akron33f5c672019-06-24 19:40:47 +020015 Kalamar => {
16 plugins => ['Auth']
17 },
18 'Kalamar-Auth' => {
19 client_id => 2,
20 client_secret => 'k414m4r-s3cr3t',
Akron59992122019-10-29 11:28:45 +010021 oauth2 => 1,
22 experimental_client_registration => 1
Akron33f5c672019-06-24 19:40:47 +020023 }
24});
25
26# Mount fake backend
27# Get the fixture path
28my $fixtures_path = path(Mojo::File->new(__FILE__)->dirname, '..', 'server');
29my $fake_backend = $t->app->plugin(
30 Mount => {
31 $mount_point =>
32 $fixtures_path->child('mock.pl')
33 }
34);
35# Configure fake backend
Akroncdfd9d52019-07-23 11:35:00 +020036my $fake_backend_app = $fake_backend->pattern->defaults->{app};
37
38# Set general app logger for simplicity
39$fake_backend_app->log($t->app->log);
40
41my $access_token = $fake_backend_app->get_token('access_token');
42my $refresh_token = $fake_backend_app->get_token('refresh_token');
43my $access_token_2 = $fake_backend_app->get_token('access_token_2');
44my $refresh_token_2 = $fake_backend_app->get_token('refresh_token_2');
45
46# Some routes to modify the session
47# This expires the session
48$t->app->routes->get('/x/expire')->to(
49 cb => sub {
50 my $c = shift;
51 $c->session(auth_exp => 0);
52 return $c->render(text => 'okay')
53 }
54);
55
56# This expires the session and removes the refresh token
57$t->app->routes->get('/x/expire-no-refresh')->to(
58 cb => sub {
59 my $c = shift;
60 $c->session(auth_exp => 0);
61 delete $c->session->{auth_r};
62 return $c->render(text => 'okay')
63 }
64);
65
66# This sets an invalid token
67$t->app->routes->get('/x/invalid')->to(
68 cb => sub {
69 my $c = shift;
70 $c->session(auth_exp => time + 1000);
71 $c->session(auth_r => $refresh_token_2);
72 $c->session(auth => 'Bearer inv4lid');
73 return $c->render(text => 'okay')
74 }
75);
76
77
78# This sets an invalid token
79$t->app->routes->get('/x/invalid-no-refresh')->to(
80 cb => sub {
81 my $c = shift;
82 $c->session(auth_exp => time + 1000);
83 delete $c->session->{auth_r};
84 $c->session(auth => 'Bearer inv4lid');
85 return $c->render(text => 'okay')
86 }
87);
88
89# This sets an invalid refresh token
90$t->app->routes->get('/x/expired-with-wrong-refresh')->to(
91 cb => sub {
92 my $c = shift;
93 $c->session(auth_exp => 0);
94 $c->session(auth => 'Bearer inv4lid');
95 $c->session(auth_r => 'inv4lid');
96 return $c->render(text => 'okay')
97 }
98);
99
Akronbc6b3f22021-01-13 14:53:12 +0100100my $q = qr!(?:\"|")!;
Akron33f5c672019-06-24 19:40:47 +0200101
Akron63d963b2019-07-05 15:35:51 +0200102$t->get_ok('/realapi/v1.0')
Akron33f5c672019-06-24 19:40:47 +0200103 ->status_is(200)
104 ->content_is('Fake server available');
105
106$t->get_ok('/?q=Baum')
107 ->status_is(200)
108 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
109 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100110 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200111 ->element_exists_not('div.button.top a')
112 ->element_exists_not('aside.active')
113 ->element_exists_not('aside.off')
114 ;
115
116$t->get_ok('/')
117 ->status_is(200)
Akrone208d302020-11-28 11:14:50 +0100118 ->element_exists('form[action=/user/login] input[name=handle]')
Akron33f5c672019-06-24 19:40:47 +0200119 ->element_exists('aside.active')
120 ->element_exists_not('aside.off')
121 ;
122
Akronff088112021-06-15 15:26:04 +0200123$t->get_ok('/settings/oauth')
124 ->status_is(401)
125 ->text_is('p.no-results', 'Not authenticated')
126 ;
127
Akron3e0fdc12020-05-15 16:17:21 +0200128# Test for bug with long password
129$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100130 handle => 'test',
Akron3e0fdc12020-05-15 16:17:21 +0200131 pwd => 'kjskjhndkjndqknaskjnakjdnkjdankajdnkjdsankjdsakjdfkjahzroiuqzriudjoijdmlamdlkmdsalkmdl' })
132 ->status_is(302)
133 ->header_is('Location' => '/');
134
Akrone208d302020-11-28 11:14:50 +0100135$t->post_ok('/user/login' => form => { handle => 'test', pwd => 'fail' })
Akron33f5c672019-06-24 19:40:47 +0200136 ->status_is(302)
137 ->header_is('Location' => '/');
138
139$t->get_ok('/')
140 ->status_is(200)
141 ->element_exists('div.notify-error')
142 ->text_is('div.notify-error', 'Bad CSRF token')
Akrone208d302020-11-28 11:14:50 +0100143 ->element_exists('input[name=handle][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200144 ->element_exists_not('div.button.top a')
145 ;
146
Akrone208d302020-11-28 11:14:50 +0100147$t->post_ok('/user/login' => form => { handle => 'test', pwd => 'pass' })
Akron33f5c672019-06-24 19:40:47 +0200148 ->status_is(302)
149 ->header_is('Location' => '/');
150
151my $csrf = $t->get_ok('/')
152 ->status_is(200)
153 ->element_exists('div.notify-error')
154 ->text_is('div.notify-error', 'Bad CSRF token')
155 ->element_exists_not('div.button.top a')
156 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
157 ;
158
159$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100160 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200161 pwd => 'ldaperr',
162 csrf_token => $csrf
163})
164 ->status_is(302)
165 ->content_is('')
166 ->header_is('Location' => '/');
167
168$csrf = $t->get_ok('/')
169 ->status_is(200)
170 ->element_exists('div.notify-error')
171 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akrone208d302020-11-28 11:14:50 +0100172 ->element_exists('input[name=handle][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200173 ->element_exists_not('div.button.top a')
Akron3b3c7af2020-05-15 16:23:55 +0200174 ->element_exists_not('div.notify-success')
Akron33f5c672019-06-24 19:40:47 +0200175 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
176 ;
177
178$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100179 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200180 pwd => 'unknown',
181 csrf_token => $csrf
182})
183 ->status_is(302)
184 ->content_is('')
185 ->header_is('Location' => '/');
186
187$csrf = $t->get_ok('/')
188 ->status_is(200)
189 ->element_exists('div.notify-error')
Akron8bbbecf2019-07-01 18:57:30 +0200190 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akrone208d302020-11-28 11:14:50 +0100191 ->element_exists('input[name=handle][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200192 ->element_exists_not('div.button.top a')
193 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
194 ;
195
196$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100197 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200198 pwd => 'pass',
199 csrf_token => $csrf
200})
201 ->status_is(302)
202 ->content_is('')
203 ->header_is('Location' => '/');
204
205$t->get_ok('/')
206 ->status_is(200)
207 ->element_exists_not('div.notify-error')
208 ->element_exists('div.notify-success')
209 ->text_is('div.notify-success', 'Login successful')
Akron1d09b532021-06-15 18:18:25 +0200210 ->element_exists_not('aside.off')
Akrondc0b3ab2021-06-18 11:52:43 +0200211 ->element_exists_not('aside.active')
Akron1d09b532021-06-15 18:18:25 +0200212 ->element_exists('aside.settings')
Akron33f5c672019-06-24 19:40:47 +0200213 ;
214
Akron33f5c672019-06-24 19:40:47 +0200215# Now the user is logged in and should be able to
216# search with authorization
217$t->get_ok('/?q=Baum')
218 ->status_is(200)
Akron4cefe1f2019-09-04 10:11:28 +0200219 ->session_has('/auth')
220 ->session_is('/auth', 'Bearer ' . $access_token)
221 ->session_is('/auth_r', $refresh_token)
222 ->session_is('/user', 'test')
Akron33f5c672019-06-24 19:40:47 +0200223 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
224 ->text_like('#total-results', qr/\d+$/)
225 ->element_exists_not('div.notify-error')
Akronbc6b3f22021-01-13 14:53:12 +0100226 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron33f5c672019-06-24 19:40:47 +0200227 ->element_exists('div.button.top a')
228 ->element_exists('div.button.top a.logout[title~="test"]')
229 ;
230
Akron27031aa2020-04-28 14:57:10 +0200231$t->get_ok('/?q=Paum')
232 ->status_is(200)
233 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
234 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100235 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron27031aa2020-04-28 14:57:10 +0200236 ->element_exists_not('p.hint')
237 ;
238
Akroncce055c2021-07-02 12:18:03 +0200239# Query with error
240$t->get_ok('/?q=error')
241 ->status_is(400)
242 ->text_is('#notifications .notify-error','500: Internal Server Error')
243;
Akron27031aa2020-04-28 14:57:10 +0200244
Akron33f5c672019-06-24 19:40:47 +0200245# Logout
246$t->get_ok('/user/logout')
247 ->status_is(302)
Akron4cefe1f2019-09-04 10:11:28 +0200248 ->session_hasnt('/auth')
249 ->session_hasnt('/auth_r')
250 ->session_hasnt('/user')
Akron33f5c672019-06-24 19:40:47 +0200251 ->header_is('Location' => '/');
252
253$t->get_ok('/')
254 ->status_is(200)
255 ->element_exists_not('div.notify-error')
256 ->element_exists('div.notify-success')
257 ->text_is('div.notify-success', 'Logout successful')
Akrone208d302020-11-28 11:14:50 +0100258 ->element_exists("input[name=handle]")
259 ->element_exists("input[name=handle][value=test]")
Akron33f5c672019-06-24 19:40:47 +0200260 ;
261
262$t->get_ok('/?q=Baum')
263 ->status_is(200)
264 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
265 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100266 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200267 ;
268
Akron27031aa2020-04-28 14:57:10 +0200269$t->get_ok('/?q=Paum')
270 ->status_is(200)
271 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
272 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100273 ->content_like(qr/${q}authorized${q}:null/)
Akron27031aa2020-04-28 14:57:10 +0200274 ->text_is('p.hint', 'Maybe you need to log in first?')
275 ;
276
277
Akron33f5c672019-06-24 19:40:47 +0200278# Get redirect
279my $fwd = $t->get_ok('/?q=Baum&ql=poliqarp')
280 ->status_is(200)
281 ->element_exists_not('div.notify-error')
282 ->tx->res->dom->at('input[name=fwd]')->attr('value')
283 ;
284
285is($fwd, '/?q=Baum&ql=poliqarp', 'Redirect is valid');
286
287$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100288 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200289 pwd => 'pass',
290 csrf_token => $csrf,
291 fwd => 'http://bad.example.com/test'
292})
293 ->status_is(302)
294 ->header_is('Location' => '/');
295
296$t->get_ok('/')
297 ->status_is(200)
298 ->element_exists('div.notify-error')
299 ->element_exists_not('div.notify-success')
300 ->text_is('div.notify-error', 'Redirect failure')
301 ;
302
303$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100304 handle => 'test',
Akron33f5c672019-06-24 19:40:47 +0200305 pwd => 'pass',
306 csrf_token => $csrf,
307 fwd => $fwd
308})
309 ->status_is(302)
310 ->header_is('Location' => '/?q=Baum&ql=poliqarp');
311
Akron8bbbecf2019-07-01 18:57:30 +0200312$t->get_ok('/?q=Baum&ql=poliqarp')
313 ->status_is(200)
314 ->element_exists_not('div.notify-error')
315 ->element_exists('div.notify-success')
316 ->text_is('div.notify-success', 'Login successful')
Akroncdfd9d52019-07-23 11:35:00 +0200317 ->session_has('/auth')
318 ->session_is('/auth', 'Bearer ' . $access_token)
319 ->session_is('/auth_r', $refresh_token)
320 ->header_isnt('X-Kalamar-Cache', 'true')
Akron8bbbecf2019-07-01 18:57:30 +0200321 ;
322
Akroncdfd9d52019-07-23 11:35:00 +0200323# Expire the session
324# (makes the token be marked as expired - though it isn't serverside)
325$t->get_ok('/x/expire')
Akron8bbbecf2019-07-01 18:57:30 +0200326 ->status_is(200)
Akroncdfd9d52019-07-23 11:35:00 +0200327 ->content_is('okay')
328 ;
329
330## It may be a problem, but the cache is still valid
331$t->get_ok('/?q=Baum')
332 ->status_is(200)
333 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
334 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100335 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200336 ->header_is('X-Kalamar-Cache', 'true')
337 ;
338
339# Query without partial cache (unfortunately) (but no total results)
Akron58c60992021-09-07 13:11:43 +0200340my $err = $t->get_ok('/?q=baum&cutoff=true')
Akroncdfd9d52019-07-23 11:35:00 +0200341 ->status_is(200)
342 ->session_is('/auth', 'Bearer ' . $access_token_2)
343 ->session_is('/auth_r', $refresh_token_2)
Akroncdfd9d52019-07-23 11:35:00 +0200344 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
345 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
346 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100347 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200348 ->header_isnt('X-Kalamar-Cache', 'true')
Akronbc6b3f22021-01-13 14:53:12 +0100349 ->content_like(qr!${q}cutOff${q}:true!)
Akroncdfd9d52019-07-23 11:35:00 +0200350 ->element_exists_not('#total-results')
Akron58c60992021-09-07 13:11:43 +0200351 ->tx->res->dom->at('#error')
Akroncdfd9d52019-07-23 11:35:00 +0200352 ;
Akron58c60992021-09-07 13:11:43 +0200353is(defined $err ? $err->text : '', '');
Akroncdfd9d52019-07-23 11:35:00 +0200354
355# Expire the session and remove the refresh option
356$t->get_ok('/x/expire-no-refresh')
357 ->status_is(200)
358 ->content_is('okay')
359 ;
360
361$t->app->defaults(no_cache => 1);
362
363
364$t->get_ok('/x/invalid-no-refresh')
365 ->status_is(200)
366 ->content_is('okay')
367 ;
368
369# Query without cache
370# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200371$err = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200372 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200373 ->session_hasnt('/auth')
374 ->session_hasnt('/auth_r')
Akroncdfd9d52019-07-23 11:35:00 +0200375 ->text_is('div.notify-error','Access token invalid')
376 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
377 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
378 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100379 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200380 ->header_isnt('X-Kalamar-Cache', 'true')
381 ->element_exists('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200382 ->tx->res->dom->at('#error')
Akroncdfd9d52019-07-23 11:35:00 +0200383 ;
Akron58c60992021-09-07 13:11:43 +0200384is(defined $err ? $err->text : '', '');
385
Akroncdfd9d52019-07-23 11:35:00 +0200386
387$t->get_ok('/x/invalid')
388 ->status_is(200)
389 ->content_is('okay')
390 ;
391
392# Query without cache
393# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200394$err = $t->get_ok('/?q=baum&cutoff=true')
Akroncdfd9d52019-07-23 11:35:00 +0200395 ->status_is(200)
396 ->session_is('/auth', 'Bearer ' . $access_token_2)
397 ->session_is('/auth_r', $refresh_token_2)
Akroncdfd9d52019-07-23 11:35:00 +0200398 ->element_exists_not('div.notify-error','Access token invalid')
399 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
400 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
401 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100402 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200403 ->header_isnt('X-Kalamar-Cache', 'true')
404 ->element_exists_not('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200405 ->tx->res->dom->at('#error')
Akron8bbbecf2019-07-01 18:57:30 +0200406 ;
Akron58c60992021-09-07 13:11:43 +0200407is(defined $err ? $err->text : '', '');
Akron8bbbecf2019-07-01 18:57:30 +0200408
Akron33f5c672019-06-24 19:40:47 +0200409
Akroncdfd9d52019-07-23 11:35:00 +0200410$t->get_ok('/x/expired-with-wrong-refresh')
411 ->status_is(200)
412 ->content_is('okay')
413 ;
Akron4796e002019-07-05 10:13:15 +0200414
Akron4796e002019-07-05 10:13:15 +0200415
Akroncdfd9d52019-07-23 11:35:00 +0200416# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200417my $dom = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200418 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200419 ->session_hasnt('/auth')
420 ->session_hasnt('/auth_r')
Akroncdfd9d52019-07-23 11:35:00 +0200421 ->text_is('div.notify-error','Refresh token is expired')
422 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
Akronbc6b3f22021-01-13 14:53:12 +0100423 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200424 ->element_exists('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200425 ->tx->res->dom;
426
427$csrf = $dom->at('input[name="csrf_token"]')
Akron59992122019-10-29 11:28:45 +0100428 ->attr('value')
Akroncdfd9d52019-07-23 11:35:00 +0200429 ;
Akron4796e002019-07-05 10:13:15 +0200430
Akron58c60992021-09-07 13:11:43 +0200431$err = $dom->at('#error');
432is(defined $err ? $err->text : '', '');
433
434
Akron59992122019-10-29 11:28:45 +0100435# Login:
436$t->post_ok('/user/login' => form => {
Akrone208d302020-11-28 11:14:50 +0100437 handle => 'test',
Akron59992122019-10-29 11:28:45 +0100438 pwd => 'pass',
439 csrf_token => $csrf
440})
441 ->status_is(302)
442 ->content_is('')
443 ->header_is('Location' => '/');
444
445$t->get_ok('/')
446 ->status_is(200)
447 ->element_exists_not('div.notify-error')
448 ->element_exists('div.notify-success')
449 ->text_is('div.notify-success', 'Login successful')
Akron1d09b532021-06-15 18:18:25 +0200450 ->element_exists_not('aside.off')
Akrondc0b3ab2021-06-18 11:52:43 +0200451 ->element_exists_not('aside.active')
Akron1d09b532021-06-15 18:18:25 +0200452 ->element_exists('aside.settings')
Akron59992122019-10-29 11:28:45 +0100453 ;
454
455$t->get_ok('/settings/oauth')
456 ->text_is('form.form-table legend', 'Register new client application')
457 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100458 ->element_exists('ul.client-list')
459 ->element_exists_not('ul.client-list > li')
Akronad011bb2021-06-10 12:16:36 +0200460 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
461 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
462 ->header_is('Pragma','no-cache')
Akron59992122019-10-29 11:28:45 +0100463 ;
Akronad011bb2021-06-10 12:16:36 +0200464
Akron59992122019-10-29 11:28:45 +0100465$csrf = $t->post_ok('/settings/oauth/register' => form => {
466 name => 'MyApp',
467 type => 'PUBLIC',
468 desc => 'This is my application'
469})
470 ->text_is('div.notify-error', 'Bad CSRF token')
471 ->tx->res->dom->at('input[name="csrf_token"]')
472 ->attr('value')
473 ;
474
475$t->post_ok('/settings/oauth/register' => form => {
476 name => 'MyApp',
477 type => 'CONFIDENTIAL',
478 desc => 'This is my application',
479 csrf_token => $csrf
480})
481 ->status_is(200)
482 ->element_exists('div.notify-success')
483 ->text_is('legend', 'Client Credentials')
484 ->text_is('label[for=client_id]', 'ID of the client application')
485 ->element_exists('input[name=client_id][readonly][value]')
486 ->element_exists('input[name=client_secret][readonly][value]')
Akronad011bb2021-06-10 12:16:36 +0200487 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
488 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
489 ->header_is('Pragma','no-cache')
Akron59992122019-10-29 11:28:45 +0100490 ;
Akron4796e002019-07-05 10:13:15 +0200491
Akron58c60992021-09-07 13:11:43 +0200492my $anchor = $t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200493 ->text_is('.form-table legend', 'Register new client application')
494 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron17de86e2020-04-16 16:03:40 +0200495 ->text_is('ul.client-list > li > span.client-name a', 'MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100496 ->text_is('ul.client-list > li > span.client-desc', 'This is my application')
Akronad011bb2021-06-10 12:16:36 +0200497 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
498 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
499 ->header_is('Pragma','no-cache')
Akron58c60992021-09-07 13:11:43 +0200500 ->tx->res->dom->at('ul.client-list > li > span.client-url a')
Akron17de86e2020-04-16 16:03:40 +0200501 ;
Akron58c60992021-09-07 13:11:43 +0200502is(defined $anchor ? $anchor->text : '', '');
Akron17de86e2020-04-16 16:03:40 +0200503
Akron041ca4d2021-06-10 11:52:51 +0200504$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akron17de86e2020-04-16 16:03:40 +0200505 ->status_is(200)
Akronc1aaf932021-06-09 12:19:15 +0200506 ->text_is('ul.client-list > li.client > span.client-name', 'MyApp')
507 ->text_is('ul.client-list > li.client > span.client-desc', 'This is my application')
Akron17de86e2020-04-16 16:03:40 +0200508 ->text_is('a.client-unregister', 'Unregister')
Akron041ca4d2021-06-10 11:52:51 +0200509 ->attr_is('a.client-unregister', 'href', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100510 ;
511
Akron041ca4d2021-06-10 11:52:51 +0200512$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100513 ->content_like(qr!Do you really want to unregister \<span class="client-name"\>MyApp\<\/span\>?!)
Akronc1aaf932021-06-09 12:19:15 +0200514 ->attr_is('.form-table input[name=client-name]', 'value', 'MyApp')
Akronad011bb2021-06-10 12:16:36 +0200515 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
516 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
517 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100518 ->tx->res->dom->at('input[name="csrf_token"]')
519 ->attr('value')
520 ;
521
Akron041ca4d2021-06-10 11:52:51 +0200522$t->post_ok('/settings/oauth/xxxx==/unregister' => form => {
Akron1a9d5be2020-03-19 17:28:33 +0100523 'client-name' => 'MyApp',
Akron1a9d5be2020-03-19 17:28:33 +0100524 'csrf_token' => $csrf
525})->status_is(302)
526 ->content_is('')
527 ->header_is('Location' => '/settings/oauth')
528 ;
529
530$t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200531 ->text_is('.form-table legend', 'Register new client application')
532 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100533 ->element_exists('ul.client-list > li')
534 ->text_is('div.notify', 'Unknown client with xxxx==.')
Akronad011bb2021-06-10 12:16:36 +0200535 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
536 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
537 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100538 ;
539
Akron041ca4d2021-06-10 11:52:51 +0200540$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister' => form => {
Akron1a9d5be2020-03-19 17:28:33 +0100541 'client-name' => 'MyApp',
Akron1a9d5be2020-03-19 17:28:33 +0100542 'csrf_token' => $csrf
543})->status_is(302)
544 ->content_is('')
545 ->header_is('Location' => '/settings/oauth')
546 ;
547
548$t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200549 ->text_is('.form-table legend', 'Register new client application')
550 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100551 ->element_exists_not('ul.client-list > li')
552 ->text_is('div.notify-success', 'Successfully deleted MyApp')
Akronad011bb2021-06-10 12:16:36 +0200553 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
554 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
555 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100556 ;
557
Akron83209f72021-01-29 17:54:15 +0100558$t->post_ok('/settings/oauth/register' => form => {
559 name => 'MyApp2',
560 type => 'PUBLIC',
561 desc => 'This is my application',
562 csrf_token => $csrf
563})->status_is(200)
564 ->element_exists('div.notify-success')
565 ->text_is('legend', 'Client Credentials')
566 ->text_is('label[for=client_id]', 'ID of the client application')
567 ->element_exists('input[name=client_id][readonly][value]')
568 ->element_exists_not('input[name=client_secret][readonly][value]')
Akronad011bb2021-06-10 12:16:36 +0200569 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
570 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
571 ->header_is('Pragma','no-cache')
Akron83209f72021-01-29 17:54:15 +0100572 ;
573
Akron041ca4d2021-06-10 11:52:51 +0200574$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akron83209f72021-01-29 17:54:15 +0100575 ->text_is('.client-name', 'MyApp2')
576 ->text_is('.client-desc', 'This is my application')
Akrone997bb52021-06-11 16:44:06 +0200577 ->text_is('.client-issue-token', 'Issue new token')
Akron041ca4d2021-06-10 11:52:51 +0200578 ->attr_is('.client-issue-token', 'href', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?name=MyApp2')
Akronad011bb2021-06-10 12:16:36 +0200579 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
580 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
581 ->header_is('Pragma','no-cache')
Akrone997bb52021-06-11 16:44:06 +0200582 ->text_is('ul.token-list label[for=token]', 'Access Token')
583 ->text_is('p[name=created]', 'Created at ')
584 ->text_is('p[name=expires]', 'Expires in 31533851 seconds.')
Akron83209f72021-01-29 17:54:15 +0100585 ;
586
Akron041ca4d2021-06-10 11:52:51 +0200587$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?name=MyApp2')
Akron83209f72021-01-29 17:54:15 +0100588 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200589 ->attr_is('#issue-token','action', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token')
Akron83209f72021-01-29 17:54:15 +0100590 ->attr_is('input[name=client-id]', 'value', 'fCBbQkA2NDA3MzM1Yw==')
591 ->attr_is('input[name=name]', 'value', 'MyApp2')
Akronad011bb2021-06-10 12:16:36 +0200592 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
593 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
594 ->header_is('Pragma','no-cache')
Akrone997bb52021-06-11 16:44:06 +0200595 ->text_is('a.button-abort', 'Abort')
596 ->attr_is('#issue-token input[type=submit]', 'value', 'Issue new token')
597 ->content_like(qr!Issue a new token for!)
Akron83209f72021-01-29 17:54:15 +0100598 ->tx->res->dom->at('input[name="csrf_token"]')
599 ->attr('value')
600 ;
601
Akron041ca4d2021-06-10 11:52:51 +0200602$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token' => form => {
Akron83209f72021-01-29 17:54:15 +0100603 csrf_token => $csrf,
604 name => 'MyApp2',
605 'client-id' => 'fCBbQkA2NDA3MzM1Yw=='
606})
Akronbc94a9c2021-04-15 00:07:35 +0200607 ->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200608 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronbc94a9c2021-04-15 00:07:35 +0200609 ;
610
Akron041ca4d2021-06-10 11:52:51 +0200611$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
612 ->status_is(200)
Akronbc94a9c2021-04-15 00:07:35 +0200613 ->text_is('div.notify-success', 'New access token created')
Akronad011bb2021-06-10 12:16:36 +0200614 ->status_is(200)
615 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
616 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
617 ->header_is('Pragma','no-cache')
Akron83209f72021-01-29 17:54:15 +0100618 ;
619
Akron041ca4d2021-06-10 11:52:51 +0200620$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200621 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200622 ->attr_is('form.token-revoke', 'action', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token/revoke')
Akronc1aaf932021-06-09 12:19:15 +0200623 ->attr_is('form.token-revoke input[name=token]', 'value', 'jhkhkjhk_hjgjsfz67i')
624 ->attr_is('form.token-revoke input[name=name]', 'value', 'MyApp2')
625 ->tx->res->dom->at('input[name="csrf_token"]')
626 ->attr('value')
627 ;
628
Akron041ca4d2021-06-10 11:52:51 +0200629$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token/revoke' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200630 csrf_token => $csrf,
631 name => 'MyApp2',
632 token => 'jhkhkjhk_hjgjsfz67i'
633})
634 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200635 ->attr_is('form#revoke-token','action','/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE')
Akronc1aaf932021-06-09 12:19:15 +0200636 ->attr_is('form#revoke-token','method','POST')
637 ->attr_is('form#revoke-token input[name=token]','value','jhkhkjhk_hjgjsfz67i')
Akrone997bb52021-06-11 16:44:06 +0200638 ->text_is('a.button-abort', 'Abort')
639 ->attr_is('#revoke-token input[type=submit]', 'value', 'Revoke')
640 ->content_like(qr!Revoke a token for!)
Akronc1aaf932021-06-09 12:19:15 +0200641;
642
643
644# CSRF missing
Akron041ca4d2021-06-10 11:52:51 +0200645$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200646 name => 'MyApp2',
647 token => 'jhkhkjhk_hjgjsfz67i'
648})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200649 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200650 ;
651
Akron041ca4d2021-06-10 11:52:51 +0200652$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200653 ->element_exists_not('div.notify-success')
654 ->text_is('div.notify-error', 'Bad CSRF token')
655 ;
656
657# Token missing
Akron041ca4d2021-06-10 11:52:51 +0200658$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200659 name => 'MyApp2',
660 csrf_token => $csrf,
661})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200662 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200663 ;
664
Akron041ca4d2021-06-10 11:52:51 +0200665$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200666 ->element_exists_not('div.notify-success')
667 ->text_is('div.notify-error', 'Some fields are invalid')
668 ;
669
Akron041ca4d2021-06-10 11:52:51 +0200670$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200671 name => 'MyApp2',
672 csrf_token => $csrf,
673 token => 'jhkhkjhk_hjgjsfz67i'
674})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200675 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200676 ;
677
678
Akron041ca4d2021-06-10 11:52:51 +0200679$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200680 ->element_exists_not('div.notify-error')
681 ->text_is('div.notify-success', 'Token was revoked successfully')
682 ;
Akron83209f72021-01-29 17:54:15 +0100683
Akron33f5c672019-06-24 19:40:47 +0200684done_testing;
685__END__