Commit 2b6b0dc6 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added x-token based authentication.

parent 1e1f6766
......@@ -19,10 +19,24 @@ authentication or access tokens. Currently the authentication is validated again
users and sessions in the NOMAD-coe repository postgres db.
.. autodata:: base_path
There are two authentication "schemes" to authenticate users. First we use
HTTP Basic Authentication (username, password), which also works with username=token,
password=''. Second, there is a curstom HTTP header 'X-Token' that can be used to
give a token. The first precedes the second. The used tokens are given and stored
by the NOMAD-coe repository GUI.
Authenticated user information is available via FLASK's build in flask.g.user object.
It is set to None, if no user information is available.
There are two decorators for FLASK API endpoints that can be used if endpoints require
authenticated user information for authorization or otherwise.
.. autofunction:: login_if_available
.. autofunction:: login_really_required
"""
from flask import Flask, g
from flask import Flask, g, request
from flask_restful import Api, abort
from flask_cors import CORS
from flask_httpauth import HTTPBasicAuth
......@@ -72,12 +86,34 @@ def verify_password(username_or_token, password):
return True
def login_if_available(func):
"""
A decorator for API endpoint implementations that might authenticate users, but
provide limited functionality even without users.
"""
@auth.login_required
def wrapper(*args, **kwargs):
# TODO the cutom X-Token based authentication should be replaced by a real
# Authentication header based token authentication
if not g.user and 'X-Token' in request.headers:
token = request.headers['X-Token']
g.user = User.verify_auth_token(token)
if not g.user:
abort(401, message='Provided access token is not valid or does not exist.')
return func(*args, **kwargs)
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
return wrapper
def login_really_required(func):
"""
A decorator for API endpoint implementations that forces user authentication on
endpoints.
"""
@auth.login_required
@login_if_available
def wrapper(*args, **kwargs):
if g.user is None:
abort(401, message='Anonymous access is forbidden, authorization required')
......
......@@ -23,7 +23,7 @@ from flask_restful import Resource, abort
from nomad.repo import RepoCalc
from .app import api, auth, base_path
from .app import api, auth, base_path, login_if_available
class RepoCalcRes(Resource):
......@@ -90,7 +90,7 @@ class RepoCalcRes(Resource):
class RepoCalcsRes(Resource):
@auth.login_required
@login_if_available
def get(self):
"""
Get *'all'* calculations in repository from, paginated.
......
......@@ -87,6 +87,35 @@ def assert_upload(upload_json_str, id=None, **kwargs):
return data
def test_xtoken_auth(client, test_user, no_warn):
rv = client.get('/uploads', headers={
'X-Token': test_user.email
})
assert rv.status_code == 200
def test_xtoken_auth_denied(client, no_warn):
rv = client.get('/uploads', headers={
'X-Token': 'invalid'
})
assert rv.status_code == 401
def test_basic_auth(client, test_user_auth, no_warn):
rv = client.get('/uploads', headers=test_user_auth)
assert rv.status_code == 200
def test_basic_auth_denied(client, no_warn):
basic_auth_base64 = base64.b64encode('invalid'.encode('utf-8')).decode('utf-8')
rv = client.get('/uploads', headers={
'Authorization': 'Basic %s' % basic_auth_base64
})
assert rv.status_code == 401
def test_no_uploads(client, test_user_auth, no_warn):
rv = client.get('/uploads', headers=test_user_auth)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment