blob: f03f61e1c013683d1e04856a706c39566d7eae0d [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',
21 oauth2 => 1
22 }
23});
24
25# Mount fake backend
26# Get the fixture path
27my $fixtures_path = path(Mojo::File->new(__FILE__)->dirname, '..', 'server');
28my $fake_backend = $t->app->plugin(
29 Mount => {
30 $mount_point =>
31 $fixtures_path->child('mock.pl')
32 }
33);
34# Configure fake backend
Akroncdfd9d52019-07-23 11:35:00 +020035my $fake_backend_app = $fake_backend->pattern->defaults->{app};
36
37# Set general app logger for simplicity
38$fake_backend_app->log($t->app->log);
39
40my $access_token = $fake_backend_app->get_token('access_token');
41my $refresh_token = $fake_backend_app->get_token('refresh_token');
42my $access_token_2 = $fake_backend_app->get_token('access_token_2');
43my $refresh_token_2 = $fake_backend_app->get_token('refresh_token_2');
44
45# Some routes to modify the session
46# This expires the session
47$t->app->routes->get('/x/expire')->to(
48 cb => sub {
49 my $c = shift;
50 $c->session(auth_exp => 0);
51 return $c->render(text => 'okay')
52 }
53);
54
55# This expires the session and removes the refresh token
56$t->app->routes->get('/x/expire-no-refresh')->to(
57 cb => sub {
58 my $c = shift;
59 $c->session(auth_exp => 0);
60 delete $c->session->{auth_r};
61 return $c->render(text => 'okay')
62 }
63);
64
65# This sets an invalid token
66$t->app->routes->get('/x/invalid')->to(
67 cb => sub {
68 my $c = shift;
69 $c->session(auth_exp => time + 1000);
70 $c->session(auth_r => $refresh_token_2);
71 $c->session(auth => 'Bearer inv4lid');
72 return $c->render(text => 'okay')
73 }
74);
75
76
77# This sets an invalid token
78$t->app->routes->get('/x/invalid-no-refresh')->to(
79 cb => sub {
80 my $c = shift;
81 $c->session(auth_exp => time + 1000);
82 delete $c->session->{auth_r};
83 $c->session(auth => 'Bearer inv4lid');
84 return $c->render(text => 'okay')
85 }
86);
87
88# This sets an invalid refresh token
89$t->app->routes->get('/x/expired-with-wrong-refresh')->to(
90 cb => sub {
91 my $c = shift;
92 $c->session(auth_exp => 0);
93 $c->session(auth => 'Bearer inv4lid');
94 $c->session(auth_r => 'inv4lid');
95 return $c->render(text => 'okay')
96 }
97);
98
Akron33f5c672019-06-24 19:40:47 +020099
Akron63d963b2019-07-05 15:35:51 +0200100$t->get_ok('/realapi/v1.0')
Akron33f5c672019-06-24 19:40:47 +0200101 ->status_is(200)
102 ->content_is('Fake server available');
103
104$t->get_ok('/?q=Baum')
105 ->status_is(200)
106 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
107 ->text_like('#total-results', qr/\d+$/)
108 ->content_like(qr/\"authorized\"\:null/)
109 ->element_exists_not('div.button.top a')
110 ->element_exists_not('aside.active')
111 ->element_exists_not('aside.off')
112 ;
113
114$t->get_ok('/')
115 ->status_is(200)
116 ->element_exists('form[action=/user/login] input[name=handle_or_email]')
117 ->element_exists('aside.active')
118 ->element_exists_not('aside.off')
119 ;
120
121$t->post_ok('/user/login' => form => { handle_or_email => 'test', pwd => 'fail' })
122 ->status_is(302)
123 ->header_is('Location' => '/');
124
125$t->get_ok('/')
126 ->status_is(200)
127 ->element_exists('div.notify-error')
128 ->text_is('div.notify-error', 'Bad CSRF token')
129 ->element_exists('input[name=handle_or_email][value=test]')
130 ->element_exists_not('div.button.top a')
131 ;
132
133$t->post_ok('/user/login' => form => { handle_or_email => 'test', pwd => 'pass' })
134 ->status_is(302)
135 ->header_is('Location' => '/');
136
137my $csrf = $t->get_ok('/')
138 ->status_is(200)
139 ->element_exists('div.notify-error')
140 ->text_is('div.notify-error', 'Bad CSRF token')
141 ->element_exists_not('div.button.top a')
142 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
143 ;
144
145$t->post_ok('/user/login' => form => {
146 handle_or_email => 'test',
147 pwd => 'ldaperr',
148 csrf_token => $csrf
149})
150 ->status_is(302)
151 ->content_is('')
152 ->header_is('Location' => '/');
153
154$csrf = $t->get_ok('/')
155 ->status_is(200)
156 ->element_exists('div.notify-error')
157 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
158 ->element_exists('input[name=handle_or_email][value=test]')
159 ->element_exists_not('div.button.top a')
160 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
161 ;
162
163$t->post_ok('/user/login' => form => {
164 handle_or_email => 'test',
165 pwd => 'unknown',
166 csrf_token => $csrf
167})
168 ->status_is(302)
169 ->content_is('')
170 ->header_is('Location' => '/');
171
172$csrf = $t->get_ok('/')
173 ->status_is(200)
174 ->element_exists('div.notify-error')
Akron8bbbecf2019-07-01 18:57:30 +0200175 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akron33f5c672019-06-24 19:40:47 +0200176 ->element_exists('input[name=handle_or_email][value=test]')
177 ->element_exists_not('div.button.top a')
178 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
179 ;
180
181$t->post_ok('/user/login' => form => {
182 handle_or_email => 'test',
183 pwd => 'pass',
184 csrf_token => $csrf
185})
186 ->status_is(302)
187 ->content_is('')
188 ->header_is('Location' => '/');
189
190$t->get_ok('/')
191 ->status_is(200)
192 ->element_exists_not('div.notify-error')
193 ->element_exists('div.notify-success')
194 ->text_is('div.notify-success', 'Login successful')
195 ->element_exists('aside.off')
196 ->element_exists_not('aside.active')
197 ;
198
Akron33f5c672019-06-24 19:40:47 +0200199# Now the user is logged in and should be able to
200# search with authorization
201$t->get_ok('/?q=Baum')
202 ->status_is(200)
Akron4cefe1f2019-09-04 10:11:28 +0200203 ->session_has('/auth')
204 ->session_is('/auth', 'Bearer ' . $access_token)
205 ->session_is('/auth_r', $refresh_token)
206 ->session_is('/user', 'test')
Akron33f5c672019-06-24 19:40:47 +0200207 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
208 ->text_like('#total-results', qr/\d+$/)
209 ->element_exists_not('div.notify-error')
210 ->content_like(qr/\"authorized\"\:\"yes\"/)
211 ->element_exists('div.button.top a')
212 ->element_exists('div.button.top a.logout[title~="test"]')
213 ;
214
215# Logout
216$t->get_ok('/user/logout')
217 ->status_is(302)
Akron4cefe1f2019-09-04 10:11:28 +0200218 ->session_hasnt('/auth')
219 ->session_hasnt('/auth_r')
220 ->session_hasnt('/user')
Akron33f5c672019-06-24 19:40:47 +0200221 ->header_is('Location' => '/');
222
223$t->get_ok('/')
224 ->status_is(200)
225 ->element_exists_not('div.notify-error')
226 ->element_exists('div.notify-success')
227 ->text_is('div.notify-success', 'Logout successful')
Akron4cefe1f2019-09-04 10:11:28 +0200228 ->element_exists("input[name=handle_or_email]")
229 ->element_exists("input[name=handle_or_email][value=test]")
Akron33f5c672019-06-24 19:40:47 +0200230 ;
231
232$t->get_ok('/?q=Baum')
233 ->status_is(200)
234 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
235 ->text_like('#total-results', qr/\d+$/)
236 ->content_like(qr/\"authorized\"\:null/)
237 ;
238
239# Get redirect
240my $fwd = $t->get_ok('/?q=Baum&ql=poliqarp')
241 ->status_is(200)
242 ->element_exists_not('div.notify-error')
243 ->tx->res->dom->at('input[name=fwd]')->attr('value')
244 ;
245
246is($fwd, '/?q=Baum&ql=poliqarp', 'Redirect is valid');
247
248$t->post_ok('/user/login' => form => {
249 handle_or_email => 'test',
250 pwd => 'pass',
251 csrf_token => $csrf,
252 fwd => 'http://bad.example.com/test'
253})
254 ->status_is(302)
255 ->header_is('Location' => '/');
256
257$t->get_ok('/')
258 ->status_is(200)
259 ->element_exists('div.notify-error')
260 ->element_exists_not('div.notify-success')
261 ->text_is('div.notify-error', 'Redirect failure')
262 ;
263
264$t->post_ok('/user/login' => form => {
265 handle_or_email => 'test',
266 pwd => 'pass',
267 csrf_token => $csrf,
268 fwd => $fwd
269})
270 ->status_is(302)
271 ->header_is('Location' => '/?q=Baum&ql=poliqarp');
272
Akron8bbbecf2019-07-01 18:57:30 +0200273$t->get_ok('/?q=Baum&ql=poliqarp')
274 ->status_is(200)
275 ->element_exists_not('div.notify-error')
276 ->element_exists('div.notify-success')
277 ->text_is('div.notify-success', 'Login successful')
Akroncdfd9d52019-07-23 11:35:00 +0200278 ->session_has('/auth')
279 ->session_is('/auth', 'Bearer ' . $access_token)
280 ->session_is('/auth_r', $refresh_token)
281 ->header_isnt('X-Kalamar-Cache', 'true')
Akron8bbbecf2019-07-01 18:57:30 +0200282 ;
283
Akroncdfd9d52019-07-23 11:35:00 +0200284# Expire the session
285# (makes the token be marked as expired - though it isn't serverside)
286$t->get_ok('/x/expire')
Akron8bbbecf2019-07-01 18:57:30 +0200287 ->status_is(200)
Akroncdfd9d52019-07-23 11:35:00 +0200288 ->content_is('okay')
289 ;
290
291## It may be a problem, but the cache is still valid
292$t->get_ok('/?q=Baum')
293 ->status_is(200)
294 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
295 ->text_like('#total-results', qr/\d+$/)
296 ->content_like(qr/\"authorized\"\:\"yes\"/)
297 ->header_is('X-Kalamar-Cache', 'true')
298 ;
299
300# Query without partial cache (unfortunately) (but no total results)
301$t->get_ok('/?q=baum&cutoff=true')
302 ->status_is(200)
303 ->session_is('/auth', 'Bearer ' . $access_token_2)
304 ->session_is('/auth_r', $refresh_token_2)
305 ->text_is('#error','')
306 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
307 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
308 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
309 ->content_like(qr/\"authorized\"\:\"yes\"/)
310 ->header_isnt('X-Kalamar-Cache', 'true')
311 ->content_like(qr!\"cutOff":true!)
312 ->element_exists_not('#total-results')
313 ;
314
315# Expire the session and remove the refresh option
316$t->get_ok('/x/expire-no-refresh')
317 ->status_is(200)
318 ->content_is('okay')
319 ;
320
321$t->app->defaults(no_cache => 1);
322
323
324$t->get_ok('/x/invalid-no-refresh')
325 ->status_is(200)
326 ->content_is('okay')
327 ;
328
329# Query without cache
330# The token is invalid and can't be refreshed!
331$t->get_ok('/?q=baum&cutoff=true')
332 ->status_is(200)
333 ->session_hasnt('/auth')
334 ->session_hasnt('/auth_r')
335 ->text_is('#error','')
336 ->text_is('div.notify-error','Access token invalid')
337 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
338 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
339 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
340 ->content_unlike(qr/\"authorized\"\:\"yes\"/)
341 ->header_isnt('X-Kalamar-Cache', 'true')
342 ->element_exists('p.no-results')
343 ;
344
345$t->get_ok('/x/invalid')
346 ->status_is(200)
347 ->content_is('okay')
348 ;
349
350# Query without cache
351# The token is invalid and can't be refreshed!
352$t->get_ok('/?q=baum&cutoff=true')
353 ->status_is(200)
354 ->session_is('/auth', 'Bearer ' . $access_token_2)
355 ->session_is('/auth_r', $refresh_token_2)
356 ->text_is('#error','')
357 ->element_exists_not('div.notify-error','Access token invalid')
358 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
359 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
360 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
361 ->content_like(qr/\"authorized\"\:\"yes\"/)
362 ->header_isnt('X-Kalamar-Cache', 'true')
363 ->element_exists_not('p.no-results')
Akron8bbbecf2019-07-01 18:57:30 +0200364 ;
365
Akron33f5c672019-06-24 19:40:47 +0200366
Akroncdfd9d52019-07-23 11:35:00 +0200367$t->get_ok('/x/expired-with-wrong-refresh')
368 ->status_is(200)
369 ->content_is('okay')
370 ;
Akron4796e002019-07-05 10:13:15 +0200371
Akron4796e002019-07-05 10:13:15 +0200372
Akroncdfd9d52019-07-23 11:35:00 +0200373# The token is invalid and can't be refreshed!
374$t->get_ok('/?q=baum&cutoff=true')
375 ->status_is(200)
376 ->session_hasnt('/auth')
377 ->session_hasnt('/auth_r')
378 ->text_is('#error','')
379 ->text_is('div.notify-error','Refresh token is expired')
380 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
381 ->content_unlike(qr/\"authorized\"\:\"yes\"/)
382 ->element_exists('p.no-results')
383 ;
Akron4796e002019-07-05 10:13:15 +0200384
Akron4796e002019-07-05 10:13:15 +0200385
Akron33f5c672019-06-24 19:40:47 +0200386done_testing;
387__END__
388