blob: 7331c817eb452744912a6e730499a892543ded1b [file] [log] [blame]
Akron0e1ed242018-10-11 13:22:00 +02001#!/usr/bin/env perl
2use Mojolicious::Lite;
3use Mojo::ByteStream 'b';
4use Mojo::Date;
5use Mojo::JSON qw/true false encode_json decode_json/;
6use strict;
7use warnings;
Akron6d49c1f2018-10-11 14:22:21 +02008use Mojo::File qw/path/;
9use Mojo::Util qw/slugify/;
Akron0e1ed242018-10-11 13:22:00 +020010
11# This is an API fake server with fixtures
12
13my $secret = 's3cr3t';
Akron73f36082018-10-25 15:34:59 +020014my $fixture_path = path(Mojo::File->new(__FILE__)->dirname)->child('..', 'fixtures');
Akron0e1ed242018-10-11 13:22:00 +020015
Akroncdfd9d52019-07-23 11:35:00 +020016our %tokens = (
Akron59992122019-10-29 11:28:45 +010017 'access_token' => "4dcf8784ccfd26fac9bdb82778fe60e2",
18 'refresh_token' => "hlWci75xb8atDiq3924NUSvOdtAh7Nlf9z",
19 'access_token_2' => "abcde",
Akron83209f72021-01-29 17:54:15 +010020 'access_token_3' => 'jvgjbvjgzucgdwuiKHJK',
Akron59992122019-10-29 11:28:45 +010021 'refresh_token_2' => "fghijk",
22 'new_client_id' => 'fCBbQkA2NDA3MzM1Yw==',
Akronb6b156e2022-03-31 14:57:49 +020023 'new_client_id_2' => 'hghGHhjhFRz_gJhjrd==',
Akron6b75d122022-05-12 17:39:05 +020024 'new_client_id_3' => 'jh0gfjhjbfdsgzjghj==',
Akron59992122019-10-29 11:28:45 +010025 'new_client_secret' => 'KUMaFxs6R1WGud4HM22w3HbmYKHMnNHIiLJ2ihaWtB4N5JxGzZgyqs5GTLutrORj',
Akron83209f72021-01-29 17:54:15 +010026 'auth_token_1' => 'mscajfdghnjdfshtkjcuynxahgz5il'
Akroncdfd9d52019-07-23 11:35:00 +020027);
28
29helper get_token => sub {
30 my ($c, $token) = @_;
31 return $tokens{$token}
32};
33
Akroncdfd9d52019-07-23 11:35:00 +020034# Expiration helper
35helper expired => sub {
36 my ($c, $auth, $set) = @_;
37
Akroncdfd9d52019-07-23 11:35:00 +020038 $auth =~ s/^[^ ]+? //;
39 if ($set) {
40 $c->app->log->debug("Set $auth for expiration");
41 $c->app->defaults('auth_' . $auth => 1);
42 return 1;
43 };
44
45 $c->app->log->debug("Check $auth for expiration: " . (
46 $c->app->defaults('auth_' . $auth) // '0'
47 ));
48
49 return $c->app->defaults('auth_' . $auth);
50};
Akron0e1ed242018-10-11 13:22:00 +020051
Akron408bc7c2022-04-28 15:46:43 +020052
53helper 'add_client' => sub {
54 my $c = shift;
55 my $client = shift;
Akrondb1f4672023-01-24 12:05:07 +010056 my $list = $c->stash('oauth.client_list');
Akron408bc7c2022-04-28 15:46:43 +020057 push @$list, $client;
58};
59
Helge278fbca2022-11-29 18:49:15 +010060# Add plugin to plugin list for marketplace
61helper 'add_plugin' => sub {
62 my $c = shift;
63 my $cplugin = shift;
64 my $pl_list = $c->app->defaults('oauth.plugin_list');
65 push @$pl_list, $cplugin;
66};
Akron408bc7c2022-04-28 15:46:43 +020067
Akron6d49c1f2018-10-11 14:22:21 +020068# Load fixture responses
69helper 'load_response' => sub {
70 my $c = shift;
71 my $q_name = shift;
72 my $file = $fixture_path->child("response_$q_name.json");
Akron8ea84292018-10-24 13:41:52 +020073 $c->app->log->debug("Load response from $file");
74
Akron6d49c1f2018-10-11 14:22:21 +020075 unless (-f $file) {
76 return {
77 status => 500,
78 json => {
79 errors => [[0, 'Unable to load query response from ' . $file]]
80 }
81 }
82 };
Akron8ea84292018-10-24 13:41:52 +020083
Akron6d49c1f2018-10-11 14:22:21 +020084 my $response = $file->slurp;
Akrona3c353c2019-02-14 23:50:00 +010085 my $decode = decode_json($response);
86 unless ($decode) {
87 return {
88 status => 500,
89 json => {
90 errors => [[0, 'Unable to parse JSON']]
91 }
92 }
93 };
94
95 return $decode;
Akron6d49c1f2018-10-11 14:22:21 +020096};
97
Akron1a9d5be2020-03-19 17:28:33 +010098app->defaults('oauth.client_list' => []);
Helge278fbca2022-11-29 18:49:15 +010099app->defaults('oauth.plugin_list' => []);
Akron1a9d5be2020-03-19 17:28:33 +0100100
Akron6d49c1f2018-10-11 14:22:21 +0200101
Akron0e1ed242018-10-11 13:22:00 +0200102# Base page
Akron63d963b2019-07-05 15:35:51 +0200103get '/v1.0/' => sub {
Akron6d49c1f2018-10-11 14:22:21 +0200104 shift->render(text => 'Fake server available');
Akron0e1ed242018-10-11 13:22:00 +0200105};
106
Akron32396632018-10-11 17:08:37 +0200107
Akrond00b4272020-02-05 17:00:33 +0100108get '/v1.0/redirect-target-a' => sub {
109 shift->render(text => 'Redirect Target!');
110} => 'redirect-target';
111
112
113# Base page
114get '/v1.0/redirect' => sub {
115 my $c = shift;
116 $c->res->code(308);
117 $c->res->headers->location($c->url_for('redirect-target')->to_abs);
118 return $c->render(text => '');
119};
120
121
Akron0e1ed242018-10-11 13:22:00 +0200122# Search fixtures
Akron63d963b2019-07-05 15:35:51 +0200123get '/v1.0/search' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200124 my $c = shift;
125 my $v = $c->validation;
126 $v->optional('q');
127 $v->optional('page');
128 $v->optional('ql');
Akroncd42a142019-07-12 18:55:37 +0200129 $v->optional('cq');
Akron0e1ed242018-10-11 13:22:00 +0200130 $v->optional('count');
131 $v->optional('context');
Akron8ea84292018-10-24 13:41:52 +0200132 $v->optional('offset');
Akronc58bfc42020-10-05 12:09:45 +0200133 $v->optional('pipes');
Akron8ea84292018-10-24 13:41:52 +0200134 $v->optional('cutoff')->in(qw/true false/);
Akron0e1ed242018-10-11 13:22:00 +0200135
Akron32396632018-10-11 17:08:37 +0200136 $c->app->log->debug('Receive request');
137
Akron0e1ed242018-10-11 13:22:00 +0200138 # Response q=x&ql=cosmas3
139 if ($v->param('ql') && $v->param('ql') eq 'cosmas3') {
140 return $c->render(
141 status => 400,
142 json => {
143 "\@context" => "http://korap.ids-mannheim.de/ns/koral/0.3/context.jsonld",
144 "errors" => [[307,"cosmas3 is not a supported query language!"]]
145 });
146 };
147
Akron6d49c1f2018-10-11 14:22:21 +0200148 if (!$v->param('q')) {
Akron8ea84292018-10-24 13:41:52 +0200149 return $c->render(%{$c->load_response('query_no_query')});
Akron0e1ed242018-10-11 13:22:00 +0200150 };
151
Akroncce055c2021-07-02 12:18:03 +0200152 if ($v->param('q') eq 'error') {
153 return $c->render(
154 status => 500,
155 inline => '<html><head>ERROR</head></html>'
156 );
157 };
158
Akron8ea84292018-10-24 13:41:52 +0200159 my @slug_base = ($v->param('q'));
160 push @slug_base, 'o' . $v->param('offset') if defined $v->param('offset');
161 push @slug_base, 'c' . $v->param('count') if defined $v->param('count');
162 push @slug_base, 'co' . $v->param('cutoff') if defined $v->param('cutoff');
Akroncd42a142019-07-12 18:55:37 +0200163 push @slug_base, 'cq' if defined $v->param('cq');
Akronc58bfc42020-10-05 12:09:45 +0200164 push @slug_base, 'p' . $v->param('pipes') if defined $v->param('pipes');
Akron8ea84292018-10-24 13:41:52 +0200165
Akron6d49c1f2018-10-11 14:22:21 +0200166 # Get response based on query parameter
Akron8ea84292018-10-24 13:41:52 +0200167 my $response = $c->load_response('query_' . slugify(join('_', @slug_base)));
Akron0e1ed242018-10-11 13:22:00 +0200168
169 # Check authentification
170 if (my $auth = $c->req->headers->header('Authorization')) {
Akron33f5c672019-06-24 19:40:47 +0200171
Akroncdfd9d52019-07-23 11:35:00 +0200172 $c->app->log->debug("There is an authorization header $auth");
Akron33f5c672019-06-24 19:40:47 +0200173 if ($auth =~ /^Bearer/) {
174 # Username unknown in OAuth2
175 $response->{json}->{meta}->{authorized} = 'yes';
Akron0e1ed242018-10-11 13:22:00 +0200176 };
Akroncdfd9d52019-07-23 11:35:00 +0200177
178 # Code is expired
179 if ($c->expired($auth)) {
180
181 $c->app->log->debug("The access token has expired");
182
183 return $c->render(
184 status => 401,
185 json => {
186 errors => [[2003, 'Access token is expired']]
187 }
188 );
189 }
190
191 # Auth token is invalid
192 if ($auth =~ /^Bearer inv4lid/) {
193 $c->app->log->debug("The access token is invalid");
194
195 return $c->render(
196 status => 401,
197 json => {
198 errors => [[2011, 'Access token is invalid']]
199 }
200 );
201 }
Akron0e1ed242018-10-11 13:22:00 +0200202 };
203
Akronc58bfc42020-10-05 12:09:45 +0200204 if ($v->param('pipes')) {
205 $response->{json}->{meta}->{pipes} = $v->param('pipes');
Akron7b9a1962020-07-02 09:52:53 +0200206 };
207
Akron6d49c1f2018-10-11 14:22:21 +0200208 # Set page parameter
Akron0e1ed242018-10-11 13:22:00 +0200209 if ($v->param('page')) {
Akron6d49c1f2018-10-11 14:22:21 +0200210 $response->{json}->{meta}->{startIndex} = $v->param("startIndex");
Akron0e1ed242018-10-11 13:22:00 +0200211 };
212
Akron0e1ed242018-10-11 13:22:00 +0200213 # Simple search fixture
Akron32396632018-10-11 17:08:37 +0200214 $c->render(%$response);
215
216 $c->app->log->debug('Rendered result');
217
218 return 1;
Akron0e1ed242018-10-11 13:22:00 +0200219};
220
Akron80a84b22018-10-24 17:44:24 +0200221# Textinfo fixtures
Akron63d963b2019-07-05 15:35:51 +0200222get '/v1.0/corpus/:corpusId/:docId/:textId' => sub {
Akron80a84b22018-10-24 17:44:24 +0200223 my $c = shift;
224
225 my $file = join('_', (
226 'textinfo',
227 $c->stash('corpusId'),
228 $c->stash('docId'),
229 $c->stash('textId')
230 ));
231
232 my $slug = slugify($file);
233
234 # Get response based on query parameter
235 my $response = $c->load_response($slug);
236 return $c->render(%$response);
237};
238
Akron0e1ed242018-10-11 13:22:00 +0200239
Akronb80341d2018-10-15 19:46:23 +0200240# Matchinfo fixtures
Akron63d963b2019-07-05 15:35:51 +0200241get '/v1.0/corpus/:corpusId/:docId/:textId/:matchId/matchInfo' => sub {
Akronb80341d2018-10-15 19:46:23 +0200242 my $c = shift;
243
244 my $file = join('_', (
245 'matchinfo',
246 $c->stash('corpusId'),
247 $c->stash('docId'),
248 $c->stash('textId'),
249 $c->stash('matchId')
250 ));
251
Akronb8d0b402018-10-18 23:51:52 +0200252 my $slug = slugify($file);
253
Akronb80341d2018-10-15 19:46:23 +0200254 # Get response based on query parameter
Akronb8d0b402018-10-18 23:51:52 +0200255 my $response = $c->load_response($slug);
Akronb80341d2018-10-15 19:46:23 +0200256 return $c->render(%$response);
257};
258
Akron0e1ed242018-10-11 13:22:00 +0200259
Akronbe61f4c2018-10-20 00:52:58 +0200260# Statistics endpoint
Akron63d963b2019-07-05 15:35:51 +0200261get '/v1.0/statistics' => sub {
Akronbe61f4c2018-10-20 00:52:58 +0200262 my $c = shift;
263 my $v = $c->validation;
Akron5fa61e92019-07-15 11:56:11 +0200264 $v->optional('cq');
Akronbe61f4c2018-10-20 00:52:58 +0200265
266 my @list = 'corpusinfo';
Akron5fa61e92019-07-15 11:56:11 +0200267 if ($v->param('cq')) {
268 push @list, $v->param('cq');
Akronbe61f4c2018-10-20 00:52:58 +0200269 };
270 my $slug = slugify(join('_', @list));
271
272 # Get response based on query parameter
273 my $response = $c->load_response($slug);
274 return $c->render(%$response);
275};
276
Akron0e1ed242018-10-11 13:22:00 +0200277############
278# Auth API #
279############
280
281# Request API token
Akron63d963b2019-07-05 15:35:51 +0200282get '/v1.0/auth/logout' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200283 my $c = shift;
284
285 if (my $auth = $c->req->headers->header('Authorization')) {
Akroncdfd9d52019-07-23 11:35:00 +0200286
287 if ($auth =~ /^Bearer/) {
288 $c->app->log->debug('Server-Logout: ' . $auth);
289 return $c->render(json => { msg => [[0, 'Fine!']]});
Akron0e1ed242018-10-11 13:22:00 +0200290 };
291 };
292
293 return $c->render(status => 400, json => { error => [[0, 'No!']]});
294};
295
296
297# Request API token
Akron63d963b2019-07-05 15:35:51 +0200298get '/v1.0/auth/apiToken' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200299 my $c = shift;
300
301 # Get auth header
302 my $auth = $c->req->headers->authorization;
303
304 # Authorization missing or not basic
305 if (!$auth || $auth !~ s/\s*Basic\s+//gi) {
306 return $c->render(
307 json => {
308 error => [[2, 'x']]
309 }
310 );
311 };
312
313 # Decode header
314 my ($username, $pwd) = @{b($auth)->b64_decode->split(':')->to_array};
315
316 # the password is 'pass'
317 if ($pwd) {
Akrona205b142022-11-28 13:35:19 +0100318 if ($pwd eq 'ldaperr') {
Akron3d673062019-01-29 15:54:16 +0100319 return $c->render(
320 format => 'html',
321 status => 401,
322 json => {
323 "errors" => [[2022,"LDAP Authentication failed due to unknown user or password!"]]
324 }
325 );
Akron0e1ed242018-10-11 13:22:00 +0200326 };
327
328 return $c->render(
329 json => {
330 error => [[2004, undef]]
331 }
332 );
333 };
334
335 return $c->render(
336 json => {
337 error => [[2004, undef]]
338 }
339 );
340};
341
Akron33f5c672019-06-24 19:40:47 +0200342
343# Request API token
Akron63d963b2019-07-05 15:35:51 +0200344post '/v1.0/oauth2/token' => sub {
Akron33f5c672019-06-24 19:40:47 +0200345 my $c = shift;
346
Akron63d963b2019-07-05 15:35:51 +0200347 my $grant_type = $c->param('grant_type') // 'undefined';
348
349 if ($grant_type eq 'password') {
Akron33f5c672019-06-24 19:40:47 +0200350
Akron8bbbecf2019-07-01 18:57:30 +0200351 # Check for wrong client id
352 if ($c->param('client_id') ne '2') {
353 return $c->render(
354 json => {
355 "error_description" => "Unknown client with " . $_->{client_id},
356 "error" => "invalid_client"
357 },
358 status => 401
359 );
360 }
Akron33f5c672019-06-24 19:40:47 +0200361
Akron8bbbecf2019-07-01 18:57:30 +0200362 # Check for wrong client secret
363 elsif ($c->param('client_secret') ne 'k414m4r-s3cr3t') {
364 return $c->render(
365 json => {
366 "error_description" => "Invalid client credentials",
367 "error" => "invalid_client"
368 },
369 status => 401
370 );
371 }
Akron33f5c672019-06-24 19:40:47 +0200372
Akron8bbbecf2019-07-01 18:57:30 +0200373 # Check for wrong user name
Akron6a228db2021-10-14 15:57:00 +0200374 elsif ($c->param('username') !~ /^t.st$/) {
Akron8bbbecf2019-07-01 18:57:30 +0200375 return $c->render(json => {
376 error => [[2004, undef]]
377 });
378 }
379
380 # Check for ldap error
381 elsif ($c->param('password') eq 'ldaperr') {
382 return $c->render(
383 format => 'html',
384 status => 401,
385 json => {
386 "errors" => [
387 [
388 2022,
389 "LDAP Authentication failed due to unknown user or password!"
390 ]
391 ]
392 }
393 );
394 }
395
396 # Check for wrong password
397 elsif ($c->param('password') ne 'pass') {
398 return $c->render(json => {
399 format => 'html',
400 status => 401,
Akron33f5c672019-06-24 19:40:47 +0200401 "errors" => [[2022,"LDAP Authentication failed due to unknown user or password!"]]
Akron8bbbecf2019-07-01 18:57:30 +0200402 });
403 }
404
405 # Return fine access
406 return $c->render(
407 json => {
Akroncdfd9d52019-07-23 11:35:00 +0200408 "access_token" => $c->get_token('access_token'),
409 "refresh_token" => $c->get_token('refresh_token'),
Akron8bbbecf2019-07-01 18:57:30 +0200410 "scope" => "all",
411 "token_type" => "Bearer",
412 "expires_in" => 86400
413 });
414 }
415
416 # Refresh token
Akron63d963b2019-07-05 15:35:51 +0200417 elsif ($grant_type eq 'refresh_token') {
Akroncdfd9d52019-07-23 11:35:00 +0200418
419 if ($c->param('refresh_token') eq 'inv4lid') {
420 return $c->render(
421 status => 400,
422 json => {
423 "error_description" => "Refresh token is expired",
424 "error" => "invalid_grant"
425 }
426 );
427 };
428
429 $c->app->log->debug("Refresh the token in the mock server!");
430
Akron8bbbecf2019-07-01 18:57:30 +0200431 return $c->render(
432 status => 200,
433 json => {
Akroncdfd9d52019-07-23 11:35:00 +0200434 "access_token" => $c->get_token("access_token_2"),
435 "refresh_token" => $c->get_token("refresh_token_2"),
Akron8bbbecf2019-07-01 18:57:30 +0200436 "token_type" => "Bearer",
437 "expires_in" => 86400
Akron33f5c672019-06-24 19:40:47 +0200438 }
439 );
440 }
441
Akron83209f72021-01-29 17:54:15 +0100442 # Get auth_token_1
443 elsif ($grant_type eq 'authorization_code') {
Akrone3daaeb2023-05-08 09:44:18 +0200444 if ($c->param('code') && $c->param('code') eq $tokens{auth_token_1}) {
Akron83209f72021-01-29 17:54:15 +0100445 return $c->render(
446 status => 200,
447 json => {
448 "access_token" => $tokens{access_token_3},
449 "expires_in" => 31536000,
450 "scope" => 'match_info search openid',
451 "token_type" => "Bearer"
452 }
453 );
454 };
455 }
456
Akron8bbbecf2019-07-01 18:57:30 +0200457 # Unknown token grant
458 else {
459 return $c->render(
Akron63d963b2019-07-05 15:35:51 +0200460 status => 400,
Akron8bbbecf2019-07-01 18:57:30 +0200461 json => {
462 "errors" => [
463 [
Akron63d963b2019-07-05 15:35:51 +0200464 0, "Grant Type unknown", $grant_type
Akron8bbbecf2019-07-01 18:57:30 +0200465 ]
466 ]
467 }
468 )
Akron33f5c672019-06-24 19:40:47 +0200469 }
Akron33f5c672019-06-24 19:40:47 +0200470};
471
Akron4cefe1f2019-09-04 10:11:28 +0200472# Revoke API token
473post '/v1.0/oauth2/revoke' => sub {
474 my $c = shift;
475
476 my $refresh_token = $c->param('token');
477
478 if ($c->param('client_secret') ne 'k414m4r-s3cr3t') {
479 return $c->render(
480 json => {
481 "error_description" => "Invalid client credentials",
482 "error" => "invalid_client"
483 },
484 status => 401
485 );
486 };
487
488 return $c->render(
489 text => ''
490 )
491};
Akron33f5c672019-06-24 19:40:47 +0200492
Akron59992122019-10-29 11:28:45 +0100493# Register a client
494post '/v1.0/oauth2/client/register' => sub {
495 my $c = shift;
496 my $json = $c->req->json;
497
Akrondc50c892021-05-05 18:12:02 +0200498 if ($json->{redirectURI}) {
499 return $c->render(
500 status => 400,
501 json => {
502 errors => [
503 [
504 201,
505 "Unrecognized field \"redirectURI\" (class de.ids_mannheim.korap.web.input.OAuth2ClientJson), not marked as ignorable (5 known properties: \"redirect_uri\", \"type\", \"name\", \"description\", \"url\"])\n at [Source: (org.eclipse.jetty.server.HttpInputOverHTTP); line: 1, column: 94] (through reference chain: de.ids_mannheim.korap.web.input.OAuth2ClientJson[\"redirectURI\"])"
506 ]
507 ]
508 }
509 );
510 };
511
Akron59992122019-10-29 11:28:45 +0100512 my $name = $json->{name};
Akron1a9d5be2020-03-19 17:28:33 +0100513 my $desc = $json->{description};
Akron59992122019-10-29 11:28:45 +0100514 my $type = $json->{type};
515 my $url = $json->{url};
Akron9f2ad342022-05-04 16:16:40 +0200516 my $src = $json->{source};
Akronb6b156e2022-03-31 14:57:49 +0200517 my $redirect_uri = $json->{redirect_uri};
Akron59992122019-10-29 11:28:45 +0100518
Akron1a9d5be2020-03-19 17:28:33 +0100519 my $list = $c->app->defaults('oauth.client_list');
520
Akron6b75d122022-05-12 17:39:05 +0200521 my $obj = {
Akrondc50c892021-05-05 18:12:02 +0200522 "client_id" => $tokens{new_client_id},
523 "client_name" => $name,
Akronbc94a9c2021-04-15 00:07:35 +0200524 "client_description" => $desc,
Akronb6b156e2022-03-31 14:57:49 +0200525 "client_url" => $url,
Akron9f2ad342022-05-04 16:16:40 +0200526 "client_redirect_uri" => $redirect_uri,
Akron6b75d122022-05-12 17:39:05 +0200527 "client_type" => $type
Akronb6b156e2022-03-31 14:57:49 +0200528 };
529
Akron6b75d122022-05-12 17:39:05 +0200530 # Plugin!
531 if ($src) {
532 $obj->{source} = $src;
533 $obj->{client_id} = $tokens{new_client_id_3};
534 };
535
536 push @$list, $obj;
537
Akronb6b156e2022-03-31 14:57:49 +0200538 if ($redirect_uri && $redirect_uri =~ /FAIL$/) {
539 return $c->render(
540 status => 400,
541 json => {
542 "error_description" => $redirect_uri . " is invalid.",
543 "error" => "invalid_request"
544 }
545 )
Akron1a9d5be2020-03-19 17:28:33 +0100546 };
547
Akron59992122019-10-29 11:28:45 +0100548 # Confidential server application
549 if ($type eq 'CONFIDENTIAL') {
Akronb6b156e2022-03-31 14:57:49 +0200550
Akron59992122019-10-29 11:28:45 +0100551 return $c->render(json => {
Akronb6b156e2022-03-31 14:57:49 +0200552 client_id => $tokens{new_client_id_2},
Akron59992122019-10-29 11:28:45 +0100553 client_secret => $tokens{new_client_secret}
554 });
555 };
556
557 # Desktop application
558 return $c->render(json => {
559 client_id => $tokens{new_client_id}
560 });
561};
562
Helge278fbca2022-11-29 18:49:15 +0100563# List plugins
564post '/v1.0/plugins' => sub {
Akron0f1b93b2020-03-17 11:37:19 +0100565 my $c = shift;
566
Akron276afc02021-06-14 11:00:21 +0200567 my $v = $c->validation;
568
569 $v->required('super_client_id');
570 $v->required('super_client_secret');
571
572 if ($v->has_error) {
573 return $c->render(
574 json => [],
575 status => 400
576 );
577 };
Helge278fbca2022-11-29 18:49:15 +0100578
579 my $p;
580 if($c->param("permitted_only")){
581 $p = $c->param("permitted_only");
582 }
583 else{
584 $p="false";
585 }
586
587 #Mocks the return only of permitted plugins
588 if($p eq "true"){
589 my @p_plugin_list = grep{$_->{permitted} eq "true"} @{$c->stash('oauth.plugin_list')};
590 my $listref = \@p_plugin_list;
591 return $c->render(
592 json => $listref,
593 status => 200
594 );
595 }
596 else{
597 return $c->render(
598 json => $c->stash('oauth.plugin_list'),
599 status => 200
600 );
601 }
602
603};
604
605# Register a client
606post '/v1.0/oauth2/client/list' => sub {
607 my $c = shift;
608
609 my $v = $c->validation;
610 $v->required('super_client_id');
611 $v->required('super_client_secret');
612
613 if ($v->has_error) {
614 return $c->render(
615 json => [],
616 status => 400
617 );
618 };
619
Akron276afc02021-06-14 11:00:21 +0200620
Akron0f1b93b2020-03-17 11:37:19 +0100621 # $c->param('client_secret');
Akron1a9d5be2020-03-19 17:28:33 +0100622
623 # Is empty [] when nothing registered
624
Akron0f1b93b2020-03-17 11:37:19 +0100625 return $c->render(
Akron1a9d5be2020-03-19 17:28:33 +0100626 json => $c->stash('oauth.client_list'),
627 status => 200
628 );
629};
630
Akrondb1f4672023-01-24 12:05:07 +0100631# Get client info
632post '/v1.0/oauth2/client/:client_id' => sub {
633 my $c = shift;
634
635 # Validate input
636 my $v = $c->validation;
637 $v->required('super_client_id');
638 $v->required('super_client_secret');
639
640 if ($v->has_error) {
641 return $c->render(
642 status => 400,
643 json => {
644 error_description => "No super client",
645 error => "no_superclient"
646 }
647 );
648 };
649
650 my $client_id = $c->stash('client_id');
651
652 my $list = $c->stash('oauth.client_list');
653
654 foreach (@$list) {
655 if ($_->{client_id} eq $client_id) {
656 return $c->render(
657 json => $_,
658 status => 200
659 );
660 };
661 };
662
663 return $c->render(
664 json => {
665 error_description => "Unknown client with $client_id.",
666 error => "invalid_client"
667 },
668 status => 401
669 );
670};
671
Akronbc94a9c2021-04-15 00:07:35 +0200672
673# Get token list
674post '/v1.0/oauth2/token/list' => sub {
675 my $c = shift;
676 return $c->render(json => [
677 {
678 "client_description" => "Nur ein Beispiel",
679 "client_id" => $tokens{new_client_id},
680 "client_name" => "Beispiel",
681 "client_url" => "",
682 "created_date" => "2021-04-14T19:40:26.742+02:00[Europe\/Berlin]",
683 "expires_in" => "31533851",
684 "scope" => [
685 "match_info",
686 "search",
687 "openid"
688 ],
689 "token" => "jhkhkjhk_hjgjsfz67i",
690 "user_authentication_time" => "2021-04-14T19:39:41.81+02:00[Europe\/Berlin]"
691 }
692 ]);
693};
694
Akron1a9d5be2020-03-19 17:28:33 +0100695del '/v1.0/oauth2/client/deregister/:client_id' => sub {
696 my $c = shift;
697 my $client_id = $c->stash('client_id');
698
699 my $list = $c->app->defaults('oauth.client_list');
700
701 my $break = -1;
702 for (my $i = 0; $i < @$list; $i++) {
Akrondc50c892021-05-05 18:12:02 +0200703 if ($list->[$i]->{client_id} eq $client_id) {
Akron1a9d5be2020-03-19 17:28:33 +0100704 $break = $i;
705 last;
706 };
707 };
708
709 if ($break != -1) {
710 splice @$list, $break, 1;
711 }
712
713 else {
714 return $c->render(
715 json => {
716 error_description => "Unknown client with $client_id.",
717 error => "invalid_client"
Akron0f1b93b2020-03-17 11:37:19 +0100718 },
Akron1a9d5be2020-03-19 17:28:33 +0100719 status => 401
720 );
721 };
722
723 return $c->render(
724 json => $c->stash('oauth.client_list'),
Akron0f1b93b2020-03-17 11:37:19 +0100725 status => 200
726 );
727};
728
Akron83209f72021-01-29 17:54:15 +0100729post '/v1.0/oauth2/authorize' => sub {
730 my $c = shift;
731 my $type = $c->param('response_type');
732 my $client_id = $c->param('client_id');
Akrona8efaa92022-04-09 14:45:43 +0200733 my $scope = $c->param('scope');
734 my $state = $c->param('state');
735 my $redirect_uri = $c->param('redirect_uri') // 'NO';
Akron83209f72021-01-29 17:54:15 +0100736
Akrona8efaa92022-04-09 14:45:43 +0200737 if ($type eq 'code' && $client_id eq 'xyz') {
738
739 if ($state eq 'fail') {
740 $c->res->headers->location(
741 Mojo::URL->new($redirect_uri)->query({
742 error_description => 'FAIL'
743 })
744 );
745 $c->res->code(400);
746 return $c->rendered;
747 };
748
Akron9ccf69a2023-01-31 14:21:37 +0100749 if (index($redirect_uri,'http://wrong') >= 0) {
750 return $c->render(
751 code => 400,
752 content_type => 'text/plain',
753 text => '{"error_description":"Invalid redirect URI","state":"ZMwDGTZ2RY","error":"invalid_request"}'
754 );
755 };
756
Akrona8efaa92022-04-09 14:45:43 +0200757 return $c->redirect_to(
758 Mojo::URL->new($redirect_uri)->query({
759 code => $tokens{auth_token_1},
760 scope => $scope,
761 })
762 );
763 }
764
765 elsif ($type eq 'code') {
Akrone3daaeb2023-05-08 09:44:18 +0200766 my $loc = Mojo::URL->new($redirect_uri)->query({
767 code => $tokens{auth_token_1},
768 scope => 'match_info search openid'
769 });
Akron83209f72021-01-29 17:54:15 +0100770
Akrone3daaeb2023-05-08 09:44:18 +0200771 my $res = $c->res;
772 $res->headers->location($loc);
773 return $c->rendered($client_id eq '307' ? 307 : 302);
774 # return $c->rendered(302);
Akron9ccf69a2023-01-31 14:21:37 +0100775 };
776
777 return $c->render(
778 code => 400,
779 content_type => 'text/plain',
780 content => 'Unknown'
781 );
Akron83209f72021-01-29 17:54:15 +0100782};
783
Akron0f1b93b2020-03-17 11:37:19 +0100784
Akronabdf9a92021-01-12 19:06:57 +0100785#######################
786# Query Reference API #
787#######################
788
789use CHI;
790my $chi = CHI->new(
791 driver => 'Memory',
792 global => 1
793);
794
795# Store query
796put '/v1.0/query/~:user/:query_name' => sub {
797 my $c = shift;
798 my $user = $c->stash('user');
799 my $qname = $c->stash('query_name');
800
801 if ($chi->is_valid($qname)) {
802 return $c->render(
803 json => {
804 errors => [
805 {
806 message => 'Unable to store query reference'
807 }
808 ]
809 }, status => 400
810 );
811 };
812
813 my $json = $c->req->json;
814
815 my $store = {
816 name => $qname,
817 koralQuery => { '@type' => 'Okay' },
818 query => $json->{query},
819 queryType => $json->{queryType},
820 type => $json->{type},
821 queryLanguage => $json->{queryLanguage},
822 };
823
824 if (exists $json->{description}) {
825 $store->{description} = $json->{description}
826 };
827
828 # Set query reference
829 $chi->set($qname => $store);
830
831 my $queries = $chi->get('~queries') // [];
832 push @$queries, $qname;
833 $chi->set('~queries' => $queries);
834
835 return $c->render(
836 status => 201,
837 text => ''
838 );
839};
840
841# Get query
842get '/v1.0/query/~:user/:query_name' => sub {
843 my $c = shift;
844
845 my $user = $c->stash('user');
846 my $qname = $c->stash('query_name');
847
848 my $json = $chi->get($qname);
849
850 if ($json) {
851 return $c->render(
852 json => $json
853 );
854 };
855
856 return $c->render(
857 json => {
858 errors => [
859 {
860 message => 'Query reference not found'
861 }
862 ]
863 }, status => 404
864 );
865};
866
867
868# Get all queries
869get '/v1.0/query/~:user' => sub {
870 my $c = shift;
871 my $user = $c->stash('user');
872 my $qs = $chi->get('~queries') // [];
873 my @queries = ();
874 foreach (@$qs) {
875 push @queries, $chi->get($_);
876 };
877 return $c->render(json => { refs => \@queries });
878};
879
880
881# Store query
882del '/v1.0/query/~:user/:query_name' => sub {
883 my $c = shift;
884 my $user = $c->stash('user');
885 my $qname = $c->stash('query_name');
886
887 $chi->remove($qname);
888
889 my $queries = $chi->get('~queries') // [];
890
891 my @clean = ();
892 foreach (@$queries) {
893 push @clean, $_ unless $_ eq $qname
894 };
895
896 $chi->set('~queries' => \@clean);
897
898 return $c->render(
899 status => 200,
900 text => ''
901 );
902};
903
Akronc1aaf932021-06-09 12:19:15 +0200904post '/v1.0/oauth2/revoke/super' => sub {
905 my $c = shift;
906
907 my $s_client_id = $c->param('super_client_id');
908 my $s_client_secret = $c->param('super_client_secret');
909 my $token = $c->param('token');
910
911 return $c->render(text => 'SUCCESS');
912};
913
Akrona8efaa92022-04-09 14:45:43 +0200914get '/fakeclient/return' => sub {
915 my $c = shift;
916 $c->render(
917 text => 'welcome back! [' . $c->param('code') . ']'
918 );
919} => 'return_uri';
920
Akron0f1b93b2020-03-17 11:37:19 +0100921
Akron0e1ed242018-10-11 13:22:00 +0200922app->start;
923
924
925__END__
926
927
928 # Temporary:
929 my $collection_query = {
930 '@type' => "koral:docGroup",
931 "operation" => "operation:or",
932 "operands" => [
933 {
934 '@type' => "koral:docGroup",
935 "operation" => "operation:and",
936 "operands" => [
937 {
938 '@type' => "koral:doc",
939 "key" => "title",
940 "match" => "match:eq",
941 "value" => "Der Birnbaum",
942 "type" => "type:string"
943 },
944 {
945 '@type' => "koral:doc",
946 "key" => "pubPlace",
947 "match" => "match:eq",
948 "value" => "Mannheim",
949 "type" => "type:string"
950 },
951 {
952 '@type' => "koral:docGroup",
953 "operation" => "operation:or",
954 "operands" => [
955 {
956 '@type' => "koral:doc",
957 "key" => "subTitle",
958 "match" => "match:eq",
959 "value" => "Aufzucht oder Pflege",
960 "type" => "type:string"
961 },
962 {
963 '@type' => "koral:doc",
964 "key" => "subTitle",
965 "match" => "match:eq",
966 "value" => "Gedichte",
967 "type" => "type:string"
968 }
969 ]
970 }
971 ]
972 },
973 {
974 '@type' => "koral:doc",
975 "key" => "pubDate",
976 "match" => "match:geq",
977 "value" => "2015-03-05",
978 "type" => "type:date"
979 }
980 ]
981 };