-
Notifications
You must be signed in to change notification settings - Fork 26
Authenticated REST API
By default, the provisioner REST API will accept requests from anyone who pushes an appropriately structured HTTP request to the API's listening port. While we expect that OpenLI users will take appropriate steps to ensure that the API port is only reachable by trusted hosts on their network, we also (as of OpenLI 1.0.6) support some authentication methods that can be used to restrict API access to only those who have appropriate credentials.
At present, OpenLI supports the following authentication methods for the REST API:
- API keys
- Digest Authentication
The credentials for authorised users of the REST API are stored in an encrypted SQLite3 database on the host that is running the provisioner. The database is encrypted using sqlcipher and can therefore only be read or modified in conjunction with the passphrase that was set when the database was created.
The database only contains the one table: authcreds
, which is created with the following schema:
CREATE TABLE authcreds(username text primary key, digesthash blob not null, apikey text null);
A bash script is provided within the OpenLI source code that can be used to create the authentication database. The script can be found at src/provisioner/authsetup/openli-prov-authsetup.sh
and should be run as follows:
./src/provisioner/authsetup/openli-prov-authsetup.sh <passphrase> <database file>
This will create a new authentication database, stored in the file at <database file>
and protected using the passphrase passphrase
.
If you have installed OpenLI via a Debian or RPM package, then you will find that this script has already been run for you. Your database file will be located at /var/lib/openli/provauth.db
and the passphrase will be saved to /etc/openli/provauthdb.phrase
. You should record the passphrase somewhere safe (preferably somewhere other than on the provisioner host!) and then delete the /etc/openli/provauthdb.phrase
file as soon as possible.
Once you've created an authentication database, you can configure the OpenLI provisioner to use it by setting the following two options in its configuration file:
-
restauthdb
-- the name of the database file -
restauthkey
-- the passphrase required to decrypt the database file
After adding these configuration options (and being restarted), the provisioner will refuse all requests received via the REST API that do not either include a valid API key or complete Digest Authentication successfully.
If either of the above configuration options is absent, then authentication will be disabled and all REST API requests will be actioned by the provisioner. If in doubt, the provisioner logs should include a message regarding whether authentication for the REST API is enabled or disabled currently.
The easiest way to add a new user is run the openli-prov-adduser.sh
script that can be found in ./src/provisioner/authsetup/
. If you've installed OpenLI via a Debian or RPM package, this script will be installed into /usr/sbin/
.
The script can be run as follows:
./src/provisioner/authsetup/openli-prov-adduser.sh <passphrase> <username> <password> <database file>
The <passphrase>
is the passphrase that was used to encrypt the database file originally.
This script will automatically calculate the md5 digest hash for the given username and password and store that in the digesthash
column of the authcreds
table. The user's password is NOT stored in the database, just the derived hash. The script will also generate a random API key for the user, which will be printed to the terminal if the user is added successfully. The API key will also be available by querying directly for the user in the authcreds
table.
The simplest way to authenticate when using the provisioner REST API is by using an API key. Each user in the credentials database can have an API key associated with them -- users added via the openli-prov-adduser.sh
script will have an API key generated for them randomly.
To include an API key with your REST API request, you must include the X-API-KEY
Header in your HTTP request and set it to the value of your API key. The provisioner will then check if that API key matches a valid API key for any user in the credentials database -- if it does, then your request will proceed.
If you are using curl
to perform REST API requests, then you can add the X-API-KEY
header using the -H
option as follows:
curl -H "X-API-KEY: <yourapikey>" -X GET http://10.100.100.1:9001/agency/police
API key authentication is the easiest method to use when you are writing code / scripts to interface with the provisioner REST API.
Digest authentication allows users to be authenticated by specifying a username and password, but without the password being transmitted in clear-text across the wire or being stored in the credentials database. In OpenLI, we use MD5 hashing to derive the digest value from the username and password, which is not the most secure possible approach but is well supported by both the library that we use for processing HTTP requests (libmicrohttpd) and command-line clients such as curl
.
The OpenLI provisioner conforms to the standard Digest authentication specification found in RFC 2617. The value of A1
for each user is stored in the credentials database on the provisioner and is calculated by taking the MD5 hash of:
<username>:[email protected]:<password>
A client that is attempting Digest Auth will need to include a valid response
field in its Authorization header when making an HTTP request. The curl
client will generate this field automatically for you -- you simply need to specify the username and password when invoking curl
using the -u
option (note, you may omit the password from the option and curl
will instead prompt you for the password), as well as explicitly set the --digest
option. For example:
curl --digest -u<username>:<password> -X GET http://10.100.100.1:9001/agency/police
Custom clients that wish to use Digest Auth will need to include code that can parse the WWW-Authenticate
headers sent by the provisioner, calculate the digest response as per RFC 2617 and include it in the Authorization
header of their request. Unless you already have code that does this for you, you may prefer to use an API key instead (see above).
Removal of users from the credentials database is currently a manual process, but can be easily done in a single terminal command:
sqlcipher <database file> "PRAGMA key=<passphrase>; DELETE FROM authcreds where username=`<user to remove>`;"
A similar process can be used to view or modify user credentials in the database -- the crucial step is to use the PRAGMA
command to specify the passphrase for the database file so that it can be decrypted before performing operations on it.