summaryrefslogtreecommitdiff
path: root/taler-challenger-manual.rst
blob: f9d6a7932e89640f8c9a91d919e5407a32c3cd37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
..
  This file is part of GNU TALER.

  Copyright (C) 2023, 2024 Taler Systems SA

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free Software
  Foundation; either version 2.1, or (at your option) any later version.

  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>

  @author Christian Grothoff
  @author Florian Dold

Challenger Operator Manual
##########################

.. contents:: Table of Contents
  :depth: 2
  :local:


Introduction
============

About Challenger
----------------

Challenger is an OAuth 2.0-compatible address validation service.
By redirecting a user-agent to a Challenger service a client can
have Challenger validate that the user is able to receive messages
at a particular address and obtain that address via the ``/info``
endpoint.


About this manual
-----------------

This manual targets system administrators who want to install,
operate or integrate a challenger service.  To report issues
or learn about known limitations, please check our
`bug tracker <https://bugs.taler.net>`__.


Architecture overview
---------------------

The following picture gives an overview of the Challenger
architecture and the main interactions:

.. image:: images/challenger.png

Here, the *resource owner* is a user that is in control
of some *address* at a messaging service. This could be
an e-mail account, a mobile phone number (for SMS), or
a physical mail address (using the post office as the
messaging service).

The *resource owner* makes some request that requires
some *client* to be in need of address validation. The
*client* is registered with the Challenger OAuth 2.0
service and first authorizes an address validation to
be initiated. The client then redirects the resource
owner to the Challenger service. In step (2), the resource
owner submits the address that they claim to own.

The Challenger service then creates a TAN code and
submits it to the given address via a configurable
*helper script* that is specific to the type of address
being validated. When the resource owner submits the
correct TAN code in step (6), they are given a token
that they can provide to the client. Using this token
the client can then finally obtain the now validated
address in step (8).

Address data, TAN codes and meta-data such as the number
of failed attempts to submit a TAN code are recorded
in a Postgres database by the Challenger service.

.. _ChallengerInstallation:

Installation
============

In this guide's shell-session fragments, the command prompt shows two pieces
of information:

