9. Challenger Operator Manual

9.1. Introduction

9.1.1. 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.

9.1.2. 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.

9.1.3. Architecture overview

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

_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.

9.2. 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 #).

9.2.1. 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.

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:

  • “Sphinx RTD Theme” Python package aka python3-sphinx-rtd-theme on Debian-based systems (for GNUnet documentation support, can be omitted if GNUnet is configured with --disable-documentation)

  • libsqlite3 >= 3.16.2

  • GNU libunistring >= 0.9.3

  • libcurl >= 7.26 (or libgnurl >= 7.26)

  • libqrencode >= 4.0.0 (Taler merchant only)

  • GNU libgcrypt >= 1.6 (1.10 or later highly recommended)

  • libsodium >= 1.0

  • libargon2 >= 20171227

  • libjansson >= 2.7

  • PostgreSQL >= 15, including libpq

  • GNU libmicrohttpd >= 0.9.71

  • GNUnet >= 0.20 (from source tarball)

  • Python3 with jinja2

If you are on Debian stable or later, the following command may help you install these dependencies:

# apt-get install \
  libqrencode-dev \
  libsqlite3-dev \
  libltdl-dev \
  libunistring-dev \
  libsodium-dev \
  libargon2-dev \
  libcurl4-gnutls-dev \
  libgcrypt20-dev \
  libjansson-dev \
  libpq-dev \
  libmicrohttpd-dev \
  python3-jinja2 \
  postgresql-15

Before you install GNUnet, you must download and install the dependencies mentioned in the previous section, otherwise the build may succeed, but could fail to export some of the tooling required by GNU Taler.

On Ubuntu, you also need to install pkg-config, for example:

$ apt-get install pkg-config

To install GNUnet, unpack the tarball and change into the resulting directory, then proceed as follows:

$ ./configure [--prefix=GNUNETPFX]
$ # Each dependency can be fetched from non standard locations via
$ # the '--with-<LIBNAME>' option. See './configure --help'.
$ make
# make install
# ldconfig

If you did not specify a prefix, GNUnet will install to /usr/local, which requires you to run the last step as root. The ldconfig command (also run as root) makes the shared object libraries (.so files) visible to the various installed programs.

Please note that unlike most packages, if you want to run the make check command, you should run it only after having done make install. The latter ensures that necessary binaries are copied to the right place.

In any case, if make check fails, please consider filing a bug report with the Taler bug tracker.

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!

After installing GNUnet, unpack the GNU Taler exchange tarball, change into the resulting directory, and proceed as follows:

$ ./configure [--prefix=EXCHANGEPFX] \
              [--with-gnunet=GNUNETPFX]
$ # Each dependency can be fetched from non standard locations via
$ # the '--with-<LIBNAME>' option. See './configure --help'.
$ make
# make install

If you did not specify a prefix, the exchange will install to /usr/local, which requires you to run the last step as root. You have to specify --with-gnunet=/usr/local if you installed GNUnet to /usr/local in the previous step.

TBD.

Please note that unlike most packages, if you want to run the make check command, you should run it only after having done make install. The latter ensures that necessary binaries are copied to the right place.

In any case, if make check fails, please consider filing a bug report with the Taler bug tracker.

9.2.2. Installing the Challenger binary packages on Debian

To install the GNU Taler Debian packages, first ensure that you have the right Debian distribution. At this time, the packages are built for Debian bookworm.

You need to add a file to import the GNU Taler packages. Typically, this is done by adding a file /etc/apt/sources.list.d/taler.list that looks like this:

deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/debian bookworm main

Next, you must import the Taler Systems SA public package signing key into your keyring and update the package lists:

# wget -O /etc/apt/keyrings/taler-systems.gpg \
    https://taler.net/taler-systems.gpg
# apt update

Note

You may want to verify the correctness of the Taler Systems SA key out-of-band.

Now your system is ready to install the official GNU Taler binary packages using apt.

To install the Challenger, you can now simply run:

# 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.

9.2.3. Installing the GNU Taler binary packages on Trisquel

To install the GNU Taler Trisquel packages, first ensure that you have the right Trisquel distribution. Packages are currently available for Trisquel GNU/Linux 10.0. Simply follow the same instructions provided for Ubuntu.

9.2.4. Installing the GNU Taler binary packages on Ubuntu

To install the GNU Taler Ubuntu packages, first ensure that you have the right Ubuntu distribution. At this time, the packages are built for Ubuntu Lunar and Ubuntu Jammy. Make sure to have universe in your /etc/apt/sources.list (after main) as we depend on some packages from Ubuntu universe.

A typical /etc/apt/sources.list.d/taler.list file for this setup would look like this for Ubuntu Lunar:

deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ lunar taler-lunar

For Ubuntu Mantic use this instead:

deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ mantic taler-mantic

For Ubuntu Noble use this instead:

deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ noble taler-noble

Next, you must import the Taler Systems SA public package signing key into your keyring and update the package lists:

# wget -O /etc/apt/keyrings/taler-systems.gpg \
    https://taler.net/taler-systems.gpg
# apt update

Note

You may want to verify the correctness of the Taler Systems key out-of-band.

Now your system is ready to install the official GNU Taler binary packages using apt.

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

# 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.

9.2.5. 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.

9.3. 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:

