Line data Source code
1 : /*
2 : This file is part of Challenger
3 : Copyright (C) 2023 Taler Systems SA
4 :
5 : Challenger is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : Challenger is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : Challenger; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file src/challengerdb/do_insert_token.c
18 : * @brief Implementation of the do_insert_token function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <taler/taler_error_codes.h>
23 : #include <taler/taler_dbevents.h>
24 : #include <taler/taler_pq_lib.h>
25 : #include "do_insert_token.h"
26 : #include "pg_helper.h"
27 :
28 :
29 : enum GNUNET_DB_QueryStatus
30 11 : CHALLENGERDB_do_insert_token (struct CHALLENGERDB_PostgresContext *ctx,
31 : const struct CHALLENGER_ValidationNonceP *nonce,
32 : uint64_t client_id,
33 : const struct CHALLENGER_AccessTokenP *token,
34 : struct GNUNET_TIME_Relative token_expiration,
35 : struct GNUNET_TIME_Relative address_expiration)
36 : {
37 : struct GNUNET_TIME_Absolute now
38 11 : = GNUNET_TIME_absolute_get ();
39 : struct GNUNET_TIME_Absolute ge
40 11 : = GNUNET_TIME_relative_to_absolute (token_expiration);
41 : struct GNUNET_TIME_Absolute ae
42 11 : = GNUNET_TIME_relative_to_absolute (address_expiration);
43 11 : struct GNUNET_PQ_QueryParam params[] = {
44 11 : GNUNET_PQ_query_param_auto_from_type (nonce),
45 11 : GNUNET_PQ_query_param_auto_from_type (token),
46 11 : GNUNET_PQ_query_param_absolute_time (&ge),
47 11 : GNUNET_PQ_query_param_absolute_time (&ae),
48 11 : GNUNET_PQ_query_param_absolute_time (&now),
49 11 : GNUNET_PQ_query_param_uint64 (&client_id),
50 : GNUNET_PQ_query_param_end
51 : };
52 :
53 : /* Redemption must be atomic and one-shot (RFC 6749 4.1.2): consume the
54 : validation by deleting it as we mint the token, so the same authorization
55 : code cannot be replayed to mint additional tokens. A replay finds no
56 : matching validations row and thus inserts no token (NO_RESULTS), which the
57 : caller maps to 'invalid_grant'. The 'auth_attempts_left < 0' guard is what
58 : restricts us to validations that were actually *solved*: -1 is the sentinel
59 : challenger_do_validate_and_solve_pin() writes once the user entered the
60 : correct TAN. The 'address IS NOT NULL' guard additionally avoids violating
61 : the tokens.address NOT NULL constraint. Expiration and client are checked
62 : here as well and not merely by the get_validation_pkce() that preceded us:
63 : the two run in separate transactions, so anything we do not repeat is a
64 : TOCTOU window. */
65 11 : PREPARE (ctx,
66 : "do_insert_token",
67 : "WITH consumed AS ("
68 : " DELETE FROM validations"
69 : " WHERE nonce=$1"
70 : " AND address IS NOT NULL"
71 : " AND auth_attempts_left < 0"
72 : " AND expiration_time > $5"
73 : " AND client_serial_id=$6"
74 : " RETURNING address"
75 : ") INSERT INTO tokens"
76 : " (access_token"
77 : " ,address"
78 : " ,token_expiration_time"
79 : " ,address_expiration_time"
80 : ") SELECT"
81 : " $2"
82 : " ,address"
83 : " ,$3"
84 : " ,$4"
85 : " FROM consumed;");
86 11 : return GNUNET_PQ_eval_prepared_non_select (ctx->conn,
87 : "do_insert_token",
88 : params);
89 : }
|