taler-merchant-httpd_post-private-token.c (6232B)
1 /* 2 This file is part of GNU Taler 3 (C) 2023, 2025 Taler Systems SA 4 5 GNU Taler is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation; either version 3, 8 or (at your option) any later version. 9 10 GNU 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, 17 see <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file src/backend/taler-merchant-httpd_post-private-token.c 22 * @brief implementing POST /instances/$ID/token request handling 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "taler-merchant-httpd_post-private-token.h" 27 #include "taler-merchant-httpd_auth.h" 28 #include "taler-merchant-httpd_helper.h" 29 #include "taler-merchant-httpd_mfa.h" 30 #include <taler/taler_json_lib.h> 31 #include "merchant-database/insert_login_token.h" 32 33 34 /** 35 * Default duration for the validity of a login token. 36 */ 37 #define DEFAULT_DURATION GNUNET_TIME_UNIT_DAYS 38 39 40 enum MHD_Result 41 TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh, 42 struct MHD_Connection *connection, 43 struct TMH_HandlerContext *hc) 44 { 45 struct TMH_MerchantInstance *mi = hc->instance; 46 json_t *jtoken = hc->request_body; 47 const char *scope; 48 const char *description; 49 enum TMH_AuthScope iscope = TMH_AS_NONE; 50 bool refreshable = false; 51 struct TALER_MERCHANTDB_LoginTokenP btoken; 52 struct GNUNET_TIME_Relative duration 53 = DEFAULT_DURATION; 54 struct GNUNET_TIME_Timestamp expiration_time; 55 struct GNUNET_JSON_Specification spec[] = { 56 GNUNET_JSON_spec_string ("scope", 57 &scope), 58 GNUNET_JSON_spec_mark_optional ( 59 GNUNET_JSON_spec_relative_time ("duration", 60 &duration), 61 NULL), 62 GNUNET_JSON_spec_mark_optional ( 63 GNUNET_JSON_spec_bool ("refreshable", 64 &refreshable), 65 NULL), 66 GNUNET_JSON_spec_mark_optional ( 67 GNUNET_JSON_spec_string ("description", 68 &description), 69 NULL), 70 GNUNET_JSON_spec_end () 71 }; 72 enum GNUNET_DB_QueryStatus qs; 73 74 { 75 enum GNUNET_GenericReturnValue res; 76 77 res = TALER_MHD_parse_json_data (connection, 78 jtoken, 79 spec); 80 if (GNUNET_OK != res) 81 return (GNUNET_NO == res) ? MHD_YES : MHD_NO; 82 } 83 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 84 &btoken, 85 sizeof (btoken)); 86 expiration_time = GNUNET_TIME_relative_to_timestamp (duration); 87 { 88 char *tmp_scope; 89 char *scope_prefix; 90 char *scope_suffix; 91 92 tmp_scope = GNUNET_strdup (scope); 93 scope_prefix = strtok (tmp_scope, 94 ":"); 95 scope_suffix = strtok (NULL, 96 ":"); 97 /* We allow <SCOPE>:REFRESHABLE syntax */ 98 if ( (NULL != scope_suffix) && 99 (0 == strcasecmp (scope_suffix, 100 "refreshable"))) 101 refreshable = true; 102 iscope = TMH_get_scope_by_name (scope_prefix); 103 if (TMH_AS_NONE == iscope) 104 { 105 GNUNET_break_op (0); 106 GNUNET_free (tmp_scope); 107 return TALER_MHD_reply_with_ec (connection, 108 TALER_EC_GENERIC_PARAMETER_MALFORMED, 109 "scope"); 110 } 111 GNUNET_free (tmp_scope); 112 } 113 if (refreshable) 114 iscope |= TMH_AS_REFRESHABLE; 115 if (! TMH_scope_is_subset (hc->auth_scope, 116 iscope)) 117 { 118 /* more permissions requested for the new token, not allowed */ 119 GNUNET_break_op (0); 120 return TALER_MHD_reply_with_ec (connection, 121 TALER_EC_GENERIC_TOKEN_PERMISSION_INSUFFICIENT, 122 NULL); 123 } 124 if (NULL == description) 125 { 126 description = ""; 127 } 128 129 { 130 enum GNUNET_GenericReturnValue ret = 131 TMH_mfa_check_simple (hc, 132 TALER_MERCHANT_MFA_CO_AUTH_TOKEN_CREATION, 133 mi); 134 135 if (GNUNET_OK != ret) 136 { 137 return (GNUNET_NO == ret) 138 ? MHD_YES 139 : MHD_NO; 140 } 141 } 142 143 qs = TALER_MERCHANTDB_insert_login_token (TMH_db, 144 mi->settings.id, 145 &btoken, 146 GNUNET_TIME_timestamp_get (), 147 expiration_time, 148 iscope, 149 description); 150 switch (qs) 151 { 152 case GNUNET_DB_STATUS_HARD_ERROR: 153 case GNUNET_DB_STATUS_SOFT_ERROR: 154 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 155 GNUNET_break (0); 156 return TALER_MHD_reply_with_ec (connection, 157 TALER_EC_GENERIC_DB_STORE_FAILED, 158 "insert_login_token"); 159 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 160 break; 161 } 162 163 { 164 char *tok; 165 enum MHD_Result ret; 166 char *val; 167 168 val = GNUNET_STRINGS_data_to_string_alloc (&btoken, 169 sizeof (btoken)); 170 GNUNET_asprintf (&tok, 171 RFC_8959_PREFIX "%s", 172 val); 173 GNUNET_free (val); 174 ret = TALER_MHD_REPLY_JSON_PACK ( 175 connection, 176 MHD_HTTP_OK, 177 GNUNET_JSON_pack_string ("access_token", 178 tok), 179 GNUNET_JSON_pack_string ("token", 180 tok), 181 GNUNET_JSON_pack_string ("scope", 182 scope), 183 GNUNET_JSON_pack_bool ("refreshable", 184 refreshable), 185 GNUNET_JSON_pack_timestamp ("expiration", 186 expiration_time)); 187 GNUNET_free (tok); 188 return ret; 189 } 190 } 191 192 193 /* end of taler-merchant-httpd_post-private-token.c */