[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.

9.3.1. Configuration format

All GNU Taler components are designed to possibly share the same configuration files. When installing a GNU Taler component, the installation deploys default values in configuration files located at ${prefix}/share/taler/config.d/ where ${prefix} is the installation prefix. Different components must be installed to the same prefix.

In order to override these defaults, the user can write a custom configuration file and either pass it to the component at execution time using the -c option, or name it taler.conf and place it under $HOME/.config/ which is where components will look by default. Note that the systemd service files pass -c /etc/taler/taler.conf, thus making /etc/taler/taler.conf the primary location for the configuration.

A config file is a text file containing sections, and each section contains maps options to their values. Configuration files follow basically the INI syntax:

[section1]
value1 = string
value2 = 23

[section2]
value21 = string
value22 = /path22

Comments start with a hash (#). Throughout the configuration, it is possible to use $-substitution for options relating to names of files or directories. It is also possible to provide defaults values for those variables that are unset, by using the following syntax: ${VAR:-default}. There are two ways a user can set the value of $-prefixable variables:

  1. by defining them under a [paths] section:

    [paths]
    TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data
    ..
    [section-x]
    path-x = ${TALER_DEPLOYMENT_SHARED}/x
    
    
  2. or by setting them in the environment:

    $ export VAR=/x
    
    

The configuration loader will give precedence to variables set under [path] over environment variables.

The utility taler-config, which gets installed along with the exchange, can be used get and set configuration values without directly editing the configuration file. The option -f is particularly useful to resolve pathnames, when they use several levels of $-expanded variables. See taler-config --help.

The repository git://git.taler.net/deployment contains example code for generating configuration files under deployment/netzbon/.

9.3.2. 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.

/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.

9.3.4. Terms of Service

The service has an endpoint “/terms” to return the terms of service (in legal language) of the service operator. Client software show these terms of service to the user when the user is first interacting with the service. Terms of service are optional for experimental deployments, if none are configured, the service will return a simple statement saying that there are no terms of service available.

To configure the terms of service response, there are two options in the configuration file for the service:

  • TERMS_ETAG: The current “Etag” to return for the terms of service. This value must be changed whenever the terms of service are updated. A common value to use would be a version number. Note that if you change the TERMS_ETAG, you MUST also provide the respective files in TERMS_DIR (see below).

  • TERMS_DIR: The directory that contains the terms of service. The files in the directory must be readable to the service process.

9.3.5. Privacy Policy

The service has an endpoint “/pp” to return the terms privacy policy (in legal language) of the service operator. Clients should show the privacy policy to the user when the user explicitly asks for it, but it should not be shown by default. Privacy policies are optional for experimental deployments, if none are configured, the service will return a simple statement saying that there is no privacy policy available.

To configure the privacy policy response, there are two options in the configuration file for the service:

  • PRIVACY_ETAG: The current “Etag” to return for the privacy policy. This value must be changed whenever the privacy policy is updated. A common value to use would be a version number. Note that if you change the PRIVACY_ETAG, you MUST also provide the respective files in PRIVACY_DIR (see below).

  • PRIVACY_DIR: The directory that contains the privacy policy. The files in the directory must be readable to the service process.

9.3.8. Adding translations

Translations must be available in subdirectories locale/$LANGUAGE/LC_MESSAGES/$ETAG.po. To start translating, you first need to add a new language:

$ taler-terms-generator -i $ETAG -l $LANGUAGE

Here, $LANGUAGE should be a two-letter language code like de or fr. The command will generate a file locale/$LANGUAGE/LC_MESSAGES/$ETAG.po which contains each English sentence or paragraph in the original document and an initially empty translation. Translators should update the .po file. Afterwards, simply re-run

$ taler-terms-generator -i $ETAG

to make the current translation(s) available to the service.

Note

You must restart the service whenever adding or updating legal documents or their translations.

9.3.10. 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:

[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:

/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:

[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 challenger-dbinit(1).

9.4. Deployment

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

9.4.1. 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.

9.4.2. 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:

[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

9.4.3. 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:

# systemctl start challenger-httpd.service

9.4.4. 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. Challenger also does not allow multiple clients sharing the same 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:

# sudo -u challenger-httpd challenger-admin --add=$CLIENT_SECRET $CLIENT_REDIRECT_URI

Here, $CLIENT_SECRET is the client secret of OAuth 2.0 which will be used in various parts of the protocol to authenticate the client. It must begin with the “secret-token:” prefix of RFC 8959. The $CLIENT_REDIRECT_URI is the REDIRECT 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 $CLIENT_SECRET and the $CLIENT_REDIRECT_URI will form the foundation for the OAuth 2.0 configuration.

9.4.5. 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 $CLIENT_SECRET HTTP header to obtain a fresh $NONCE. It is (optionally) possible to pass an address in the body of the /setup POST request. In this case, Challenger will pre-populate the address of the KYC form with the given body. Here, the format of the body is address type-specific.

Note

By passing a flag read_only: true editing of the address in the SPA can be disabled. However, the backend currently does not enforce this (see #9349).

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:

/etc/taler-exchange/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
# Make sure to include the RFC 8959 prefix in "$SECRET"
KYC_OAUTH2_CLIENT_SECRET = "$SECRET"

9.4.6. 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:

$ challenger-dbinit

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

$ challenger-dbinit --garbagecollect

The Challenger database can be re-initialized using:

$ challenger-dbinit --reset

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