Line data Source code
1 : /*
2 : This file is part of GNU Taler
3 : (C) 2023 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_private-post-instances-ID-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_private-post-instances-ID-token.h"
27 : #include "taler-merchant-httpd_helper.h"
28 : #include <taler/taler_json_lib.h>
29 :
30 :
31 : /**
32 : * Default duration for the validity of a login token.
33 : */
34 : #define DEFAULT_DURATION GNUNET_TIME_UNIT_DAYS
35 :
36 : MHD_RESULT
37 15 : TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh,
38 : struct MHD_Connection *connection,
39 : struct TMH_HandlerContext *hc)
40 : {
41 15 : struct TMH_MerchantInstance *mi = hc->instance;
42 15 : json_t *jtoken = hc->request_body;
43 : const char *scope;
44 : const char *description;
45 15 : uint32_t iscope = TMH_AS_NONE;
46 15 : bool refreshable = false;
47 : struct TALER_MERCHANTDB_LoginTokenP btoken;
48 : struct GNUNET_TIME_Relative duration
49 15 : = DEFAULT_DURATION;
50 : struct GNUNET_TIME_Timestamp expiration_time;
51 : struct GNUNET_JSON_Specification spec[] = {
52 15 : GNUNET_JSON_spec_string ("scope",
53 : &scope),
54 15 : GNUNET_JSON_spec_mark_optional (
55 : GNUNET_JSON_spec_relative_time ("duration",
56 : &duration),
57 : NULL),
58 15 : GNUNET_JSON_spec_mark_optional (
59 : GNUNET_JSON_spec_bool ("refreshable",
60 : &refreshable),
61 : NULL),
62 15 : GNUNET_JSON_spec_mark_optional (
63 : GNUNET_JSON_spec_string ("description",
64 : &description),
65 : NULL),
66 15 : GNUNET_JSON_spec_end ()
67 : };
68 : enum GNUNET_DB_QueryStatus qs;
69 :
70 : {
71 : enum GNUNET_GenericReturnValue res;
72 :
73 15 : res = TALER_MHD_parse_json_data (connection,
74 : jtoken,
75 : spec);
76 15 : if (GNUNET_OK != res)
77 0 : return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
78 : }
79 15 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
80 : &btoken,
81 : sizeof (btoken));
82 15 : expiration_time = GNUNET_TIME_relative_to_timestamp (duration);
83 : {
84 : char *tmp_scope;
85 : char *scope_prefix;
86 : char *scope_suffix;
87 15 : tmp_scope = GNUNET_strdup (scope);
88 15 : scope_prefix = strtok (tmp_scope, ":");
89 15 : scope_suffix = strtok (NULL, ":");
90 :
91 : /* We allow <SCOPE>:REFRESHABLE syntax */
92 15 : if ((NULL != scope_suffix) &&
93 2 : (0 == strcasecmp (scope_suffix, "refreshable")))
94 2 : refreshable = true;
95 15 : iscope = TMH_get_scope_by_name (scope_prefix);
96 15 : if (TMH_AS_NONE == iscope)
97 : {
98 0 : GNUNET_break_op (0);
99 0 : GNUNET_free (tmp_scope);
100 0 : return TALER_MHD_reply_with_ec (connection,
101 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
102 : "scope");
103 : }
104 : }
105 15 : if (refreshable)
106 9 : iscope |= TMH_AS_REFRESHABLE;
107 15 : if (! TMH_scope_is_subset (hc->auth_scope, iscope))
108 : {
109 : /* more permissions requested for the new token, not allowed */
110 1 : GNUNET_break_op (0);
111 1 : return TALER_MHD_reply_with_ec (connection,
112 : TALER_EC_GENERIC_TOKEN_PERMISSION_INSUFFICIENT,
113 : NULL);
114 : }
115 14 : if (NULL == description)
116 : {
117 13 : description = "";
118 : }
119 14 : qs = TMH_db->insert_login_token (TMH_db->cls,
120 14 : mi->settings.id,
121 : &btoken,
122 : GNUNET_TIME_timestamp_get (),
123 : expiration_time,
124 : iscope,
125 : description);
126 14 : switch (qs)
127 : {
128 0 : case GNUNET_DB_STATUS_HARD_ERROR:
129 : case GNUNET_DB_STATUS_SOFT_ERROR:
130 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
131 0 : GNUNET_break (0);
132 0 : return TALER_MHD_reply_with_ec (connection,
133 : TALER_EC_GENERIC_DB_STORE_FAILED,
134 : "insert_login_token");
135 14 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
136 14 : break;
137 : }
138 :
139 : {
140 : char *tok;
141 : MHD_RESULT ret;
142 : char *val;
143 :
144 14 : val = GNUNET_STRINGS_data_to_string_alloc (&btoken,
145 : sizeof (btoken));
146 14 : GNUNET_asprintf (&tok,
147 : RFC_8959_PREFIX "%s",
148 : val);
149 14 : GNUNET_free (val);
150 14 : ret = TALER_MHD_REPLY_JSON_PACK (
151 : connection,
152 : MHD_HTTP_OK,
153 : GNUNET_JSON_pack_string ("access_token",
154 : tok),
155 : GNUNET_JSON_pack_string ("token",
156 : tok),
157 : GNUNET_JSON_pack_string ("scope",
158 : scope),
159 : GNUNET_JSON_pack_bool ("refreshable",
160 : refreshable),
161 : GNUNET_JSON_pack_timestamp ("expiration",
162 : expiration_time));
163 14 : GNUNET_free (tok);
164 14 : return ret;
165 : }
166 : }
167 :
168 :
169 : /* end of taler-merchant-httpd_private-post-instances-ID-token.c */
|