challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

do_insert_token.c (3838B)


      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 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     = GNUNET_TIME_absolute_get ();
     39   struct GNUNET_TIME_Absolute ge
     40     = GNUNET_TIME_relative_to_absolute (token_expiration);
     41   struct GNUNET_TIME_Absolute ae
     42     = GNUNET_TIME_relative_to_absolute (address_expiration);
     43   struct GNUNET_PQ_QueryParam params[] = {
     44     GNUNET_PQ_query_param_auto_from_type (nonce),
     45     GNUNET_PQ_query_param_auto_from_type (token),
     46     GNUNET_PQ_query_param_absolute_time (&ge),
     47     GNUNET_PQ_query_param_absolute_time (&ae),
     48     GNUNET_PQ_query_param_absolute_time (&now),
     49     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 PIN.  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   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   return GNUNET_PQ_eval_prepared_non_select (ctx->conn,
     87                                              "do_insert_token",
     88                                              params);
     89 }