* Who is performing the command
  (``$user`` vs ``root``, and ending character ``$`` vs ``#``).


Installing from source
----------------------

The following instructions will show how to install libgnunetutil and
the core GNU Taler libraries from source.

The package sources can be find in our
`download directory <http://ftpmirror.gnu.org/taler/>`__.

GNU Taler components version numbers follow the ``MAJOR.MINOR.MICRO`` format.
The general rule for compatibility is that ``MAJOR`` and ``MINOR`` must match.
Exceptions to this general rule are documented in the release notes.
For example, Challenger 1.3.0 should be compatible with Taler exchange 1.4.x
as the MAJOR version matches.  A MAJOR version of 0 indicates experimental
development, and you are expected to always run all of the *latest* releases
together (no compatibility guarantees).

First, the following packages need to be installed before we can compile the
backend:

.. include:: frags/list-of-dependencies.rst

.. include:: frags/installing-gnunet.rst

.. include:: frags/install-before-check.rst

There is no need to actually run a GNUnet peer or a Taler exchange to use
Challenger -- all Challenger needs from GNUnet and Taler are a number of
headers and libraries!

.. include:: frags/installing-taler-exchange.rst


.. include:: frags/installing-challenger.rst

.. include:: frags/install-before-check.rst



Installing the Challenger binary packages on Debian
---------------------------------------------------

.. include:: frags/installing-debian.rst

To install the Challenger, you can now simply run:

.. code-block:: shell-session

   # apt install challenger

Note that the package does not perform any configuration work except for
setting up the various users and the systemd service scripts. You still must
configure at least the database, HTTP reverse proxy (typically with TLS
certificates) and the terms of service.

Installing the GNU Taler binary packages on Trisquel
----------------------------------------------------

.. include:: frags/installing-trisquel.rst

Installing the GNU Taler binary packages on Ubuntu
--------------------------------------------------

.. include:: frags/installing-ubuntu.rst

To install the Taler exchange, you can now simply run:

.. code-block:: shell-session

   # apt install challenger

Note that the package does not perform any configuration work except for
setting up the various users and the systemd service scripts. You still must
configure at least the database, HTTP reverse proxy (typically with TLS
certificates), and the terms of service.


Services, users, groups and file system hierarchy
-------------------------------------------------

The *challenger* package will use several system users
to compartmentalize different parts of the system:

* ``challenger-httpd``: runs the HTTP daemon with the core business logic.
* ``postgres``: runs the PostgreSQL database (from *postgresql* package).
* ``www-data``: runs the frontend HTTPS service with the TLS keys (from *nginx* package).

The package will deploy a systemd service files in
``/usr/lib/systemd/system/`` for Challenger:

* ``challenger-httpd.service``: the Challenger logic with the public REST API.


Configuration Fundamentals
==========================

This chapter provides fundamental details about the exchange configuration.

The configuration for all Taler components uses a single configuration file
as entry point: ``/etc/challenger/challenger.conf``.

System defaults are automatically loaded from files in
``/usr/share/challenger/config.d``.  These default files should never be modified.

The default configuration ``challenger.conf`` configuration file also includes all
configuration files in ``/etc/challenger/conf.d``.

To view the entire configuration annotated with the source of each configuration option, you
can use the ``challenger-config`` helper:


.. code-block:: shell-session

  [root@exchange-online]# challenger-config --diagnostics
  < ... annotated, full configuration ... >

.. warning::

  While ``challenger-config`` also supports rewriting configuration files, we strongly
  recommend to edit configuration files manually, as ``challenger-config`` does not
  preserve comments and, by default, rewrites ``/etc/challenger/challenger.conf``.

.. include:: frags/configuration-format.rst


Fundamental Setup: Address validation
-------------------------------------

Each challenger service is designed to validate one type of address. Possible
address types include:

* phone numbers (via SMS)
* e-mail addresses (via SMTP)
* mail addresses (via postal service)

In principle, additional types of addresses can easily be added by extending
the respective HTML and programs to send challenges to the new address type.

To make different types of address validations possible, the Challenger
configuration contains two configuration options.

(1) The ``ADDRESS_TYPE`` configuration option informs Challenger about the
    type of address it is expected to validate. It is returned as part of
    the OAuth 2.0 ``/info`` endpoint to the client, and is typically also
    used when deciding how to render the HTML form for address entry that is
    shown to the user.

(2) The ``AUTH_COMMAND`` configuration option specifies which command
    Challenger should run to send a challenge to an address. The actual
    address is given to this subcommand as the first argument (``$1``),
    while the text with the challenge is passed to standard input.
    The subcommand should terminate with a status code of 0 on success.

.. code-block:: ini
  :caption: /etc/challenger/challenger.conf

   [challenger]
   ADDRESS_TYPE = email
   AUTH_COMMAND = challenger-send-email.sh
   # ... rest of file ...

Challenger comes with ``AUTH_COMMAND`` shell scripts for sending e-mail, SMS
and postal mail. Note that for SMS and postal mail the Challenger scripts uses
third party services to actually send the SMS or print and mail the postal
mail. These third parties naturally charge money for their services, and thus
the Challenger administrator will need to add the respective credentials to
the SMS and postal mail scripts before they can function.  In any case, these
scripts should be primarily seen as *examples* on how to write authentication
commands.

.. note::

  We strongly welcome contributions for additional scripts with alternative
  providers or for new types of addresses.


Legal conditions for using the service
--------------------------------------

.. include:: frags/legal.rst

Database Configuration
----------------------

The access credentials for the Challenger database are configured in
``/etc/challenger/challenger.conf``.  Currently, only PostgreSQL is
supported as a database backend.

.. note::

   The **challenger-dbconfig** tool can be used to automate the database
   setup. When using the Debian/Ubuntu packages, the user should already have
   been created, so you can just run the tool without any arguments and should
   have a working database configuration.  Subsequently, you should still run
   **taler-challenger-dbinit** as the ``challenger-httpd`` user to
   initialize the database schema.


To create a database for Challenger on the local system, run:

.. code-block:: shell-session

  [root@exchange-online]# su - postgres
  [postgres@exchange-online]# createuser challenger-httpd
  [postgres@exchange-online]# createdb -O challenger-httpd challenger
  [postgres@exchange-online]# exit

This will create a ``challenger`` database owned by the ``taler-httpd`` user.
We will use that user later to perform database maintenance operations.

Assuming the above database setup, the database credentials to configure
in the configuration file would simply be:

.. code-block:: ini
  :caption: /etc/challenger/challenger.conf

  [challenger]
  DB = postgres

  [challenger-postgres]
  CONFIG = postgres:///challenger

If the database is run on a different host, please follow the instructions
from the PostgreSQL manual for configuring remote access.

After configuring the database credentials, the Challenger database needs
to be initialized with the following command:

.. code-block:: shell-session

  [root@exchange-online]# sudo -u challenger-httpd challenger-dbinit

.. note::

  To run this command, the user must have ``CREATE TABLE``, ``CREATE
  INDEX``, ``ALTER TABLE`` and (in the future possibly even) ``DROP TABLE``
  permissions.  Those permissions are only required for this step (which may
  have to be repeated when upgrading a deployment).  Afterwards, during
  normal operation, permissions to ``CREATE`` or ``ALTER`` tables are not
  required by Challenger and thus should not be granted.  For more
  information, see :doc:`manpages/challenger-dbinit.1`.


Deployment
==========

This chapter describes how to deploy Challenger once the basic installation
and configuration are completed.

.. _ChallengerServing:

Serving
-------

The Challenger can serve HTTP over both TCP and UNIX domain socket.

The following options are to be configured in the section ``[challenger]``:

-  ``SERVE``: Must be set to ``tcp`` to serve HTTP over TCP, or ``unix`` to serve
   HTTP over a UNIX domain socket.

-  ``PORT``: Set to the TCP port to listen on if ``SERVE`` is ``tcp``.

-  ``UNIXPATH``: Set to the UNIX domain socket path to listen on if ``SERVE`` is
   ``unix``.

- ``UNIXPATH_MODE``: Number giving the mode with the access permission mask
   for the ``UNIXPATH`` (i.e. 660 = ``rw-rw---``). Make sure to set it in such
   a way that your reverse proxy has permissions to access the UNIX domain
   socket.  The default (660) assumes that the reverse proxy is a member of
   the group under which the exchange HTTP server is running.

.. _ChallengerReverseProxy:

Reverse Proxy Setup
-------------------

By default, the ``challenger-httpd`` service listens for HTTP connections
on a UNIX domain socket.  To make the service publicly available, a reverse
proxy such as nginx should be used.  You must configure the reverse proxy
to use TLS as this is required by OAuth 2.0.

The ``challenger`` package ships with a sample configuration that can be
enabled in nginx:

.. code-block:: shell-session

  [root@exchange-online]# vim /etc/nginx/sites-available/challenger
  < ... customize configuration ... >
  [root@exchange-online]# ln -s /etc/nginx/sites-available/challenger \
                                /etc/nginx/sites-enabled/challenger
  [root@exchange-online]# systemctl reload nginx


Launching Challenger
--------------------

A running exchange requires starting the following processes:

-   ``challenger-httpd`` (needs database access)

The processes should be started via a hypervisor like
``systemd`` or ``gnunet-arm`` that automatically re-starts them should they
have terminated unexpectedly.  Furthermore, the hypervisor
*should* periodically re-start the service (say once per hour)
to limit Postgres database memory utilization.

.. note::

  The ``challenger-httpd`` does not ship with HTTPS enabled by default.
  It must thus be run behind an HTTPS reverse proxy that performs
  TLS termination on the same system.  Thus, it would typically be configured
  to listen on a UNIX domain socket.

Given proper packaging, all of the above are realized via a simple systemd
target. This enables Challenger to be properly started using a simple command:

.. code-block:: shell-session

  # systemctl start challenger-httpd.service


Authorizing clients
-------------------

Before clients can use Challenger, they must be explicitly configured. Each
client is identified via its OAuth 2.0 REDIRECT URI.  Thus, a client must have
exactly one REDIRECT URI

.. note::

  The OAuth 2.0 specification allows for a client to register
  zero or multiple REDIRECT URIs. However, zero is insecure
  as it creates an open redirector, and multiple REDIRECT URIs
  can trivially be implemented with Challenger by adding more
  clients.

You can add or remove clients at any time; the Challenger service does not
need to be running, but if it is you can still add or remove clients without
restarting the service.  To add (or remove) a client, you must use the
``challenger-admin`` command:

.. code-block:: shell-session

  # sudo -u challenger-httpd challenger-admin --add=$SECRET $REDIRECT_URI

Here, ``$SECRET`` is the client secret of OAuth 2.0 which will be used in
various parts of the protocol to authenticate the client.  The
``$REDIRECT_URI`` is the URI where the user-agent will be redirected to upon
completion of the process.  The ``challenger-admin`` command will
then output the *client ID*, which will be a unique positive number.
The first time you run the command, you will thus likely see:
``Client added. Client ID is: 1``.  This client ID, the ``$SECRET``
and the ``$REDIRECT_URI`` will form the foundation for the OAuth 2.0
configuration.


OAuth 2.0 integration
---------------------

When integrating Challenger into an OAuth 2.0 process, you need to provide the
three options from the previous section, but also the authorization, token and
info endpoints.  For Challenger, these are ``/authorize``, ``/token`` and
``/info``.  However, the ``/authorize`` endpoint is special, as it is actually
``/authorize/$NONCE`` where ``$NONCE`` is a nonce that must be first requested
by the client using the ``/setup/$CLIENT_ID`` endpoint!

.. note::

  This extra step prevents user-agents from (ab)using the Challenger service
  to send challenges to addresses even when there is no authorized client
  that desires address validation. This is an important feature as address
  validation could be expensive.

Thus, to generate the authorization URL, a client must first POST to
``/setup/$CLIENT_ID`` using their client secret in an ``Authorization: Bearer $SECRET``
HTTP header to obtain a fresh ``$NONCE``.

In the GNU Taler exchange configuration, this is indicated by appending
``#setup`` to the ``KYC_OAUTH2_AUTHORIZE_URL`` endpoint.  Be careful to quote
the URL, as ``#`` is otherwise interpreted as the beginning of a comment by
the configuration file syntax:

.. code-block:: ini
  :caption: /etc/taler/conf.d/exchange-oauth2.conf

  [kyc-provider-example-oauth2]
  LOGIC = oauth2
  # (generic options omitted)
  KYC_OAUTH2_AUTHORIZE_URL = "https://challenger.example.com/authorize#setup"
  KYC_OAUTH2_TOKEN_URL = "https://challenger.example.com/token"
  KYC_OAUTH2_INFO_URL = "https://challenger.example.com/info"
  KYC_OAUTH2_CLIENT_ID = 1
  KYC_OAUTH2_CLIENT_SECRET = "$SECRET"



Database management
-------------------

.. note::

  We advise to make good backups before experimenting with
  the database.

To update the Challenger database after upgrading to a newer
version of Challenger, you should simply re-run ``challenger-dbinit``.
Without further options, this command is expected to preserve
all data and only migrate the existing database to the latest
schema:

.. code-block:: console

   $ challenger-dbinit

To delete stale data from the Challenger database, you can use
garbage collection:

.. code-block:: console

   $ challenger-dbinit --garbagecollect


The Challenger database can be re-initialized using:

.. code-block:: console

   $ challenger-dbinit --reset

However, running this command will result in all data in the database
being lost.


.. _ChallengerCustomization:

Template Customization
======================

The Challenger service comes with various HTML templates that are shown to
guide users through the process. Challenger uses `C implementation of mustache
<https://gitlab.com/jobol/mustach>`__ as the templating engine.  This section
describes the various templates.  In general, the templates must be installed
to the ``share/challenger/templates/`` directory. The file names must be of
the form ``$NAME.$LANG.must`` where ``$NAME`` is the name of the template and
``$LANG`` is the 2-letter language code of the template. English templates
must exist and will be used as a fallback.  If the browser (user-agent) has
provided language preferences in the HTTP header and the respective language
exists, the correct language will be automatically served.

The following subsections give details about each of the templates. The
subsection title is the ``$NAME`` of the respective template.

.. _challenger_enter-address_type-form:

enter-$ADDRESS_TYPE-form
------------------------

These templates are used to ask the user to enter the address that challenger
is expected to validate. Here, ``$ADDRESS_TYPE`` will be replaced by the
``ADDRESS_TYPE`` configuration option in the ``[challenger]`` section of the
configuration file.  Typical values include ``address`` (for physical mailing
addresses), ``phone`` (for mobile phone numbers) and ``email`` (for email
addresses). For testing, ``file`` (where the TAN code is written into a local
file) is also supported.

The template is instantiated using the following information:

* restrictions: Object; map of keys (names of the fields of the
  address to be entered by the user) to objects with a "regex"
  (string) containing an extended Posix regular expression for
  allowed address field values, and a "hint"/"hint_i18n" giving
  a human-readable explanation to display if the value entered
  by the user does not match the regex. Keys that are not mapped
  to such an object have no restriction on the value provided by
  the user.  See "ADDRESS_RESTRICTIONS" in the challenger
  configuration.
* fix_address: boolean; indicates if the given address cannot be changed
  anymore, the form should be read-only if set to true.
* nonce: String; unique value identifying the challenge, should be shown
  to the user so that they can recognize it when they receive the TAN code
* last_address: Object; form values from the previous submission if available,
  details depend on the ``ADDRESS_TYPE``, should be used to pre-populate the form
* changes_left: Integer; number of times the address can still be changed,
  may or may not be shown to the user

.. _challenger_enter-tan-form:

enter-tan-form
--------------

This page should generate the HTML form for the user to enter the TAN code
that they received at the respective address.

The template is instantiated using the following information:

* nonce: String; unique value identifying the challenge, should be shown
  to the user so that they can match it to the TAN code they received
* attempts_left: Integer; how many more attempts are allowed, might be
  shown to the user, highlighting might be appropriate for low values
  such as 1 or 2 (the form will never be used if the value is zero)
* address: Object; the address that is being validated, might be shown
  or not
* transmitted: boolean; true if we just retransmitted the challenge,
  false if we sent a challenge recently and thus refused to transmit it
  again this time; might make a useful hint to the user
* next_tx_time: String; timestamp explaining when we would re-transmit
  the challenge the next time (at the earliest) if requested by the user


.. _challenger_invalid-pin:

invalid-pin
-----------

The user has provided an invalid TAN code (HTTP 403 Forbidden).

The template is instantiated using the following information:

* ec: Integer; numeric Taler error code, should be shown to indicate the
  error compactly for reporting to developers
* hint: String; human-readable Taler error code, should be shown for the
  user to understand the error
* addresses_left: Integer; how many times is the user still allowed to
  change the address; if 0, the user should not be shown a link to jump
  to the address entry form
* pin_transmissions_left: Integer; how many times might the PIN still
  be retransmitted
* auth_attempts_left: Integer; how many times might the user still try
  entering the PIN code
* exhausted: Bool; if true, the PIN was not even evaluated as the user
  previously exhausted the number of attempts
* no_challenge: Bool; if true, the PIN was not even evaluated as no
  challenge was ever issued (the user must have skipped the step of
  providing their address first!)

If both *pin_transmissions_left* and *auth_attempts_left* are zero, the link
to re-enter the PIN should be hidden and the user should only be allowed to
specify a different address. The form will never be generated if all three
values are zero. (Thus there is always at least one valid choice when the form
is shown.)


.. _challenger_validation-unknown:

validation-unknown
------------------

The user has tried to access a validation process that is not known to the
backend (HTTP 404 Not Found).

The template is instantiated using the following information:

* ec: Integer; numeric Taler error code, should be shown to indicate the
  error compactly for reporting to developers
* hint: String; human-readable Taler error code, should be shown for the
  user to understand the error
* detail: String; optional, extended human-readable text provided to elaborate
  on the error, should be shown to provide additional context

.. _challenger_invalid-request:

invalid-request
---------------

The request of the client is invalid (HTTP 400 Bad Request).

The template is instantiated using the following information:

* ec: Integer; numeric Taler error code, should be shown to indicate the
  error compactly for reporting to developers
* hint: String; human-readable Taler error code, should be shown for the
  user to understand the error
* detail: String; optional, extended human-readable text provided to elaborate
  on the error, should be shown to provide additional context

.. _challenger_internal-error:

internal-error
--------------

The service experienced an internal error (HTTP 500 Internal Server Error).

The template is instantiated using the following information:

* ec: Integer; numeric Taler error code, should be shown to indicate the
  error compactly for reporting to developers
* hint: String; human-readable Taler error code, should be shown for the
  user to understand the error
* detail: String; optional, extended human-readable text provided to elaborate
  on the error, should be shown to provide additional context