diff --git a/director/api/__init__.py b/director/api/__init__.py index 5a079b1..4bde4d6 100644 --- a/director/api/__init__.py +++ b/director/api/__init__.py @@ -1,2 +1,3 @@ from .private import PrivateAPI from .public import PublicAPI +from .json_web_token import generate_jwt, token_required \ No newline at end of file diff --git a/director/api/json_web_token.py b/director/api/json_web_token.py new file mode 100644 index 0000000..e2d24d7 --- /dev/null +++ b/director/api/json_web_token.py @@ -0,0 +1,32 @@ +from flask import jsonify, request, current_app +import jwt +import datetime +from functools import wraps + +def token_required(f): + """ + THIS function requires the use of a json web token in order to be accepted + """ + @wraps(f) + def decorated(*args, **kwargs): + token = None + if 'x-access-token' in request.headers: + token = request.headers['x-access-token'] + if not token: + jsonify({'message': 'Token is missing'}), 401 + try: + data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256']) + except: + return jsonify({'message':'Token is false'}), 401 + return f(*args,**kwargs) + return decorated + + +def generate_jwt(username): + """ + Generats a Jwt given a username more could be added in the future + """ + token = jwt.encode({'username': username, + 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60)}, + current_app.config['SECRET_KEY']) + return jsonify({'token': token.decode('UTF-8')}) diff --git a/director/api/public.py b/director/api/public.py index 4d1d0aa..1dde977 100644 --- a/director/api/public.py +++ b/director/api/public.py @@ -1,9 +1,33 @@ -from flask import Blueprint +from flask import Blueprint, Response, request, make_response, jsonify from director.model import User - +from .json_web_token import generate_jwt, token_required +from director.authentication import Authenticator PublicAPI = Blueprint('public_api', __name__, url_prefix='/api/public') @PublicAPI.route('/user/') def get_user(username): user = User.query.filter_by(username=username).first_or_404() return user.serialize() + + + +@PublicAPI.route('/login', methods=['POST']) +def login(): + """ + public api login with ldap authentication and returns a JWT + """ + if not 'username' in request.form: + return jsonify({'message': 'username must not be empty'}), 401 + if not 'password' in request.form: + return jsonify({'message': ' password must not be empty'}), 401 + authenticator = Authenticator() + user = authenticator.authenticate(request.form['username'], request.form['password']) + if user == None: + #if user do not exist + return Response(status=401) + return generate_jwt(request.form['username']), 200 + +@PublicAPI.route('/test') +@token_required +def test(): + return Response(status=200) \ No newline at end of file diff --git a/director/test/api/test_public.py b/director/test/api/test_public.py index 5c56e2d..caa01ed 100644 --- a/director/test/api/test_public.py +++ b/director/test/api/test_public.py @@ -3,8 +3,7 @@ from director.authentication.local_adapter import LocalAdapter def test_get_user(client): - db.session.add(User(username='p3150133', full_name='Spyridon Pagkalos')) - + db.session.add(User(username='p3150133', full_name='Spyridon Pagkalos', cached_password='pass')) rv = client.get('/api/public/user/p3150133') assert b'p3150133' in rv.data assert b'Spyridon Pagkalos' in rv.data @@ -14,3 +13,32 @@ def test_get_user_failing_test(client): rv = client.get('/api/public/user/p3150133') assert rv.status_code == 404 +def test_test_Token_false(client): + rv = client.get('/api/public/test', + headers={'x-access-token': "e1NiJ9.eyJ1c2VybmFtZSI6ImJpbNDd9.L1CYZ0pxmMxG0pBVTOS8FMjXhdfmd6CRfP-QU4"}) + assert rv.status_code == 401 + +def test_test_Token_missing(client): + rv = client.get('/api/public/test') + assert rv.status_code == 401 +""" +def test_test_Token(client): + rv = client.get('/api/public/test', + headers=[('x-access-token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImJpbGwiLCJleHAiOjE2ODM0MTM0NDd9.ylB6wPEizwVn9Dcjuzxq0iPLI23FU9cRwUU3anRYDt0')]) + assert rv.status_code == 200 +""" + +def test_login_fail_no_password(client): + rv = client.post('api/public/login',data=dict( + username='bill'), + follow_redirects=True) + assert rv.status_code==401 +""" +def test_login_success(client): + db.session.add(User(username='p3150133', full_name='Spyridon Pagkalos', cached_password='pass')) + rv = client.post('api/public/login', data=dict( + username='p3150133', + cached_password = 'pass' + ), follow_redirects=True) + assert rv.status_code==200 +""" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8af446d..59340da 100644 --- a/requirements.txt +++ b/requirements.txt @@ -45,3 +45,4 @@ wcwidth==0.1.8 Werkzeug==0.16.1 wrapt==1.11.2 zipp==3.0.0 +pyjwt==1.7.1 \ No newline at end of file