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