Line data Source code
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 18 : TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh,
42 : struct MHD_Connection *connection,
43 : struct TMH_HandlerContext *hc)
44 : {
45 18 : struct TMH_MerchantInstance *mi = hc->instance;
46 18 : json_t *jtoken = hc->request_body;
47 : const char *scope;
48 18 : const char *description = NULL;
49 18 : enum TMH_AuthScope iscope = TMH_AS_NONE;
50 18 : bool refreshable = false;
51 : struct TALER_MERCHANTDB_LoginTokenP btoken;
52 : struct GNUNET_TIME_Relative duration
53 18 : = DEFAULT_DURATION;
54 : struct GNUNET_TIME_Timestamp expiration_time;
55 : struct GNUNET_JSON_Specification spec[] = {
56 18 : GNUNET_JSON_spec_string ("scope",
57 : &scope),
58 18 : GNUNET_JSON_spec_mark_optional (
59 : GNUNET_JSON_spec_relative_time ("duration",
60 : &duration),
61 : NULL),
62 18 : GNUNET_JSON_spec_mark_optional (
63 : GNUNET_JSON_spec_bool ("refreshable",
64 : &refreshable),
65 : NULL),
66 18 : GNUNET_JSON_spec_mark_optional (
67 : GNUNET_JSON_spec_string ("description",
68 : &description),
69 : NULL),
70 18 : GNUNET_JSON_spec_end ()
71 : };
72 : enum GNUNET_DB_QueryStatus qs;
73 :
74 : {
75 : enum GNUNET_GenericReturnValue res;
76 :
77 18 : res = TALER_MHD_parse_json_data (connection,
78 : jtoken,
79 : spec);
80 18 : if (GNUNET_OK != res)
81 0 : return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
82 : }
83 18 : GNUNET_CRYPTO_random_block (&btoken,
84 : sizeof (btoken));
85 18 : expiration_time = GNUNET_TIME_relative_to_timestamp (duration);
86 : {
87 : char *tmp_scope;
88 : char *scope_prefix;
89 : char *scope_suffix;
90 :
91 18 : tmp_scope = GNUNET_strdup (scope);
92 18 : scope_prefix = strtok (tmp_scope,
93 : ":");
94 18 : scope_suffix = strtok (NULL,
95 : ":");
96 : /* We allow <SCOPE>:REFRESHABLE syntax */
97 18 : if ( (NULL != scope_suffix) &&
98 2 : (0 == strcasecmp (scope_suffix,
99 : "refreshable")))
100 2 : refreshable = true;
101 18 : iscope = TMH_get_scope_by_name (scope_prefix);
102 18 : if (TMH_AS_NONE == iscope)
103 : {
104 0 : GNUNET_break_op (0);
105 0 : GNUNET_free (tmp_scope);
106 0 : return TALER_MHD_reply_with_ec (connection,
107 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
108 : "scope");
109 : }
110 18 : GNUNET_free (tmp_scope);
111 : }
112 18 : if (refreshable)
113 12 : iscope |= TMH_AS_REFRESHABLE;
114 18 : if (! TMH_scope_is_subset (hc->auth_scope,
115 : iscope))
116 : {
117 : /* more permissions requested for the new token, not allowed */
118 1 : GNUNET_break_op (0);
119 1 : return TALER_MHD_reply_with_ec (connection,
120 : TALER_EC_GENERIC_TOKEN_PERMISSION_INSUFFICIENT,
121 : NULL);
122 : }
123 17 : if (NULL == description)
124 : {
125 16 : description = "";
126 : }
127 :
128 : {
129 : enum GNUNET_GenericReturnValue ret =
130 17 : TMH_mfa_check_simple (hc,
131 : TALER_MERCHANT_MFA_CO_AUTH_TOKEN_CREATION,
132 : mi);
133 :
134 17 : if (GNUNET_OK != ret)
135 : {
136 : return (GNUNET_NO == ret)
137 : ? MHD_YES
138 2 : : MHD_NO;
139 : }
140 : }
141 :
142 15 : qs = TALER_MERCHANTDB_insert_login_token (TMH_db,
143 15 : mi->settings.id,
144 : &btoken,
145 : GNUNET_TIME_timestamp_get (),
146 : expiration_time,
147 : iscope,
148 : description);
149 15 : switch (qs)
150 : {
151 0 : case GNUNET_DB_STATUS_HARD_ERROR:
152 : case GNUNET_DB_STATUS_SOFT_ERROR:
153 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
154 0 : GNUNET_break (0);
155 0 : return TALER_MHD_reply_with_ec (connection,
156 : TALER_EC_GENERIC_DB_STORE_FAILED,
157 : "insert_login_token");
158 15 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
159 15 : break;
160 : }
161 :
162 : {
163 : char *tok;
164 : enum MHD_Result ret;
165 : char *val;
166 :
167 15 : val = GNUNET_STRINGS_data_to_string_alloc (&btoken,
168 : sizeof (btoken));
169 15 : GNUNET_asprintf (&tok,
170 : RFC_8959_PREFIX "%s",
171 : val);
172 15 : GNUNET_free (val);
173 15 : 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 15 : GNUNET_free (tok);
187 15 : return ret;
188 : }
189 : }
190 :
191 :
192 : /* end of taler-merchant-httpd_post-private-token.c */
|