blob: ab0c34d1c48538ebc034cabe3775e855e30482bf [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
60
Akron6d49c1f2018-10-11 14:22:21 +020061# Load fixture responses
62helper 'load_response' => sub {
63 my $c = shift;
64 my $q_name = shift;
65 my $file = $fixture_path->child("response_$q_name.json");
Akron8ea84292018-10-24 13:41:52 +020066 $c->app->log->debug("Load response from $file");
67
Akron6d49c1f2018-10-11 14:22:21 +020068 unless (-f $file) {
69 return {
70 status => 500,
71 json => {
72 errors => [[0, 'Unable to load query response from ' . $file]]
73 }
74 }
75 };
Akron8ea84292018-10-24 13:41:52 +020076
Akron6d49c1f2018-10-11 14:22:21 +020077 my $response = $file->slurp;
Akrona3c353c2019-02-14 23:50:00 +010078 my $decode = decode_json($response);
79 unless ($decode) {
80 return {
81 status => 500,
82 json => {
83 errors => [[0, 'Unable to parse JSON']]
84 }
85 }
86 };
87
88 return $decode;
Akron6d49c1f2018-10-11 14:22:21 +020089};
90
Akron1a9d5be2020-03-19 17:28:33 +010091app->defaults('oauth.client_list' => []);
92
Akron6d49c1f2018-10-11 14:22:21 +020093
Akron0e1ed242018-10-11 13:22:00 +020094# Base page
Akron63d963b2019-07-05 15:35:51 +020095get '/v1.0/' => sub {
Akron6d49c1f2018-10-11 14:22:21 +020096 shift->render(text => 'Fake server available');
Akron0e1ed242018-10-11 13:22:00 +020097};
98
Akron32396632018-10-11 17:08:37 +020099
Akrond00b4272020-02-05 17:00:33 +0100100get '/v1.0/redirect-target-a' => sub {
101 shift->render(text => 'Redirect Target!');
102} => 'redirect-target';
103
104
105# Base page
106get '/v1.0/redirect' => sub {
107 my $c = shift;
108 $c->res->code(308);
109 $c->res->headers->location($c->url_for('redirect-target')->to_abs);
110 return $c->render(text => '');
111};
112
113
Akron0e1ed242018-10-11 13:22:00 +0200114# Search fixtures
Akron63d963b2019-07-05 15:35:51 +0200115get '/v1.0/search' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200116 my $c = shift;
117 my $v = $c->validation;
118 $v->optional('q');
119 $v->optional('page');
120 $v->optional('ql');
Akroncd42a142019-07-12 18:55:37 +0200121 $v->optional('cq');
Akron0e1ed242018-10-11 13:22:00 +0200122 $v->optional('count');
123 $v->optional('context');
Akron8ea84292018-10-24 13:41:52 +0200124 $v->optional('offset');
Akronc58bfc42020-10-05 12:09:45 +0200125 $v->optional('pipes');
Akron8ea84292018-10-24 13:41:52 +0200126 $v->optional('cutoff')->in(qw/true false/);
Akron0e1ed242018-10-11 13:22:00 +0200127
Akron32396632018-10-11 17:08:37 +0200128 $c->app->log->debug('Receive request');
129
Akron0e1ed242018-10-11 13:22:00 +0200130 # Response q=x&ql=cosmas3
131 if ($v->param('ql') && $v->param('ql') eq 'cosmas3') {
132 return $c->render(
133 status => 400,
134 json => {
135 "\@context" => "http://korap.ids-mannheim.de/ns/koral/0.3/context.jsonld",
136 "errors" => [[307,"cosmas3 is not a supported query language!"]]
137 });
138 };
139
Akron6d49c1f2018-10-11 14:22:21 +0200140 if (!$v->param('q')) {
Akron8ea84292018-10-24 13:41:52 +0200141 return $c->render(%{$c->load_response('query_no_query')});
Akron0e1ed242018-10-11 13:22:00 +0200142 };
143
Akroncce055c2021-07-02 12:18:03 +0200144 if ($v->param('q') eq 'error') {
145 return $c->render(
146 status => 500,
147 inline => '<html><head>ERROR</head></html>'
148 );
149 };
150
Akron8ea84292018-10-24 13:41:52 +0200151 my @slug_base = ($v->param('q'));
152 push @slug_base, 'o' . $v->param('offset') if defined $v->param('offset');
153 push @slug_base, 'c' . $v->param('count') if defined $v->param('count');
154 push @slug_base, 'co' . $v->param('cutoff') if defined $v->param('cutoff');
Akroncd42a142019-07-12 18:55:37 +0200155 push @slug_base, 'cq' if defined $v->param('cq');
Akronc58bfc42020-10-05 12:09:45 +0200156 push @slug_base, 'p' . $v->param('pipes') if defined $v->param('pipes');
Akron8ea84292018-10-24 13:41:52 +0200157
Akron6d49c1f2018-10-11 14:22:21 +0200158 # Get response based on query parameter
Akron8ea84292018-10-24 13:41:52 +0200159 my $response = $c->load_response('query_' . slugify(join('_', @slug_base)));
Akron0e1ed242018-10-11 13:22:00 +0200160
161 # Check authentification
162 if (my $auth = $c->req->headers->header('Authorization')) {
Akron33f5c672019-06-24 19:40:47 +0200163
Akroncdfd9d52019-07-23 11:35:00 +0200164 $c->app->log->debug("There is an authorization header $auth");
Akron33f5c672019-06-24 19:40:47 +0200165 if ($auth =~ /^Bearer/) {
166 # Username unknown in OAuth2
167 $response->{json}->{meta}->{authorized} = 'yes';
Akron0e1ed242018-10-11 13:22:00 +0200168 };
Akroncdfd9d52019-07-23 11:35:00 +0200169
170 # Code is expired
171 if ($c->expired($auth)) {
172
173 $c->app->log->debug("The access token has expired");
174
175 return $c->render(
176 status => 401,
177 json => {
178 errors => [[2003, 'Access token is expired']]
179 }
180 );
181 }
182
183 # Auth token is invalid
184 if ($auth =~ /^Bearer inv4lid/) {
185 $c->app->log->debug("The access token is invalid");
186
187 return $c->render(
188 status => 401,
189 json => {
190 errors => [[2011, 'Access token is invalid']]
191 }
192 );
193 }
Akron0e1ed242018-10-11 13:22:00 +0200194 };
195
Akronc58bfc42020-10-05 12:09:45 +0200196 if ($v->param('pipes')) {
197 $response->{json}->{meta}->{pipes} = $v->param('pipes');
Akron7b9a1962020-07-02 09:52:53 +0200198 };
199
Akron6d49c1f2018-10-11 14:22:21 +0200200 # Set page parameter
Akron0e1ed242018-10-11 13:22:00 +0200201 if ($v->param('page')) {
Akron6d49c1f2018-10-11 14:22:21 +0200202 $response->{json}->{meta}->{startIndex} = $v->param("startIndex");
Akron0e1ed242018-10-11 13:22:00 +0200203 };
204
Akron0e1ed242018-10-11 13:22:00 +0200205 # Simple search fixture
Akron32396632018-10-11 17:08:37 +0200206 $c->render(%$response);
207
208 $c->app->log->debug('Rendered result');
209
210 return 1;
Akron0e1ed242018-10-11 13:22:00 +0200211};
212
Akron80a84b22018-10-24 17:44:24 +0200213# Textinfo fixtures
Akron63d963b2019-07-05 15:35:51 +0200214get '/v1.0/corpus/:corpusId/:docId/:textId' => sub {
Akron80a84b22018-10-24 17:44:24 +0200215 my $c = shift;
216
217 my $file = join('_', (
218 'textinfo',
219 $c->stash('corpusId'),
220 $c->stash('docId'),
221 $c->stash('textId')
222 ));
223
224 my $slug = slugify($file);
225
226 # Get response based on query parameter
227 my $response = $c->load_response($slug);
228 return $c->render(%$response);
229};
230
Akron0e1ed242018-10-11 13:22:00 +0200231
Akronb80341d2018-10-15 19:46:23 +0200232# Matchinfo fixtures
Akron63d963b2019-07-05 15:35:51 +0200233get '/v1.0/corpus/:corpusId/:docId/:textId/:matchId/matchInfo' => sub {
Akronb80341d2018-10-15 19:46:23 +0200234 my $c = shift;
235
236 my $file = join('_', (
237 'matchinfo',
238 $c->stash('corpusId'),
239 $c->stash('docId'),
240 $c->stash('textId'),
241 $c->stash('matchId')
242 ));
243
Akronb8d0b402018-10-18 23:51:52 +0200244 my $slug = slugify($file);
245
Akronb80341d2018-10-15 19:46:23 +0200246 # Get response based on query parameter
Akronb8d0b402018-10-18 23:51:52 +0200247 my $response = $c->load_response($slug);
Akronb80341d2018-10-15 19:46:23 +0200248 return $c->render(%$response);
249};
250
Akron0e1ed242018-10-11 13:22:00 +0200251
Akronbe61f4c2018-10-20 00:52:58 +0200252# Statistics endpoint
Akron63d963b2019-07-05 15:35:51 +0200253get '/v1.0/statistics' => sub {
Akronbe61f4c2018-10-20 00:52:58 +0200254 my $c = shift;
255 my $v = $c->validation;
Akron5fa61e92019-07-15 11:56:11 +0200256 $v->optional('cq');
Akronbe61f4c2018-10-20 00:52:58 +0200257
258 my @list = 'corpusinfo';
Akron5fa61e92019-07-15 11:56:11 +0200259 if ($v->param('cq')) {
260 push @list, $v->param('cq');
Akronbe61f4c2018-10-20 00:52:58 +0200261 };
262 my $slug = slugify(join('_', @list));
263
264 # Get response based on query parameter
265 my $response = $c->load_response($slug);
266 return $c->render(%$response);
267};
268
Akron0e1ed242018-10-11 13:22:00 +0200269############
270# Auth API #
271############
272
273# Request API token
Akron63d963b2019-07-05 15:35:51 +0200274get '/v1.0/auth/logout' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200275 my $c = shift;
276
277 if (my $auth = $c->req->headers->header('Authorization')) {
Akroncdfd9d52019-07-23 11:35:00 +0200278
279 if ($auth =~ /^Bearer/) {
280 $c->app->log->debug('Server-Logout: ' . $auth);
281 return $c->render(json => { msg => [[0, 'Fine!']]});
Akron0e1ed242018-10-11 13:22:00 +0200282 };
283 };
284
285 return $c->render(status => 400, json => { error => [[0, 'No!']]});
286};
287
288
289# Request API token
Akron63d963b2019-07-05 15:35:51 +0200290get '/v1.0/auth/apiToken' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200291 my $c = shift;
292
293 # Get auth header
294 my $auth = $c->req->headers->authorization;
295
296 # Authorization missing or not basic
297 if (!$auth || $auth !~ s/\s*Basic\s+//gi) {
298 return $c->render(
299 json => {
300 error => [[2, 'x']]
301 }
302 );
303 };
304
305 # Decode header
306 my ($username, $pwd) = @{b($auth)->b64_decode->split(':')->to_array};
307
308 # the password is 'pass'
309 if ($pwd) {
Akrona205b142022-11-28 13:35:19 +0100310 if ($pwd eq 'ldaperr') {
Akron3d673062019-01-29 15:54:16 +0100311 return $c->render(
312 format => 'html',
313 status => 401,
314 json => {
315 "errors" => [[2022,"LDAP Authentication failed due to unknown user or password!"]]
316 }
317 );
Akron0e1ed242018-10-11 13:22:00 +0200318 };
319
320 return $c->render(
321 json => {
322 error => [[2004, undef]]
323 }
324 );
325 };
326
327 return $c->render(
328 json => {
329 error => [[2004, undef]]
330 }
331 );
332};
333
Akron33f5c672019-06-24 19:40:47 +0200334
335# Request API token
Akron63d963b2019-07-05 15:35:51 +0200336post '/v1.0/oauth2/token' => sub {
Akron33f5c672019-06-24 19:40:47 +0200337 my $c = shift;
338
Akron63d963b2019-07-05 15:35:51 +0200339 my $grant_type = $c->param('grant_type') // 'undefined';
340
341 if ($grant_type eq 'password') {
Akron33f5c672019-06-24 19:40:47 +0200342
Akron8bbbecf2019-07-01 18:57:30 +0200343 # Check for wrong client id
344 if ($c->param('client_id') ne '2') {
345 return $c->render(
346 json => {
347 "error_description" => "Unknown client with " . $_->{client_id},
348 "error" => "invalid_client"
349 },
350 status => 401
351 );
352 }
Akron33f5c672019-06-24 19:40:47 +0200353
Akron8bbbecf2019-07-01 18:57:30 +0200354 # Check for wrong client secret
355 elsif ($c->param('client_secret') ne 'k414m4r-s3cr3t') {
356 return $c->render(
357 json => {
358 "error_description" => "Invalid client credentials",
359 "error" => "invalid_client"
360 },
361 status => 401
362 );
363 }
Akron33f5c672019-06-24 19:40:47 +0200364
Akron8bbbecf2019-07-01 18:57:30 +0200365 # Check for wrong user name
Akron6a228db2021-10-14 15:57:00 +0200366 elsif ($c->param('username') !~ /^t.st$/) {
Akron8bbbecf2019-07-01 18:57:30 +0200367 return $c->render(json => {
368 error => [[2004, undef]]
369 });
370 }
371
372 # Check for ldap error
373 elsif ($c->param('password') eq 'ldaperr') {
374 return $c->render(
375 format => 'html',
376 status => 401,
377 json => {
378 "errors" => [
379 [
380 2022,
381 "LDAP Authentication failed due to unknown user or password!"
382 ]
383 ]
384 }
385 );
386 }
387
388 # Check for wrong password
389 elsif ($c->param('password') ne 'pass') {
390 return $c->render(json => {
391 format => 'html',
392 status => 401,
Akron33f5c672019-06-24 19:40:47 +0200393 "errors" => [[2022,"LDAP Authentication failed due to unknown user or password!"]]
Akron8bbbecf2019-07-01 18:57:30 +0200394 });
395 }
396
397 # Return fine access
398 return $c->render(
399 json => {
Akroncdfd9d52019-07-23 11:35:00 +0200400 "access_token" => $c->get_token('access_token'),
401 "refresh_token" => $c->get_token('refresh_token'),
Akron8bbbecf2019-07-01 18:57:30 +0200402 "scope" => "all",
403 "token_type" => "Bearer",
404 "expires_in" => 86400
405 });
406 }
407
408 # Refresh token
Akron63d963b2019-07-05 15:35:51 +0200409 elsif ($grant_type eq 'refresh_token') {
Akroncdfd9d52019-07-23 11:35:00 +0200410
411 if ($c->param('refresh_token') eq 'inv4lid') {
412 return $c->render(
413 status => 400,
414 json => {
415 "error_description" => "Refresh token is expired",
416 "error" => "invalid_grant"
417 }
418 );
419 };
420
421 $c->app->log->debug("Refresh the token in the mock server!");
422
Akron8bbbecf2019-07-01 18:57:30 +0200423 return $c->render(
424 status => 200,
425 json => {
Akroncdfd9d52019-07-23 11:35:00 +0200426 "access_token" => $c->get_token("access_token_2"),
427 "refresh_token" => $c->get_token("refresh_token_2"),
Akron8bbbecf2019-07-01 18:57:30 +0200428 "token_type" => "Bearer",
429 "expires_in" => 86400
Akron33f5c672019-06-24 19:40:47 +0200430 }
431 );
432 }
433
Akron83209f72021-01-29 17:54:15 +0100434 # Get auth_token_1
435 elsif ($grant_type eq 'authorization_code') {
436 if ($c->param('code') eq $tokens{auth_token_1}) {
437 return $c->render(
438 status => 200,
439 json => {
440 "access_token" => $tokens{access_token_3},
441 "expires_in" => 31536000,
442 "scope" => 'match_info search openid',
443 "token_type" => "Bearer"
444 }
445 );
446 };
447 }
448
Akron8bbbecf2019-07-01 18:57:30 +0200449 # Unknown token grant
450 else {
451 return $c->render(
Akron63d963b2019-07-05 15:35:51 +0200452 status => 400,
Akron8bbbecf2019-07-01 18:57:30 +0200453 json => {
454 "errors" => [
455 [
Akron63d963b2019-07-05 15:35:51 +0200456 0, "Grant Type unknown", $grant_type
Akron8bbbecf2019-07-01 18:57:30 +0200457 ]
458 ]
459 }
460 )
Akron33f5c672019-06-24 19:40:47 +0200461 }
Akron33f5c672019-06-24 19:40:47 +0200462};
463
Akron4cefe1f2019-09-04 10:11:28 +0200464# Revoke API token
465post '/v1.0/oauth2/revoke' => sub {
466 my $c = shift;
467
468 my $refresh_token = $c->param('token');
469
470 if ($c->param('client_secret') ne 'k414m4r-s3cr3t') {
471 return $c->render(
472 json => {
473 "error_description" => "Invalid client credentials",
474 "error" => "invalid_client"
475 },
476 status => 401
477 );
478 };
479
480 return $c->render(
481 text => ''
482 )
483};
Akron33f5c672019-06-24 19:40:47 +0200484
Akron59992122019-10-29 11:28:45 +0100485# Register a client
486post '/v1.0/oauth2/client/register' => sub {
487 my $c = shift;
488 my $json = $c->req->json;
489
Akrondc50c892021-05-05 18:12:02 +0200490 if ($json->{redirectURI}) {
491 return $c->render(
492 status => 400,
493 json => {
494 errors => [
495 [
496 201,
497 "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\"])"
498 ]
499 ]
500 }
501 );
502 };
503
Akron59992122019-10-29 11:28:45 +0100504 my $name = $json->{name};
Akron1a9d5be2020-03-19 17:28:33 +0100505 my $desc = $json->{description};
Akron59992122019-10-29 11:28:45 +0100506 my $type = $json->{type};
507 my $url = $json->{url};
Akron9f2ad342022-05-04 16:16:40 +0200508 my $src = $json->{source};
Akronb6b156e2022-03-31 14:57:49 +0200509 my $redirect_uri = $json->{redirect_uri};
Akron59992122019-10-29 11:28:45 +0100510
Akron1a9d5be2020-03-19 17:28:33 +0100511 my $list = $c->app->defaults('oauth.client_list');
512
Akron6b75d122022-05-12 17:39:05 +0200513 my $obj = {
Akrondc50c892021-05-05 18:12:02 +0200514 "client_id" => $tokens{new_client_id},
515 "client_name" => $name,
Akronbc94a9c2021-04-15 00:07:35 +0200516 "client_description" => $desc,
Akronb6b156e2022-03-31 14:57:49 +0200517 "client_url" => $url,
Akron9f2ad342022-05-04 16:16:40 +0200518 "client_redirect_uri" => $redirect_uri,
Akron6b75d122022-05-12 17:39:05 +0200519 "client_type" => $type
Akronb6b156e2022-03-31 14:57:49 +0200520 };
521
Akron6b75d122022-05-12 17:39:05 +0200522 # Plugin!
523 if ($src) {
524 $obj->{source} = $src;
525 $obj->{client_id} = $tokens{new_client_id_3};
526 };
527
528 push @$list, $obj;
529
Akronb6b156e2022-03-31 14:57:49 +0200530 if ($redirect_uri && $redirect_uri =~ /FAIL$/) {
531 return $c->render(
532 status => 400,
533 json => {
534 "error_description" => $redirect_uri . " is invalid.",
535 "error" => "invalid_request"
536 }
537 )
Akron1a9d5be2020-03-19 17:28:33 +0100538 };
539
Akron59992122019-10-29 11:28:45 +0100540 # Confidential server application
541 if ($type eq 'CONFIDENTIAL') {
Akronb6b156e2022-03-31 14:57:49 +0200542
Akron59992122019-10-29 11:28:45 +0100543 return $c->render(json => {
Akronb6b156e2022-03-31 14:57:49 +0200544 client_id => $tokens{new_client_id_2},
Akron59992122019-10-29 11:28:45 +0100545 client_secret => $tokens{new_client_secret}
546 });
547 };
548
549 # Desktop application
550 return $c->render(json => {
551 client_id => $tokens{new_client_id}
552 });
553};
554
Akron33f5c672019-06-24 19:40:47 +0200555
Akron0f1b93b2020-03-17 11:37:19 +0100556# Register a client
557post '/v1.0/oauth2/client/list' => sub {
558 my $c = shift;
559
Akron276afc02021-06-14 11:00:21 +0200560 my $v = $c->validation;
561
562 $v->required('super_client_id');
563 $v->required('super_client_secret');
564
565 if ($v->has_error) {
566 return $c->render(
567 json => [],
568 status => 400
569 );
570 };
571
Akron0f1b93b2020-03-17 11:37:19 +0100572 # $c->param('client_secret');
Akron1a9d5be2020-03-19 17:28:33 +0100573
574 # Is empty [] when nothing registered
575
Akron0f1b93b2020-03-17 11:37:19 +0100576 return $c->render(
Akron1a9d5be2020-03-19 17:28:33 +0100577 json => $c->stash('oauth.client_list'),
578 status => 200
579 );
580};
581
Akrondb1f4672023-01-24 12:05:07 +0100582# Get client info
583post '/v1.0/oauth2/client/:client_id' => sub {
584 my $c = shift;
585
586 # Validate input
587 my $v = $c->validation;
588 $v->required('super_client_id');
589 $v->required('super_client_secret');
590
591 if ($v->has_error) {
592 return $c->render(
593 status => 400,
594 json => {
595 error_description => "No super client",
596 error => "no_superclient"
597 }
598 );
599 };
600
601 my $client_id = $c->stash('client_id');
602
603 my $list = $c->stash('oauth.client_list');
604
605 foreach (@$list) {
606 if ($_->{client_id} eq $client_id) {
607 return $c->render(
608 json => $_,
609 status => 200
610 );
611 };
612 };
613
614 return $c->render(
615 json => {
616 error_description => "Unknown client with $client_id.",
617 error => "invalid_client"
618 },
619 status => 401
620 );
621};
622
Akronbc94a9c2021-04-15 00:07:35 +0200623
624# Get token list
625post '/v1.0/oauth2/token/list' => sub {
626 my $c = shift;
627 return $c->render(json => [
628 {
629 "client_description" => "Nur ein Beispiel",
630 "client_id" => $tokens{new_client_id},
631 "client_name" => "Beispiel",
632 "client_url" => "",
633 "created_date" => "2021-04-14T19:40:26.742+02:00[Europe\/Berlin]",
634 "expires_in" => "31533851",
635 "scope" => [
636 "match_info",
637 "search",
638 "openid"
639 ],
640 "token" => "jhkhkjhk_hjgjsfz67i",
641 "user_authentication_time" => "2021-04-14T19:39:41.81+02:00[Europe\/Berlin]"
642 }
643 ]);
644};
645
Akron1a9d5be2020-03-19 17:28:33 +0100646del '/v1.0/oauth2/client/deregister/:client_id' => sub {
647 my $c = shift;
648 my $client_id = $c->stash('client_id');
649
650 my $list = $c->app->defaults('oauth.client_list');
651
652 my $break = -1;
653 for (my $i = 0; $i < @$list; $i++) {
Akrondc50c892021-05-05 18:12:02 +0200654 if ($list->[$i]->{client_id} eq $client_id) {
Akron1a9d5be2020-03-19 17:28:33 +0100655 $break = $i;
656 last;
657 };
658 };
659
660 if ($break != -1) {
661 splice @$list, $break, 1;
662 }
663
664 else {
665 return $c->render(
666 json => {
667 error_description => "Unknown client with $client_id.",
668 error => "invalid_client"
Akron0f1b93b2020-03-17 11:37:19 +0100669 },
Akron1a9d5be2020-03-19 17:28:33 +0100670 status => 401
671 );
672 };
673
674 return $c->render(
675 json => $c->stash('oauth.client_list'),
Akron0f1b93b2020-03-17 11:37:19 +0100676 status => 200
677 );
678};
679
Akron83209f72021-01-29 17:54:15 +0100680post '/v1.0/oauth2/authorize' => sub {
681 my $c = shift;
682 my $type = $c->param('response_type');
683 my $client_id = $c->param('client_id');
Akrona8efaa92022-04-09 14:45:43 +0200684 my $scope = $c->param('scope');
685 my $state = $c->param('state');
686 my $redirect_uri = $c->param('redirect_uri') // 'NO';
Akron83209f72021-01-29 17:54:15 +0100687
Akrona8efaa92022-04-09 14:45:43 +0200688 if ($type eq 'code' && $client_id eq 'xyz') {
689
690 if ($state eq 'fail') {
691 $c->res->headers->location(
692 Mojo::URL->new($redirect_uri)->query({
693 error_description => 'FAIL'
694 })
695 );
696 $c->res->code(400);
697 return $c->rendered;
698 };
699
700 return $c->redirect_to(
701 Mojo::URL->new($redirect_uri)->query({
702 code => $tokens{auth_token_1},
703 scope => $scope,
704 })
705 );
706 }
707
708 elsif ($type eq 'code') {
Akron83209f72021-01-29 17:54:15 +0100709
710 return $c->redirect_to(
711 Mojo::URL->new($redirect_uri)->query({
712 code => $tokens{auth_token_1},
713 scope => 'match_info search openid'
714 })
715 );
716 }
717};
718
Akron0f1b93b2020-03-17 11:37:19 +0100719
Akronabdf9a92021-01-12 19:06:57 +0100720#######################
721# Query Reference API #
722#######################
723
724use CHI;
725my $chi = CHI->new(
726 driver => 'Memory',
727 global => 1
728);
729
730# Store query
731put '/v1.0/query/~:user/:query_name' => sub {
732 my $c = shift;
733 my $user = $c->stash('user');
734 my $qname = $c->stash('query_name');
735
736 if ($chi->is_valid($qname)) {
737 return $c->render(
738 json => {
739 errors => [
740 {
741 message => 'Unable to store query reference'
742 }
743 ]
744 }, status => 400
745 );
746 };
747
748 my $json = $c->req->json;
749
750 my $store = {
751 name => $qname,
752 koralQuery => { '@type' => 'Okay' },
753 query => $json->{query},
754 queryType => $json->{queryType},
755 type => $json->{type},
756 queryLanguage => $json->{queryLanguage},
757 };
758
759 if (exists $json->{description}) {
760 $store->{description} = $json->{description}
761 };
762
763 # Set query reference
764 $chi->set($qname => $store);
765
766 my $queries = $chi->get('~queries') // [];
767 push @$queries, $qname;
768 $chi->set('~queries' => $queries);
769
770 return $c->render(
771 status => 201,
772 text => ''
773 );
774};
775
776# Get query
777get '/v1.0/query/~:user/:query_name' => sub {
778 my $c = shift;
779
780 my $user = $c->stash('user');
781 my $qname = $c->stash('query_name');
782
783 my $json = $chi->get($qname);
784
785 if ($json) {
786 return $c->render(
787 json => $json
788 );
789 };
790
791 return $c->render(
792 json => {
793 errors => [
794 {
795 message => 'Query reference not found'
796 }
797 ]
798 }, status => 404
799 );
800};
801
802
803# Get all queries
804get '/v1.0/query/~:user' => sub {
805 my $c = shift;
806 my $user = $c->stash('user');
807 my $qs = $chi->get('~queries') // [];
808 my @queries = ();
809 foreach (@$qs) {
810 push @queries, $chi->get($_);
811 };
812 return $c->render(json => { refs => \@queries });
813};
814
815
816# Store query
817del '/v1.0/query/~:user/:query_name' => sub {
818 my $c = shift;
819 my $user = $c->stash('user');
820 my $qname = $c->stash('query_name');
821
822 $chi->remove($qname);
823
824 my $queries = $chi->get('~queries') // [];
825
826 my @clean = ();
827 foreach (@$queries) {
828 push @clean, $_ unless $_ eq $qname
829 };
830
831 $chi->set('~queries' => \@clean);
832
833 return $c->render(
834 status => 200,
835 text => ''
836 );
837};
838
Akronc1aaf932021-06-09 12:19:15 +0200839post '/v1.0/oauth2/revoke/super' => sub {
840 my $c = shift;
841
842 my $s_client_id = $c->param('super_client_id');
843 my $s_client_secret = $c->param('super_client_secret');
844 my $token = $c->param('token');
845
846 return $c->render(text => 'SUCCESS');
847};
848
Akrona8efaa92022-04-09 14:45:43 +0200849get '/fakeclient/return' => sub {
850 my $c = shift;
851 $c->render(
852 text => 'welcome back! [' . $c->param('code') . ']'
853 );
854} => 'return_uri';
855
Akron0f1b93b2020-03-17 11:37:19 +0100856
Akron0e1ed242018-10-11 13:22:00 +0200857app->start;
858
859
860__END__
861
862
863 # Temporary:
864 my $collection_query = {
865 '@type' => "koral:docGroup",
866 "operation" => "operation:or",
867 "operands" => [
868 {
869 '@type' => "koral:docGroup",
870 "operation" => "operation:and",
871 "operands" => [
872 {
873 '@type' => "koral:doc",
874 "key" => "title",
875 "match" => "match:eq",
876 "value" => "Der Birnbaum",
877 "type" => "type:string"
878 },
879 {
880 '@type' => "koral:doc",
881 "key" => "pubPlace",
882 "match" => "match:eq",
883 "value" => "Mannheim",
884 "type" => "type:string"
885 },
886 {
887 '@type' => "koral:docGroup",
888 "operation" => "operation:or",
889 "operands" => [
890 {
891 '@type' => "koral:doc",
892 "key" => "subTitle",
893 "match" => "match:eq",
894 "value" => "Aufzucht oder Pflege",
895 "type" => "type:string"
896 },
897 {
898 '@type' => "koral:doc",
899 "key" => "subTitle",
900 "match" => "match:eq",
901 "value" => "Gedichte",
902 "type" => "type:string"
903 }
904 ]
905 }
906 ]
907 },
908 {
909 '@type' => "koral:doc",
910 "key" => "pubDate",
911 "match" => "match:geq",
912 "value" => "2015-03-05",
913 "type" => "type:date"
914 }
915 ]
916 };