From 47c72d9b6858ced78fa4a94aca74746d025336a3 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 28 Jul 2019 23:12:53 -0400 Subject: [PATCH] Move token authentication to X-Api-Token header Implements #46 --- client-api/pvc-api.py | 47 ++++++++++++++++++++++++------------------- docs/manuals/api.md | 4 ++-- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/client-api/pvc-api.py b/client-api/pvc-api.py index 720d2db3..4b8ddb7f 100755 --- a/client-api/pvc-api.py +++ b/client-api/pvc-api.py @@ -75,23 +75,26 @@ if config['debug']: if config['auth_enabled']: api.config["SECRET_KEY"] = config['auth_secret_key'] +# Authentication decorator function def authenticator(function): def authenticate(*args, **kwargs): - # Check if authentication is enabled + # No authentication required if not config['auth_enabled']: return function(*args, **kwargs) - else: - # Session-based authentication - if 'token' in flask.session: - return function(*args, **kwargs) - # Direct token-based authentication - if 'token' in flask.request.values: - if any(token for token in config['auth_tokens'] if flask.request.values['token'] == token['token']): - return function(*args, **kwargs) - else: - return flask.jsonify({"message":"Authentication failed"}), 401 - return flask.jsonify({"message":"Authentication required"}), 401 + # Session-based authentication + if 'token' in flask.session: + return function(*args, **kwargs) + + # Key header-based authentication + if 'X-Api-Key' in flask.request.headers: + if any(token for token in secret_tokens if flask.request.headers.get('X-Api-Key') == token): + return function(*args, **kwargs) + else: + return "X-Api-Key Authentication failed\n", 401 + + # All authentications failed + return "X-Api-Key Authentication required\n", 401 authenticate.__name__ = function.__name__ return authenticate @@ -106,21 +109,23 @@ def api_auth_login(): if not config['auth_enabled']: return flask.jsonify({"message":"Authentication is disabled."}), 200 + if flask.request.method == 'GET': + return ''' +
+

+ Enter your authentication token: + + +

+
+ ''' + if flask.request.method == 'POST': if any(token for token in config['auth_tokens'] if flask.request.values['token'] in token['token']): flask.session['token'] = flask.request.form['token'] return flask.redirect(flask.url_for('api_root')) else: return flask.jsonify({"message":"Authentication failed"}), 401 - return ''' -
-

- Enter your authentication token: - - -

-
- ''' @api.route('/api/v1/auth/logout', methods=['GET', 'POST']) def api_auth_logout(): diff --git a/docs/manuals/api.md b/docs/manuals/api.md index 1b85287a..a3ce386b 100644 --- a/docs/manuals/api.md +++ b/docs/manuals/api.md @@ -16,7 +16,7 @@ Authentication for the API is available using a static list of tokens. These tok The API provides session-based login using the `/api/v1/auth/login` and `/api/v1/auth/logout` options. If authentication is not enabled, these endpoints return a JSON `message` of `Authentiation is disabled` and HTTP code 200. -For one-time authentication, the `token` value can be specified to any API endpoint. This is only checked if there is no valid session already established. If authentication is enabled, there is no valid session, and no `token` value is specified, the API will return a JSON `message` of `Authentication required` and HTTP code 401. +For one-time authentication, the `token` value can be specified to any API endpoint via the `X-Api-Key` header value. This is only checked if there is no valid session already established. If authentication is enabled, there is no valid session, and no `token` value is specified, the API will return a JSON `message` of `Authentication required` and HTTP code 401. ### Values @@ -107,7 +107,7 @@ The Flask authentication secret key used to salt session credentials. Should be * *optional* * *requires* `authentication` -> `enabled` -A list of API authentication tokens that can be passed via the `X-Authentication` header to authorize access to the API. +A list of API authentication tokens that can be passed via the `X-Api-Key` header to authorize access to the API. ##### `description`