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