LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_oauth.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 81 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2021 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify
       6             :   it under the terms of the GNU General Public License as
       7             :   published by the Free Software Foundation; either version 3, or
       8             :   (at your option) any later version.
       9             : 
      10             :   TALER is distributed in the hope that it will be useful, but
      11             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :   GNU General Public License for more details.
      14             : 
      15             :   You should have received a copy of the GNU General Public
      16             :   License along with TALER; see the file COPYING.  If not, see
      17             :   <http://www.gnu.org/licenses/>
      18             : */
      19             : 
      20             : /**
      21             :  * @file testing/testing_api_cmd_oauth.c
      22             :  * @brief Implement a CMD to run an OAuth service for faking the legitimation service
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include "taler_json_lib.h"
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_testing_lib.h"
      29             : #include "taler_mhd_lib.h"
      30             : 
      31             : /**
      32             :  * State for the oauth CMD.
      33             :  */
      34             : struct OAuthState
      35             : {
      36             : 
      37             :   /**
      38             :    * Handle to the "oauth" service.
      39             :    */
      40             :   struct MHD_Daemon *mhd;
      41             : 
      42             :   /**
      43             :    * Port to listen on.
      44             :    */
      45             :   uint16_t port;
      46             : };
      47             : 
      48             : 
      49             : struct RequestCtx
      50             : {
      51             :   struct MHD_PostProcessor *pp;
      52             :   char *code;
      53             :   char *client_id;
      54             :   char *redirect_uri;
      55             :   char *client_secret;
      56             : };
      57             : 
      58             : 
      59             : static void
      60           0 : append (char **target,
      61             :         const char *data,
      62             :         size_t size)
      63             : {
      64             :   char *tmp;
      65             : 
      66           0 :   if (NULL == *target)
      67             :   {
      68           0 :     *target = GNUNET_strndup (data,
      69             :                               size);
      70           0 :     return;
      71             :   }
      72           0 :   GNUNET_asprintf (&tmp,
      73             :                    "%s%.*s",
      74             :                    *target,
      75             :                    (int) size,
      76             :                    data);
      77           0 :   GNUNET_free (*target);
      78           0 :   *target = tmp;
      79             : }
      80             : 
      81             : 
      82             : static MHD_RESULT
      83           0 : handle_post (void *cls,
      84             :              enum MHD_ValueKind kind,
      85             :              const char *key,
      86             :              const char *filename,
      87             :              const char *content_type,
      88             :              const char *transfer_encoding,
      89             :              const char *data,
      90             :              uint64_t off,
      91             :              size_t size)
      92             : {
      93           0 :   struct RequestCtx *rc = cls;
      94             : 
      95             :   (void) kind;
      96             :   (void) filename;
      97             :   (void) content_type;
      98             :   (void) transfer_encoding;
      99             :   (void) off;
     100           0 :   if (0 == strcmp (key,
     101             :                    "code"))
     102           0 :     append (&rc->code,
     103             :             data,
     104             :             size);
     105           0 :   if (0 == strcmp (key,
     106             :                    "client_id"))
     107           0 :     append (&rc->client_id,
     108             :             data,
     109             :             size);
     110           0 :   if (0 == strcmp (key,
     111             :                    "redirect_uri"))
     112           0 :     append (&rc->redirect_uri,
     113             :             data,
     114             :             size);
     115           0 :   if (0 == strcmp (key,
     116             :                    "client_secret"))
     117           0 :     append (&rc->client_secret,
     118             :             data,
     119             :             size);
     120           0 :   return MHD_YES;
     121             : }
     122             : 
     123             : 
     124             : /**
     125             :  * A client has requested the given url using the given method
     126             :  * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
     127             :  * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
     128             :  * must call MHD callbacks to provide content to give back to the
     129             :  * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
     130             :  * #MHD_HTTP_NOT_FOUND, etc.).
     131             :  *
     132             :  * @param cls argument given together with the function
     133             :  *        pointer when the handler was registered with MHD
     134             :  * @param connection the connection being handled
     135             :  * @param url the requested url
     136             :  * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
     137             :  *        #MHD_HTTP_METHOD_PUT, etc.)
     138             :  * @param version the HTTP version string (i.e.
     139             :  *        MHD_HTTP_VERSION_1_1)
     140             :  * @param upload_data the data being uploaded (excluding HEADERS,
     141             :  *        for a POST that fits into memory and that is encoded
     142             :  *        with a supported encoding, the POST data will NOT be
     143             :  *        given in upload_data and is instead available as
     144             :  *        part of MHD_get_connection_values(); very large POST
     145             :  *        data *will* be made available incrementally in
     146             :  *        @a upload_data)
     147             :  * @param[in,out] upload_data_size set initially to the size of the
     148             :  *        @a upload_data provided; the method must update this
     149             :  *        value to the number of bytes NOT processed;
     150             :  * @param[in,out] con_cls pointer that the callback can set to some
     151             :  *        address and that will be preserved by MHD for future
     152             :  *        calls for this request; since the access handler may
     153             :  *        be called many times (i.e., for a PUT/POST operation
     154             :  *        with plenty of upload data) this allows the application
     155             :  *        to easily associate some request-specific state.
     156             :  *        If necessary, this state can be cleaned up in the
     157             :  *        global MHD_RequestCompletedCallback (which
     158             :  *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
     159             :  *        Initially, `*con_cls` will be NULL.
     160             :  * @return #MHD_YES if the connection was handled successfully,
     161             :  *         #MHD_NO if the socket must be closed due to a serious
     162             :  *         error while handling the request
     163             :  */
     164             : static MHD_RESULT
     165           0 : handler_cb (void *cls,
     166             :             struct MHD_Connection *connection,
     167             :             const char *url,
     168             :             const char *method,
     169             :             const char *version,
     170             :             const char *upload_data,
     171             :             size_t *upload_data_size,
     172             :             void **con_cls)
     173             : {
     174           0 :   struct RequestCtx *rc = *con_cls;
     175             :   unsigned int hc;
     176             :   json_t *body;
     177             : 
     178             :   (void) cls;
     179             :   (void) version;
     180           0 :   if (0 == strcasecmp (method,
     181             :                        MHD_HTTP_METHOD_GET))
     182             :   {
     183           0 :     body = GNUNET_JSON_PACK (
     184             :       GNUNET_JSON_pack_string (
     185             :         "status",
     186             :         "success"),
     187             :       GNUNET_JSON_pack_object_steal (
     188             :         "data",
     189             :         GNUNET_JSON_PACK (
     190             :           GNUNET_JSON_pack_string ("id",
     191             :                                    "XXXID12345678"))));
     192           0 :     return TALER_MHD_reply_json_steal (connection,
     193             :                                        body,
     194             :                                        MHD_HTTP_OK);
     195             :   }
     196           0 :   if (0 != strcasecmp (method,
     197             :                        MHD_HTTP_METHOD_POST))
     198             :   {
     199           0 :     GNUNET_break (0);
     200           0 :     return MHD_NO;
     201             :   }
     202           0 :   if (NULL == rc)
     203             :   {
     204           0 :     rc = GNUNET_new (struct RequestCtx);
     205           0 :     *con_cls = rc;
     206           0 :     rc->pp = MHD_create_post_processor (connection,
     207             :                                         4092,
     208             :                                         &handle_post,
     209             :                                         rc);
     210           0 :     return MHD_YES;
     211             :   }
     212           0 :   if (0 != *upload_data_size)
     213             :   {
     214             :     MHD_RESULT ret;
     215             : 
     216           0 :     ret = MHD_post_process (rc->pp,
     217             :                             upload_data,
     218             :                             *upload_data_size);
     219           0 :     *upload_data_size = 0;
     220           0 :     return ret;
     221             :   }
     222             : 
     223             : 
     224             :   /* NOTE: In the future, we MAY want to distinguish between
     225             :      the different URLs and possibly return more information.
     226             :      For now, just do the minimum: implement the main handler
     227             :      that checks the code. */
     228           0 :   if ( (NULL == rc->code) ||
     229           0 :        (NULL == rc->client_id) ||
     230           0 :        (NULL == rc->redirect_uri) ||
     231           0 :        (NULL == rc->client_secret) )
     232             :   {
     233           0 :     GNUNET_break (0);
     234           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     235             :                 "Bad request to Oauth faker: `%s' with %s/%s/%s/%s\n",
     236             :                 url,
     237             :                 rc->code,
     238             :                 rc->client_id,
     239             :                 rc->redirect_uri,
     240             :                 rc->client_secret);
     241           0 :     return MHD_NO;
     242             :   }
     243           0 :   if (0 != strcmp (rc->client_id,
     244             :                    "taler-exchange"))
     245             :   {
     246           0 :     body = GNUNET_JSON_PACK (
     247             :       GNUNET_JSON_pack_string ("error",
     248             :                                "unknown_client"),
     249             :       GNUNET_JSON_pack_string ("error_description",
     250             :                                "only 'taler-exchange' is allowed"));
     251           0 :     hc = MHD_HTTP_NOT_FOUND;
     252             :   }
     253           0 :   else if (0 != strcmp (rc->client_secret,
     254             :                         "exchange-secret"))
     255             :   {
     256           0 :     body = GNUNET_JSON_PACK (
     257             :       GNUNET_JSON_pack_string ("error",
     258             :                                "invalid_client_secret"),
     259             :       GNUNET_JSON_pack_string ("error_description",
     260             :                                "only 'exchange-secret' is valid"));
     261           0 :     hc = MHD_HTTP_FORBIDDEN;
     262             :   }
     263             :   else
     264             :   {
     265           0 :     if (0 != strcmp (rc->code,
     266             :                      "pass"))
     267             :     {
     268           0 :       body = GNUNET_JSON_PACK (
     269             :         GNUNET_JSON_pack_string ("error",
     270             :                                  "invalid_grant"),
     271             :         GNUNET_JSON_pack_string ("error_description",
     272             :                                  "only 'pass' shall pass"));
     273           0 :       hc = MHD_HTTP_FORBIDDEN;
     274             :     }
     275             :     else
     276             :     {
     277           0 :       body = GNUNET_JSON_PACK (
     278             :         GNUNET_JSON_pack_string ("access_token",
     279             :                                  "good"),
     280             :         GNUNET_JSON_pack_string ("token_type",
     281             :                                  "bearer"),
     282             :         GNUNET_JSON_pack_uint64 ("expires_in",
     283             :                                  3600),
     284             :         GNUNET_JSON_pack_string ("refresh_token",
     285             :                                  "better"));
     286           0 :       hc = MHD_HTTP_OK;
     287             :     }
     288             :   }
     289           0 :   return TALER_MHD_reply_json_steal (connection,
     290             :                                      body,
     291             :                                      hc);
     292             : }
     293             : 
     294             : 
     295             : static void
     296           0 : cleanup (void *cls,
     297             :          struct MHD_Connection *connection,
     298             :          void **con_cls,
     299             :          enum MHD_RequestTerminationCode toe)
     300             : {
     301           0 :   struct RequestCtx *rc = *con_cls;
     302             : 
     303             :   (void) cls;
     304             :   (void) connection;
     305             :   (void) toe;
     306           0 :   if (NULL == rc)
     307           0 :     return;
     308           0 :   GNUNET_free (rc->code);
     309           0 :   GNUNET_free (rc->client_id);
     310           0 :   GNUNET_free (rc->redirect_uri);
     311           0 :   GNUNET_free (rc->client_secret);
     312           0 :   GNUNET_free (rc);
     313             : }
     314             : 
     315             : 
     316             : /**
     317             :  * Run the command.
     318             :  *
     319             :  * @param cls closure.
     320             :  * @param cmd the command to execute.
     321             :  * @param is the interpreter state.
     322             :  */
     323             : static void
     324           0 : oauth_run (void *cls,
     325             :            const struct TALER_TESTING_Command *cmd,
     326             :            struct TALER_TESTING_Interpreter *is)
     327             : {
     328           0 :   struct OAuthState *oas = cls;
     329             : 
     330             :   (void) cmd;
     331           0 :   oas->mhd = MHD_start_daemon (MHD_USE_AUTO_INTERNAL_THREAD,
     332           0 :                                oas->port,
     333             :                                NULL, NULL,
     334             :                                &handler_cb, oas,
     335             :                                MHD_OPTION_NOTIFY_COMPLETED, &cleanup, NULL,
     336             :                                NULL);
     337           0 :   TALER_TESTING_interpreter_next (is);
     338           0 : }
     339             : 
     340             : 
     341             : /**
     342             :  * Cleanup the state from a "oauth" CMD, and possibly cancel a operation
     343             :  * thereof.
     344             :  *
     345             :  * @param cls closure.
     346             :  * @param cmd the command which is being cleaned up.
     347             :  */
     348             : static void
     349           0 : oauth_cleanup (void *cls,
     350             :                const struct TALER_TESTING_Command *cmd)
     351             : {
     352           0 :   struct OAuthState *oas = cls;
     353             : 
     354             :   (void) cmd;
     355           0 :   if (NULL != oas->mhd)
     356             :   {
     357           0 :     MHD_stop_daemon (oas->mhd);
     358           0 :     oas->mhd = NULL;
     359             :   }
     360           0 :   GNUNET_free (oas);
     361           0 : }
     362             : 
     363             : 
     364             : struct TALER_TESTING_Command
     365           0 : TALER_TESTING_cmd_oauth (const char *label,
     366             :                          uint16_t port)
     367             : {
     368             :   struct OAuthState *oas;
     369             : 
     370           0 :   oas = GNUNET_new (struct OAuthState);
     371           0 :   oas->port = port;
     372             :   {
     373           0 :     struct TALER_TESTING_Command cmd = {
     374             :       .cls = oas,
     375             :       .label = label,
     376             :       .run = &oauth_run,
     377             :       .cleanup = &oauth_cleanup,
     378             :     };
     379             : 
     380           0 :     return cmd;
     381             :   }
     382             : }
     383             : 
     384             : 
     385             : /* end of testing_api_cmd_oauth.c */

Generated by: LCOV version 1.14