frosix

Multiparty signature service (experimental)
Log | Files | Refs | README | LICENSE

frosix_authorization_plugin_file.c (10030B)


      1 /*
      2   This file is part of Frosix
      3   Copyright (C) 2019 Anastasis SARL
      4 
      5   Frosix is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Frosix 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 Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Frosix; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file frosix_authorization_plugin_file.c
     18  * @brief authorization plugin file based for testing
     19  * @author Dominik Meister
     20  */
     21 #include "platform.h"
     22 #include "frosix_authorization_plugin.h"
     23 #include <taler/taler_mhd_lib.h>
     24 #include <gnunet/gnunet_db_lib.h>
     25 #include "frosix_database_lib.h"
     26 #include "frosix.h"
     27 
     28 /**
     29  * How many retries do we allow per code?
     30  */
     31 #define INITIAL_RETRY_COUNTER 3
     32 
     33 
     34 /**
     35  * Saves the state of a authorization process
     36  */
     37 struct FROSIX_AUTHORIZATION_State
     38 {
     39   /**
     40    * UUID of the challenge which is authorised
     41    */
     42   struct FROSIX_ChallengeIdP truth_uuid;
     43 
     44   /**
     45    * Code which is sent to the user (here saved into a file)
     46    */
     47   uint64_t code;
     48 
     49   /**
     50    * holds the truth information
     51    */
     52   char *filename;
     53 
     54   /**
     55    * closure
     56    */
     57   void *cls;
     58 };
     59 
     60 
     61 /**
     62  * Validate @a data is a well-formed input into the challenge method,
     63  * i.e. @a data is a well-formed phone number for sending an SMS, or
     64  * a well-formed e-mail address for sending an e-mail. Not expected to
     65  * check that the phone number or e-mail account actually exists.
     66  *
     67  * To be possibly used before issuing a 402 payment required to the client.
     68  *
     69  * @param cls closure with a `const struct ANASTASIS_AuthorizationContext *`
     70  * @param connection HTTP client request (for queuing response)
     71  * @param truth_mime mime type of @e data
     72  * @param data input to validate (i.e. is it a valid phone number, etc.)
     73  * @param data_length number of bytes in @a data
     74  * @return #GNUNET_OK if @a data is valid,
     75  *         #GNUNET_NO if @a data is invalid and a reply was successfully queued on @a connection
     76  *         #GNUNET_SYSERR if @a data invalid but we failed to queue a reply on @a connection
     77  */
     78 static enum GNUNET_GenericReturnValue
     79 file_validate (void *cls,
     80                struct MHD_Connection *connection,
     81                const char *truth_mime,
     82                const char *data,
     83                size_t data_length)
     84 {
     85   char *filename;
     86   bool flag;
     87 
     88   (void) cls;
     89   if (NULL == data)
     90     return GNUNET_SYSERR;
     91   filename = GNUNET_STRINGS_data_to_string_alloc (data,
     92                                                   data_length);
     93   flag = false;
     94   for (size_t i = 0; i<strlen (filename); i++)
     95   {
     96     if ( (filename[i] == ' ') ||
     97          (filename[i] == '/') )
     98     {
     99       flag = true;
    100       break;
    101     }
    102   }
    103   if (flag)
    104     return GNUNET_SYSERR;
    105   GNUNET_free (filename);
    106   return GNUNET_OK;
    107 }
    108 
    109 
    110 /**
    111  * Begin issuing authentication challenge to user based on @a data.
    112  * I.e. start to send SMS or e-mail or launch video identification.
    113  *
    114  * @param cls closure
    115  * @param trigger function to call when we made progress
    116  * @param trigger_cls closure for @a trigger
    117  * @param truth_uuid Identifier of the challenge, to be (if possible) included in the
    118  *             interaction with the user
    119  * @param code secret code that the user has to provide back to satisfy the challenge in
    120  *             the main anastasis protocol
    121  * @param data input to validate (i.e. is it a valid phone number, etc.)
    122  * @param data_length number of bytes in @a data
    123  * @return state to track progress on the authorization operation, NULL on failure
    124  */
    125 static struct FROSIX_AUTHORIZATION_State *
    126 file_start (void *cls,
    127             GNUNET_SCHEDULER_TaskCallback trigger,
    128             void *trigger_cls,
    129             const struct FROSIX_ChallengeIdP *truth_uuid,
    130             uint64_t code,
    131             const void *data,
    132             size_t data_length)
    133 {
    134   // const struct FROSIX_AuthorizationContext *ac = cls;
    135   struct FROSIX_AUTHORIZATION_State *as;
    136   // enum GNUNET_DB_QueryStatus qs;
    137   /* If the user can show this challenge code, this
    138      plugin is already happy (no additional
    139      requirements), so mark this challenge as
    140      already satisfied from the start. */
    141   /*qs = ac->db->mark_challenge_code_satisfied (ac->db->cls,
    142                                               truth_uuid,
    143                                               code);
    144   if (qs <= 0)
    145   {
    146     GNUNET_break (0);
    147     return NULL;
    148   }*/
    149   as = GNUNET_new (struct FROSIX_AUTHORIZATION_State);
    150   as->cls = cls;
    151   as->truth_uuid = *truth_uuid;
    152   as->code = code;
    153   as->filename = GNUNET_strndup (data,
    154                                  data_length);
    155   return as;
    156 }
    157 
    158 
    159 /**
    160  * Begin issuing authentication challenge to user based on @a data.
    161  * I.e. start to send SMS or e-mail or launch video identification.
    162  *
    163  * @param as authorization state
    164  * @param connection HTTP client request (for queuing response, such as redirection to video portal)
    165  * @return state of the request
    166  */
    167 static enum FROSIX_AUTHORIZATION_ChallengeResult
    168 file_challenge (struct FROSIX_AUTHORIZATION_State *as,
    169                 struct MHD_Connection *connection)
    170 {
    171   const char *mime;
    172   const char *lang;
    173 
    174   mime = MHD_lookup_connection_value (connection,
    175                                       MHD_HEADER_KIND,
    176                                       MHD_HTTP_HEADER_ACCEPT);
    177   if (NULL == mime)
    178     mime = "text/plain";
    179   lang = MHD_lookup_connection_value (connection,
    180                                       MHD_HEADER_KIND,
    181                                       MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
    182   if (NULL == lang)
    183     lang = "en";
    184   {
    185     FILE *f = fopen (as->filename, "w");
    186 
    187     if (NULL == f)
    188     {
    189       struct MHD_Response *resp;
    190       MHD_RESULT mres;
    191 
    192       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    193                                 "open",
    194                                 as->filename);
    195       resp = TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    196                                    "open");
    197       mres = MHD_queue_response (connection,
    198                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    199                                  resp);
    200       MHD_destroy_response (resp);
    201       if (MHD_YES != mres)
    202         return FROSIX_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
    203       return FROSIX_AUTHORIZATION_CRES_FAILED;
    204     }
    205 
    206     /* print challenge code to file */
    207     if (0 >= fprintf (f,
    208                       "%lu",
    209                       as->code))
    210     {
    211       struct MHD_Response *resp;
    212       MHD_RESULT mres;
    213 
    214       GNUNET_break (0 == fclose (f));
    215       resp = TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    216                                    "write");
    217       mres = MHD_queue_response (connection,
    218                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    219                                  resp);
    220       MHD_destroy_response (resp);
    221       if (MHD_YES != mres)
    222         return FROSIX_AUTHORIZATION_CRES_FAILED_REPLY_FAILED;
    223       return FROSIX_AUTHORIZATION_CRES_FAILED;
    224     }
    225     GNUNET_break (0 == fclose (f));
    226   }
    227 
    228   /* Build HTTP response */
    229   {
    230     struct MHD_Response *resp;
    231 
    232     if (TALER_MHD_xmime_matches (mime,
    233                                  "application/json"))
    234     {
    235       resp = TALER_MHD_MAKE_JSON_PACK (
    236         GNUNET_JSON_pack_string ("challenge_type",
    237                                  "FILE_WRITTEN"),
    238         GNUNET_JSON_pack_string ("filename",
    239                                  as->filename));
    240     }
    241     else
    242     {
    243       size_t response_size;
    244       char *response;
    245 
    246       response_size = GNUNET_asprintf (&response,
    247                                        ("Challenge written to file"));
    248       resp = MHD_create_response_from_buffer (response_size,
    249                                               response,
    250                                               MHD_RESPMEM_MUST_COPY);
    251       GNUNET_free (response);
    252       TALER_MHD_add_global_headers (resp);
    253       GNUNET_break (MHD_YES ==
    254                     MHD_add_response_header (resp,
    255                                              MHD_HTTP_HEADER_CONTENT_TYPE,
    256                                              "text/plain"));
    257     }
    258 
    259     {
    260       MHD_RESULT mres;
    261 
    262       mres = MHD_queue_response (connection,
    263                                  MHD_HTTP_OK,
    264                                  resp);
    265       MHD_destroy_response (resp);
    266       if (MHD_YES != mres)
    267         return FROSIX_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
    268       return FROSIX_AUTHORIZATION_CRES_SUCCESS;
    269     }
    270   }
    271 }
    272 
    273 
    274 /**
    275  * Free internal state associated with @a as.
    276  *
    277  * @param as state to clean up
    278  */
    279 static void
    280 file_cleanup (struct FROSIX_AUTHORIZATION_State *as)
    281 {
    282   GNUNET_free (as->filename);
    283   GNUNET_free (as);
    284 }
    285 
    286 
    287 /**
    288  * Initialize File based authorization plugin
    289  *
    290  * @param cls a configuration instance
    291  * @return NULL on error, otherwise a `struct FROSIX_AuthorizationPlugin`
    292  */
    293 void *
    294 libfrosix_plugin_authorization_file_init (void *cls)
    295 {
    296   const struct FROSIX_AuthorizationContext *ac = cls;
    297   struct FROSIX_AuthorizationPlugin *plugin;
    298 
    299   plugin = GNUNET_new (struct FROSIX_AuthorizationPlugin);
    300   plugin->cls = (void *) ac;
    301   plugin->retry_counter = INITIAL_RETRY_COUNTER;
    302   plugin->code_validity_period = GNUNET_TIME_UNIT_MINUTES;
    303   plugin->code_rotation_period = GNUNET_TIME_UNIT_MINUTES;
    304   plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES;
    305   plugin->validate = &file_validate;
    306   plugin->start = &file_start;
    307   plugin->challenge = &file_challenge;
    308   plugin->cleanup = &file_cleanup;
    309   return plugin;
    310 }
    311 
    312 
    313 /**
    314  * Unload authorization plugin
    315  *
    316  * @param cls a `struct FROSIX_AuthorizationPlugin`
    317  * @return NULL (always)
    318  */
    319 void *
    320 libfrosix_plugin_authorization_file_done (void *cls)
    321 {
    322   struct FROSIX_AuthorizationPlugin *plugin = cls;
    323 
    324   GNUNET_free (plugin);
    325   return NULL;
    326 }