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.
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.
TBC.
In this guide’s shell-session fragments, the command prompt shows two pieces of information:
$user
vs root
, and ending character $
vs #
).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:
python3-sphinx-rtd-theme
on Debian-based systems (for GNUnet documentation support, can be
omitted if GNUnet is configured with --disable-documentation
)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-13
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.
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.
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.
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 stable main
Next, you must import the Taler Systems SA public package signing key into your keyring and update the package lists:
# wget -P /etc/apt/keyrings/ \
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.
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.
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 Kinetic.
A typical /etc/apt/sources.list.d/taler.list
file for this setup
would look like this:
deb [signed-by=/etc/apt/keysrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ stable main
The last line is crucial, as it adds the GNU Taler packages.
Next, you must import the Taler Systems SA public package signing key into your keyring and update the package lists:
# wget -P /etc/apt/keyrings/ \
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.
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.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
.
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.conf
, thus making /etc/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:
- by defining them under a
[paths]
section:[paths] TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data .. [section-x] path-x = ${TALER_DEPLOYMENT_SHARED}/x
- 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/
.
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.
- 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.- 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.
[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.
The exchange has an endpoint “/terms” to return the terms of service (in legal language) of the Challenger operator.
To configure the terms of service response, there are two options
in the [challenger]
section:
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 challenger-httpd
process.The TERMS_DIR
directory structure must follow a particular layout.
First, inside of TERMS_DIR
, there should be sub-directories using
two-letter language codes like “en”, “de”, or “jp”. Each of these
directories would then hold translations of the current terms of
service into the respective language. Empty directories are
permitted in case translations are not available.
Then, inside each language directory, files with the name of the
value set as the TERMS_ETAG
must be provided. The extension of
each of the files should be typical for the respective mime type.
The set of supported mime types is currently hard-coded in the
exchange, and includes HTML, PDF and TXT files. If other files are
present, Challenger may show a warning on startup.
A sample file structure for a TERMS_ETAG
of “v1” would be:
If the user requests an HTML format with language preferences “fr” followed by “en”,
Challenger would return TERMS_DIR/en/v1.html
lacking an HTML version in
French.
The access credentials for the Challenger database are configured in
/etc/challenger/challenger.conf
. Currently, only PostgreSQL is
supported as a database backend.
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:
[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
..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`.
This chapter describes how to deploy Challenger once the basic installation and configuration are completed.
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 maskUNIXPATH
(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.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
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
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:
# 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.
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
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
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:
[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"
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:
$ taler-exchange-dbinit --reset
However, running this command will result in all data in the database being lost.