Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2014--2025 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Lesser General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-merchant-httpd_auth.c
18 : * @brief client authentication logic
19 : * @author Martin Schanzenbach
20 : * @author Christian Grothoff
21 : */
22 : #include "platform.h"
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include <gnunet/gnunet_db_lib.h>
25 : #include <taler/taler_json_lib.h>
26 : #include "taler-merchant-httpd_auth.h"
27 : #include "taler-merchant-httpd_helper.h"
28 :
29 : /**
30 : * Maximum length of a permissions string of a scope
31 : */
32 : #define TMH_MAX_SCOPE_PERMISSIONS_LEN 4096
33 :
34 : /**
35 : * Maximum length of a name of a scope
36 : */
37 : #define TMH_MAX_NAME_LEN 255
38 :
39 : /**
40 : * Represents a hard-coded set of default scopes with their
41 : * permissions and names
42 : */
43 : struct ScopePermissionMap
44 : {
45 : /**
46 : * The scope enum value
47 : */
48 : enum TMH_AuthScope as;
49 :
50 : /**
51 : * The scope name
52 : */
53 : char name[TMH_MAX_NAME_LEN];
54 :
55 : /**
56 : * The scope permissions string.
57 : * Comma-separated.
58 : */
59 : char permissions[TMH_MAX_SCOPE_PERMISSIONS_LEN];
60 : };
61 :
62 : /**
63 : * The default scopes array for merchant
64 : */
65 : static struct ScopePermissionMap scope_permissions[] = {
66 : /* Deprecated since v19 */
67 : {
68 : .as = TMH_AS_ALL,
69 : .name = "write",
70 : .permissions = "*"
71 : },
72 : /* Full access for SPA */
73 : {
74 : .as = TMH_AS_ALL,
75 : .name = "all",
76 : .permissions = "*"
77 : },
78 : /* Full access for SPA */
79 : {
80 : .as = TMH_AS_SPA,
81 : .name = "spa",
82 : .permissions = "*"
83 : },
84 : /* Read-only access */
85 : {
86 : .as = TMH_AS_READ_ONLY,
87 : .name = "readonly",
88 : .permissions = "*-read"
89 : },
90 : /* Simple order management */
91 : {
92 : .as = TMH_AS_ORDER_SIMPLE,
93 : .name = "order-simple",
94 : .permissions = "orders-read,orders-write"
95 : },
96 : /* Simple order management for PoS, also allows inventory locking */
97 : {
98 : .as = TMH_AS_ORDER_POS,
99 : .name = "order-pos",
100 : .permissions = "orders-read,orders-write,inventory-lock"
101 : },
102 : /* Simple order management, also allows refunding */
103 : {
104 : .as = TMH_AS_ORDER_MGMT,
105 : .name = "order-mgmt",
106 : .permissions = "orders-read,orders-write,orders-refund"
107 : },
108 : /* Full order management, allows inventory locking and refunds */
109 : {
110 : .as = TMH_AS_ORDER_FULL,
111 : .name = "order-full",
112 : .permissions = "orders-read,orders-write,inventory-lock,orders-refund"
113 : },
114 : /* No permissions, dummy scope */
115 : {
116 : .as = TMH_AS_NONE,
117 : }
118 : };
119 :
120 :
121 : /**
122 : * Get permissions string for scope.
123 : * Also extracts the leftmost bit into the @a refreshable
124 : * output parameter.
125 : *
126 : * @param as the scope to get the permissions string from
127 : * @param[out] refreshable true if the token associated with this scope is refreshable.
128 : * @return the permissions string, or NULL if no such scope found
129 : */
130 : static const char*
131 566 : get_scope_permissions (enum TMH_AuthScope as,
132 : bool *refreshable)
133 : {
134 566 : *refreshable = as & TMH_AS_REFRESHABLE;
135 767 : for (unsigned int i = 0; TMH_AS_NONE != scope_permissions[i].as; i++)
136 : {
137 : /* We ignore the TMH_AS_REFRESHABLE bit */
138 749 : if ( (as & ~TMH_AS_REFRESHABLE) ==
139 749 : (scope_permissions[i].as & ~TMH_AS_REFRESHABLE) )
140 548 : return scope_permissions[i].permissions;
141 : }
142 18 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
143 : "Failed to find required permissions for scope %d\n",
144 : as);
145 18 : return NULL;
146 : }
147 :
148 :
149 : /**
150 : * Extract the token from authorization header value @a auth.
151 : * The @a auth value can be a bearer token or a Basic
152 : * authentication header. In both cases, this function
153 : * updates @a auth to point to the actual credential,
154 : * skipping spaces.
155 : *
156 : * NOTE: We probably want to replace this function with MHD2
157 : * API calls in the future that are more robust.
158 : *
159 : * @param[in,out] auth pointer to authorization header value,
160 : * will be updated to point to the start of the token
161 : * or set to NULL if header value is invalid
162 : * @param[out] is_basic_auth will be set to true if the
163 : * authorization header uses basic authentication,
164 : * otherwise to false
165 : */
166 : static void
167 71 : extract_auth (const char **auth,
168 : bool *is_basic_auth)
169 : {
170 71 : const char *bearer = "Bearer ";
171 71 : const char *basic = "Basic ";
172 71 : const char *tok = *auth;
173 71 : size_t offset = 0;
174 71 : bool is_bearer = false;
175 :
176 71 : *is_basic_auth = false;
177 71 : if (0 == strncmp (tok,
178 : bearer,
179 : strlen (bearer)))
180 : {
181 57 : offset = strlen (bearer);
182 57 : is_bearer = true;
183 : }
184 14 : else if (0 == strncmp (tok,
185 : basic,
186 : strlen (basic)))
187 : {
188 14 : offset = strlen (basic);
189 14 : *is_basic_auth = true;
190 : }
191 : else
192 : {
193 0 : *auth = NULL;
194 0 : return;
195 : }
196 71 : tok += offset;
197 71 : while (' ' == *tok)
198 0 : tok++;
199 71 : if ( (is_bearer) &&
200 57 : (0 != strncasecmp (tok,
201 : RFC_8959_PREFIX,
202 : strlen (RFC_8959_PREFIX))) )
203 : {
204 0 : *auth = NULL;
205 0 : return;
206 : }
207 71 : *auth = tok;
208 : }
209 :
210 :
211 : /**
212 : * Check if @a userpass grants access to @a instance.
213 : *
214 : * @param userpass base64 encoded "$USERNAME:$PASSWORD" value
215 : * from HTTP Basic "Authentication" header
216 : * @param instance the access controlled instance
217 : */
218 : static enum GNUNET_GenericReturnValue
219 14 : check_auth_instance (const char *userpass,
220 : struct TMH_MerchantInstance *instance)
221 : {
222 : char *tmp;
223 : char *colon;
224 : const char *instance_name;
225 : const char *password;
226 14 : const char *target_instance = "admin";
227 : enum GNUNET_GenericReturnValue ret;
228 :
229 : /* implicitly a zeroed out hash means no authentication */
230 14 : if (GNUNET_is_zero (&instance->auth.auth_hash))
231 0 : return GNUNET_OK;
232 14 : if (NULL == userpass)
233 : {
234 0 : GNUNET_break_op (0);
235 0 : return GNUNET_SYSERR;
236 : }
237 14 : if (0 ==
238 14 : GNUNET_STRINGS_base64_decode (userpass,
239 : strlen (userpass),
240 : (void**) &tmp))
241 : {
242 0 : GNUNET_break_op (0);
243 0 : return GNUNET_SYSERR;
244 : }
245 14 : colon = strchr (tmp,
246 : ':');
247 14 : if (NULL == colon)
248 : {
249 0 : GNUNET_break_op (0);
250 0 : GNUNET_free (tmp);
251 0 : return GNUNET_SYSERR;
252 : }
253 14 : *colon = '\0';
254 14 : instance_name = tmp;
255 14 : password = colon + 1;
256 : /* instance->settings.id can be NULL if there is no instance yet */
257 14 : if (NULL != instance->settings.id)
258 14 : target_instance = instance->settings.id;
259 14 : if (0 != strcmp (instance_name,
260 : target_instance))
261 : {
262 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
263 : "Somebody tried to login to instance %s with username %s (login failed).\n",
264 : target_instance,
265 : instance_name);
266 0 : GNUNET_free (tmp);
267 0 : return GNUNET_SYSERR;
268 : }
269 14 : ret = TMH_check_auth (password,
270 : &instance->auth.auth_salt,
271 : &instance->auth.auth_hash);
272 14 : GNUNET_free (tmp);
273 14 : if (GNUNET_OK != ret)
274 : {
275 1 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
276 : "Password provided does not match credentials for %s\n",
277 : target_instance);
278 : }
279 14 : return ret;
280 : }
281 :
282 :
283 : void
284 13 : TMH_compute_auth (const char *token,
285 : struct TALER_MerchantAuthenticationSaltP *salt,
286 : struct TALER_MerchantAuthenticationHashP *hash)
287 : {
288 13 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
289 : salt,
290 : sizeof (*salt));
291 13 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292 : "Computing initial auth using token with salt %s\n",
293 : TALER_B2S (salt));
294 13 : TALER_merchant_instance_auth_hash_with_salt (hash,
295 : salt,
296 : token);
297 13 : }
298 :
299 :
300 : /**
301 : * Function used to process Basic authorization header value.
302 : * Sets correct scope in the auth_scope parameter of the
303 : * #TMH_HandlerContext.
304 : *
305 : * @param hc the handler context
306 : * @param authn_s the value of the authorization header
307 : */
308 : static void
309 14 : process_basic_auth (struct TMH_HandlerContext *hc,
310 : const char *authn_s)
311 : {
312 : /* Handle token endpoint slightly differently: Only allow
313 : * instance password (Basic auth) to retrieve access token.
314 : * We need to handle authorization with Basic auth here first
315 : * The only time we need to handle authentication like this is
316 : * for the token endpoint!
317 : */
318 14 : if ( (0 != strncmp (hc->rh->url_prefix,
319 : "/token",
320 14 : strlen ("/token"))) ||
321 14 : (0 != strncmp (MHD_HTTP_METHOD_POST,
322 14 : hc->rh->method,
323 14 : strlen (MHD_HTTP_METHOD_POST))) ||
324 14 : (NULL == hc->instance))
325 : {
326 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
327 : "Called endpoint `%s' with Basic authentication. Rejecting...\n",
328 : hc->rh->url_prefix);
329 0 : hc->auth_scope = TMH_AS_NONE;
330 0 : return;
331 : }
332 14 : if (GNUNET_OK ==
333 14 : check_auth_instance (authn_s,
334 : hc->instance))
335 : {
336 13 : hc->auth_scope = TMH_AS_ALL;
337 : }
338 : else
339 : {
340 1 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
341 : "Basic authentication failed!\n");
342 1 : hc->auth_scope = TMH_AS_NONE;
343 : }
344 : }
345 :
346 :
347 : /**
348 : * Function used to process Bearer authorization header value.
349 : * Sets correct scope in the auth_scope parameter of the
350 : * #TMH_HandlerContext..
351 : *
352 : * @param hc the handler context
353 : * @param authn_s the value of the authorization header
354 : * @return TALER_EC_NONE on success.
355 : */
356 : static enum TALER_ErrorCode
357 513 : process_bearer_auth (struct TMH_HandlerContext *hc,
358 : const char *authn_s)
359 : {
360 513 : if (NULL == hc->instance)
361 : {
362 2 : hc->auth_scope = TMH_AS_NONE;
363 2 : return TALER_EC_NONE;
364 : }
365 511 : if (GNUNET_is_zero (&hc->instance->auth.auth_hash))
366 : {
367 : /* hash zero means no authentication for instance */
368 468 : hc->auth_scope = TMH_AS_ALL;
369 468 : return TALER_EC_NONE;
370 : }
371 : {
372 : enum TALER_ErrorCode ec;
373 :
374 43 : ec = TMH_check_token (authn_s,
375 43 : hc->instance->settings.id,
376 : &hc->auth_scope);
377 43 : if (TALER_EC_NONE != ec)
378 : {
379 : char *dec;
380 : size_t dec_len;
381 : const char *token;
382 :
383 : /* NOTE: Deprecated, remove sometime after v1.1 */
384 9 : if (0 != strncasecmp (authn_s,
385 : RFC_8959_PREFIX,
386 : strlen (RFC_8959_PREFIX)))
387 : {
388 0 : GNUNET_break_op (0);
389 0 : hc->auth_scope = TMH_AS_NONE;
390 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
391 : "Authentication token invalid: %d\n",
392 : (int) ec);
393 9 : return ec;
394 : }
395 9 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
396 : "Trying deprecated secret-token:password API authN\n");
397 9 : token = authn_s + strlen (RFC_8959_PREFIX);
398 9 : dec_len = GNUNET_STRINGS_urldecode (token,
399 : strlen (token),
400 : &dec);
401 18 : if ( (0 == dec_len) ||
402 : (GNUNET_OK !=
403 9 : TMH_check_auth (dec,
404 9 : &hc->instance->auth.auth_salt,
405 9 : &hc->instance->auth.auth_hash)) )
406 : {
407 9 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
408 : "Login failed\n");
409 9 : hc->auth_scope = TMH_AS_NONE;
410 9 : GNUNET_free (dec);
411 9 : return TALER_EC_NONE;
412 : }
413 0 : hc->auth_scope = TMH_AS_ALL;
414 0 : GNUNET_free (dec);
415 : }
416 : }
417 34 : return TALER_EC_NONE;
418 : }
419 :
420 :
421 : /**
422 : * Checks if @a permission_required is in permissions of
423 : * @a scope.
424 : *
425 : * @param permission_required the permission to check.
426 : * @param scope the scope to check.
427 : * @return true if @a permission_required is in the permissions set of @a scope.
428 : */
429 : static bool
430 536 : permission_in_scope (const char *permission_required,
431 : enum TMH_AuthScope scope)
432 : {
433 : char *permissions;
434 : const char *perms_tmp;
435 536 : bool is_read_perm = false;
436 536 : bool is_write_perm = false;
437 : bool refreshable;
438 : const char *last_dash;
439 :
440 536 : perms_tmp = get_scope_permissions (scope,
441 : &refreshable);
442 536 : if (NULL == perms_tmp)
443 : {
444 18 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
445 : "Permission check failed: scope %d not understood\n",
446 : (int) scope);
447 18 : return false;
448 : }
449 518 : last_dash = strrchr (permission_required,
450 : '-');
451 518 : if (NULL != last_dash)
452 : {
453 517 : is_write_perm = (0 == strcmp (last_dash,
454 : "-write"));
455 517 : is_read_perm = (0 == strcmp (last_dash,
456 : "-read"));
457 : }
458 :
459 518 : if (0 == strcmp ("token-refresh",
460 : permission_required))
461 : {
462 16 : if (! refreshable)
463 : {
464 1 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
465 : "Permission check failed: token not refreshable\n");
466 : }
467 16 : return refreshable;
468 : }
469 502 : permissions = GNUNET_strdup (perms_tmp);
470 : {
471 502 : const char *perm = strtok (permissions,
472 : ",");
473 :
474 502 : if (NULL == perm)
475 : {
476 0 : GNUNET_free (permissions);
477 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
478 : "Permission check failed: empty permission set\n");
479 0 : return false;
480 : }
481 503 : while (NULL != perm)
482 : {
483 502 : if (0 == strcmp ("*",
484 : perm))
485 : {
486 500 : GNUNET_free (permissions);
487 500 : return true;
488 : }
489 2 : if ( (0 == strcmp ("*-write",
490 0 : perm)) &&
491 : (is_write_perm) )
492 : {
493 0 : GNUNET_free (permissions);
494 0 : return true;
495 : }
496 2 : if ( (0 == strcmp ("*-read",
497 2 : perm)) &&
498 : (is_read_perm) )
499 : {
500 1 : GNUNET_free (permissions);
501 1 : return true;
502 : }
503 1 : if (0 == strcmp (permission_required,
504 : perm))
505 : {
506 0 : GNUNET_free (permissions);
507 0 : return true;
508 : }
509 1 : perm = strtok (NULL,
510 : ",");
511 : }
512 : }
513 1 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
514 : "Permission check failed: %s not found in %s\n",
515 : permission_required,
516 : permissions);
517 1 : GNUNET_free (permissions);
518 1 : return false;
519 : }
520 :
521 :
522 : bool
523 15 : TMH_scope_is_subset (enum TMH_AuthScope as,
524 : enum TMH_AuthScope candidate)
525 : {
526 : const char *as_perms;
527 : const char *candidate_perms;
528 : char *permissions;
529 : bool as_refreshable;
530 : bool cand_refreshable;
531 :
532 15 : as_perms = get_scope_permissions (as,
533 : &as_refreshable);
534 15 : candidate_perms = get_scope_permissions (candidate,
535 : &cand_refreshable);
536 15 : if (! as_refreshable && cand_refreshable)
537 0 : return false;
538 15 : if ( (NULL == as_perms) &&
539 : (NULL != candidate_perms) )
540 0 : return false;
541 15 : if ( (NULL == candidate_perms) ||
542 15 : (0 == strcmp ("*",
543 : as_perms)))
544 14 : return true;
545 1 : permissions = GNUNET_strdup (candidate_perms);
546 : {
547 : const char *perm;
548 :
549 1 : perm = strtok (permissions,
550 : ",");
551 1 : if (NULL == perm)
552 : {
553 0 : GNUNET_free (permissions);
554 0 : return true;
555 : }
556 1 : while (NULL != perm)
557 : {
558 1 : if (! permission_in_scope (perm,
559 : as))
560 : {
561 1 : GNUNET_free (permissions);
562 1 : return false;
563 : }
564 0 : perm = strtok (NULL,
565 : ",");
566 : }
567 : }
568 0 : GNUNET_free (permissions);
569 0 : return true;
570 : }
571 :
572 :
573 : enum TMH_AuthScope
574 15 : TMH_get_scope_by_name (const char *name)
575 : {
576 36 : for (unsigned int i = 0; TMH_AS_NONE != scope_permissions[i].as; i++)
577 : {
578 36 : if (0 == strcasecmp (scope_permissions[i].name,
579 : name))
580 15 : return scope_permissions[i].as;
581 : }
582 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
583 : "Name `%s' does not match any scope we understand\n",
584 : name);
585 0 : return TMH_AS_NONE;
586 : }
587 :
588 :
589 : const char*
590 2 : TMH_get_name_by_scope (enum TMH_AuthScope scope,
591 : bool *refreshable)
592 : {
593 2 : *refreshable = scope & TMH_AS_REFRESHABLE;
594 8 : for (unsigned int i = 0; TMH_AS_NONE != scope_permissions[i].as; i++)
595 : {
596 : /* We ignore the TMH_AS_REFRESHABLE bit */
597 8 : if ( (scope & ~TMH_AS_REFRESHABLE) ==
598 8 : (scope_permissions[i].as & ~TMH_AS_REFRESHABLE) )
599 2 : return scope_permissions[i].name;
600 : }
601 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
602 : "Scope #%d does not match any scope we understand\n",
603 : (int) scope);
604 0 : return NULL;
605 : }
606 :
607 :
608 : enum GNUNET_GenericReturnValue
609 23 : TMH_check_auth (const char *password,
610 : struct TALER_MerchantAuthenticationSaltP *salt,
611 : struct TALER_MerchantAuthenticationHashP *hash)
612 : {
613 : struct TALER_MerchantAuthenticationHashP val;
614 :
615 23 : if (GNUNET_is_zero (hash))
616 0 : return GNUNET_OK;
617 23 : if (NULL == password)
618 : {
619 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
620 : "Denying access: empty password provided\n");
621 0 : return GNUNET_SYSERR;
622 : }
623 23 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 : "Checking against token with salt %s\n",
625 : TALER_B2S (salt));
626 23 : TALER_merchant_instance_auth_hash_with_salt (&val,
627 : salt,
628 : password);
629 23 : if (0 !=
630 23 : GNUNET_memcmp (&val,
631 : hash))
632 : {
633 10 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
634 : "Access denied: password does not match\n");
635 10 : return GNUNET_SYSERR;
636 : }
637 13 : return GNUNET_OK;
638 : }
639 :
640 :
641 : /**
642 : * Check if the client has provided the necessary credentials
643 : * to access the selected endpoint of the selected instance.
644 : *
645 : * @param[in,out] hc handler context
646 : * @return #GNUNET_OK on success,
647 : * #GNUNET_NO if an error was queued (return #MHD_YES)
648 : * #GNUNET_SYSERR to close the connection (return #MHD_NO)
649 : */
650 : enum GNUNET_GenericReturnValue
651 548 : TMH_perform_access_control (struct TMH_HandlerContext *hc)
652 : {
653 : const char *auth;
654 548 : bool is_basic_auth = false;
655 548 : bool auth_malformed = false;
656 :
657 548 : auth = MHD_lookup_connection_value (hc->connection,
658 : MHD_HEADER_KIND,
659 : MHD_HTTP_HEADER_AUTHORIZATION);
660 :
661 548 : if (NULL != auth)
662 : {
663 71 : extract_auth (&auth,
664 : &is_basic_auth);
665 71 : if (NULL == auth)
666 0 : auth_malformed = true;
667 71 : hc->auth_token = auth;
668 : }
669 :
670 : /* If we have zero configured instances (not even ones that have been
671 : purged) or explicitly disabled authentication, THEN we accept anything
672 : (no access control), as we then also have no data to protect. */
673 548 : if ((0 == GNUNET_CONTAINER_multihashmap_size (TMH_by_id_map)) ||
674 527 : (GNUNET_YES == TMH_auth_disabled))
675 : {
676 21 : hc->auth_scope = TMH_AS_ALL;
677 : }
678 527 : else if (is_basic_auth)
679 : {
680 14 : process_basic_auth (hc,
681 : auth);
682 : }
683 : else /* Check bearer token */
684 : {
685 : enum TALER_ErrorCode ec;
686 :
687 513 : ec = process_bearer_auth (hc,
688 : auth);
689 513 : if (TALER_EC_NONE != ec)
690 : {
691 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
692 : "Bearer authentication failed: %d\n",
693 : (int) ec);
694 : return (MHD_YES ==
695 0 : TALER_MHD_reply_with_ec (hc->connection,
696 : ec,
697 : NULL))
698 : ? GNUNET_NO
699 0 : : GNUNET_SYSERR;
700 : }
701 : }
702 : /* We grant access if:
703 : - Endpoint does not require permissions
704 : - Authorization scope of bearer token contains permissions
705 : required by endpoint.
706 : */
707 548 : if ( (NULL != hc->rh->permission) &&
708 535 : (! permission_in_scope (hc->rh->permission,
709 : hc->auth_scope)))
710 : {
711 19 : if (auth_malformed &&
712 0 : (TMH_AS_NONE == hc->auth_scope) )
713 : {
714 0 : GNUNET_break_op (0);
715 : return (MHD_YES ==
716 0 : TALER_MHD_reply_with_error (
717 : hc->connection,
718 : MHD_HTTP_UNAUTHORIZED,
719 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
720 : "'" RFC_8959_PREFIX
721 : "' prefix or 'Bearer' missing in 'Authorization' header"))
722 : ? GNUNET_NO
723 0 : : GNUNET_SYSERR;
724 : }
725 19 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
726 : "Credentials provided are %d which are insufficient for access to `%s'\n",
727 : (int) hc->auth_scope,
728 : hc->rh->permission);
729 : return (MHD_YES ==
730 19 : TALER_MHD_reply_with_error (
731 : hc->connection,
732 : MHD_HTTP_UNAUTHORIZED,
733 : TALER_EC_MERCHANT_GENERIC_UNAUTHORIZED,
734 : "Check credentials in 'Authorization' header"))
735 : ? GNUNET_NO
736 19 : : GNUNET_SYSERR;
737 : }
738 529 : return GNUNET_OK;
739 : }
|