Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json web token/ login #5

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions director/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .private import PrivateAPI
from .public import PublicAPI
from .json_web_token import generate_jwt, token_required
32 changes: 32 additions & 0 deletions director/api/json_web_token.py
Original file line number Diff line number Diff line change
@@ -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:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the plain Authorization: Bearer <token> headers for this? 😄

token = request.headers['x-access-token']
if not token:
jsonify({'message': 'Token is missing'}), 401

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to jsonify stuff here, just return the dict and the status code!

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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rename username to sub, and also add the user's name in the name field.

'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60)},
current_app.config['SECRET_KEY'])
return jsonify({'token': token.decode('UTF-8')})
28 changes: 26 additions & 2 deletions director/api/public.py
Original file line number Diff line number Diff line change
@@ -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/<username>')
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)
32 changes: 30 additions & 2 deletions director/test/api/test_public.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
"""
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ wcwidth==0.1.8
Werkzeug==0.16.1
wrapt==1.11.2
zipp==3.0.0
pyjwt==1.7.1