GeneNetwork Auth
This project is for the GeneNetwork Authentication/Authorisation server to be used across the entire suite of the GeneNetwork services.
Configuration
The recommended way to pass configuration values to the application is via a
configuration file passed in via the GN_AUTH_CONF
environment variable. This
variable simply holds the path to the configuration file, e.g.
export GN_AUTH_CONF="${HOME}/genenetwork/configs/gn_auth_conf.conf"
The settings in the file above will override the default settings.
NOTE: For development purposes, you can override any of the settings in the
default configuration or the GN_AUTH_CONF
file by setting an environment
variable of the same name as the variable you wish to override.
/Please note that this is included to help with debugging - you should not use this live./
Configuration Variables
Variable | Used By/For | Description |
---|---|---|
LOGLEVEL |
Logging system events | Useful for logging system events and debugging. The acceptable values are DEBUG , INFO , WARNING , ERROR and CRITICAL . The default value is WARNING which will log out all warnings, errors and critical conditions. |
SECRET_KEY |
Flask | Used by flask to securely sign session cookies. See https://flask.palletsprojects.com/en/2.3.x/config/#SECRET_KEY. This setting is mandatory. If not provided, the system will not start. It is not provided by default, on purpose, to force the end-user to provide the value and prevent subtle bugs that can be experienced (especially with sessions) if this value is not set up. It would also be a HUGE security hole to provide a default value for this setting. |
SQL_URI |
MariaDB connections | Used to connect to the MariaDB server |
AUTH_DB |
SQLite connections | Used to connect to the Authentication/Authorisation database |
AUTH_MIGRATIONS |
Migrations | Relative (to the repo root) path to the migration scripts for the auth(entic/oris)ation database |
OAUTH2_SCOPE |
Supported OAuth2 scope for the application. | This has some default values provided in the file gn_auth/settings.py in this repository. You could narrow the allowable scopes by overriding these. |
There are a few other variables we can set, if we want to customise, or troubleshoot token generation. These are:
Variable | Used By/For | Description |
---|---|---|
OAUTH2_ACCESS_TOKEN_GENERATOR |
Generating new access tokens. | A string value that points to the function that generates the access token. e.g. OAUTH2_ACCESS_TOKEN_GENERATOR='the_project.tokens.generate_token' . |
OAUTH2_REFRESH_TOKEN_GENERATOR |
Generating refresh tokens. | Similar to the OAUTH2_ACCESS_TOKEN_GENERATOR setting above, except this setting relates to the refresh token. |
OAUTH2_TOKEN_EXPIRES_IN |
Limiting token expiry time. | This can be set to limit the amount of time a token is valid for. It can be a dict object or import string. |
Installation
The recommended way to install the application is using GNU Guix[^gnu-guix]. You could, hypothetically, safely install and run the application using Python's Distutils, but we have not tested that (hence you'd be on your own).
The first step is to install GNU Guix[^gnu-guix] on your system. If you are already using some other Linux distribution, install Guix as a package manager on your system.
Once you have Guix installed on your computer, you can now start gn-auth in one of three ways:
- Using a development shell/environment (
guix shell ...
) - As a system container (mostly for deployments (
guix system container ...
)) - Using a guix profile
Guix Shell
This is the recommended way to start gn-auth if you intend to do any development on gn-auth. To do this, you need to be inside the gn-auth repository:
cd "${HOME}/genenetwork-projects/gn-auth"
guix shell --container --network \
--share=<path-to-shareable-directory>=<path-of-share-in-shell> \
--development --file=guix.scm
The --network
option allows the container to share the host network, and you
can access the application with something like "http://localhost:
The --development
option installs all the dependencies in the shell that you
need for development - including those which won't be in production but are
needed for dev-work.
The --share
and --expose
options are used to expose specific directories on
the host system to your container. The --expose
option exposes the specified
directory in read-only mode. You cannot write to such a share. The --share
option allows the shared directory to be writable from the shell.
The --share
and --expose
options can be repeated expose as many directories
to the shell as are needed.
The --container
option creates a container environment completely isolated
from the rest of your system. This is the recommended way to do your
development. Without the option, your host environment bleeds into your shell.
Since providing the --container
option isolates your shell, it means you will
not have access to some command in the host within the shell environment. A lot
of the times, this is a non-issue, and you can get by without them. If, however,
you find yourself in one of the vanishingly-small instances where you require
to leak your host environment into your development environment, then you know
to simply omit the option.
Guix System Container
Guix system containers are an entirely different beast from the development containers we mentioned in the section above.
You can think of guix shell --container ...
invocation as simply creating an
isolated shell environment, but otherwise using the same kernel as the rest of
your host system.
A guix system container, guix system container ...
on the other hand, creates
a proper system container complete with it's own separate operating-system
kernel.
System containers are useful for deployment, not so much day-to-day development.
Guix Profile
You can install gn-auth package into a profile with something like:
guix package --install-from-file=guix.scm --profile="${HOME}/opt/gn-auth"
You can then source that profile to run the application:
source ~/opt/gn-auth/etc/profile
flask run --port=8081
Migrations
NOTE: Do not create migration scripts manually. Use the processes indicated below.
Authentication/Authorisation Migrations
The migration scripts for the authentication and authorisation system are in the migrations/auth folder in the root of the repository.
To create an new migration script for the, do:
$ yoyo new -m "<description of the migration>" ./migrations/auth/
The command will ask whether you want to save the migration configuration, e.g.
$ yoyo new --config=yoyo.auth.ini -m "testing a new migration"
Error: could not open editor!
Created file ./migrations/auth/20221103_02_HBzwk-testing-a-new-migration.py
Save migration configuration to yoyo.ini?
This is saved in plain text and contains your database password.
Answering 'y' means you do not have to specify the migration source or database connection for future runs [yn]:
If you specify y
then a file named yoyo.ini will be created in your current working directory, and you can refer to it to avoid providing the ./migrations/auth
explicitly.
Now you can open and edit the scripts to provide the appropriate SQL statements to update or rollback your schema.
Running the Migrations
To apply the migrations, you can do something like:
$ yoyo apply --database="sqlite:////tmp/test-auth.db" ./migrations/auth/
[20221103_01_js9ub-initialise-the-auth-entic-oris-ation-database]
Shall I apply this migration? [Ynvdaqjk?]: Y
[20221103_02_sGrIs-create-user-credentials-table]
Shall I apply this migration? [Ynvdaqjk?]: Y
[20221108_01_CoxYh-create-the-groups-table]
Shall I apply this migration? [Ynvdaqjk?]: Y
[20221108_02_wxTr9-create-privileges-table]
Shall I apply this migration? [Ynvdaqjk?]: Y
...
If you have previously initialised the yoyo config file, you can put the database uri in the configuration file and just provide it to avoid the prompt to save the configuration.
As a convenience, and to enable the CI/CD to apply the migrations automatically, I have provided a flask cli command that can be run with:
$ export FLASK_APP=wsgi.py
$ flask apply-migrations
This expects that the following two configuration variables are set in the application:
AUTH_MIGRATIONS
: path to the migration scriptsAUTH_DB
: path to the sqlite database file (will be created if absent)
To enable you to run the OAuth2 server without HTTPS, you need to setup the following environment variable(s):
export AUTHLIB_INSECURE_TRANSPORT=true
: Allows you to run the Authlib server without HTTPS on your development machine.
Running
Development
For initial set up, you need a custom configuration file that will contain custom local_settings. At minimum it can contain:
# contents for local_settings saved at /absolute/path/to/local_settings_file.conf
SQL_URI = "mysql://user:password@localhost/db_name" # mysql uri
AUTH_DB = "/absolute/path/to/auth.db/" # path to sqlite db file
# path to file containings SECRETS key.
# Note: this path is also used to determine the jwks location
GN_AUTH_SECRETS = "/home/rookie/gn_data/gn2_files/secrets.conf"
Here's an example secrets.conf
file:
SECRET_KEY = "qQIrgiK29kXZU6v8D09y4uw_sk8I4cqgNZniYUrRoUk"
and you set up the oauth clients using:
export FLASK_DEBUG=1 AUTHLIB_INSECURE_TRANSPORT=1 OAUTHLIB_INSECURE_TRANSPORT=1 FLASK_APP=gn_auth/wsgi
export GN_AUTH_CONF=/absolute/path/to/local_settings_file.conf
# this sets up a user and client
flask init-dev-clients --client-uri http://localhost:gn2_port_number
To run the application during development:
export FLASK_DEBUG=1
export FLASK_APP="wsgi.py"
export AUTHLIB_INSECURE_TRANSPORT=true
export GN_AUTH_CONF="/absolute/path/to/local_settings_file.conf"
flask run --port=8081
You can test this by attemptiong to log in to your local GN2 using credentials
defined by the dummy user you set up (see the function __init_dev_users__
in
/gn_auth/wsgi.py
).
Production
You can run the application on production with GUnicorn with something like:
gunicorn --bind 0.0.0.0:8081 --workers 6 --keep-alive 6000 --max-requests 10 \
--max-requests-jitter 5 --timeout 1200 gn_auth.wsgi:app
Checks
Running checks ensures the code is good, and the application actually does what it is expected to do.
The checks we do are - Lint-checks - Type-checks - Unit tests
Linting
pylint *py tests gn_auth scripts
Type-Checking
mypy --show-error-codes .
Running Tests
export AUTHLIB_INSECURE_TRANSPORT=true
pytest -k unit_test
OAuth2
This application acts as an OAuth2 server, allowing the client applications to authenticate and access the API endpoints with the appropriate authorisation levels.
[^gnu-guix]: We consider the use of GNU Guix as a package manager in this documentation, but there is nothing preventing you from using it as your operating system of choice for the entire system should you so choose.