Browse Source

token is not part of the URL anymore

master
Julio Biason 11 years ago
parent
commit
a4f4d314b6
  1. 17
      luncho/blueprints/users.py
  2. 14
      luncho/helpers.py
  3. 28
      tests/base.py
  4. 23
      tests/users_tests.py

17
luncho/blueprints/users.py

@ -12,7 +12,7 @@ from flask import jsonify
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from luncho.helpers import ForceJSON from luncho.helpers import ForceJSON
from luncho.helpers import user_from_token from luncho.helpers import auth
from luncho.server import User from luncho.server import User
from luncho.server import db from luncho.server import db
@ -53,15 +53,16 @@ def create_user():
return jsonify(status='OK') return jsonify(status='OK')
@users.route('<token>/', methods=['POST']) @users.route('/', methods=['POST'])
@ForceJSON() @ForceJSON()
def update_user(token): @auth
def update_user():
"""Update user information. Request can have the following fields: """Update user information. Request can have the following fields:
{ "full_name": "Full name", "password": "hash" } { "full_name": "Full name", "password": "hash" }
Any other field will be ignored; only fields that need to be changed Any other field will be ignored; only fields that need to be changed
must be send.""" must be send."""
json = request.get_json(force=True) json = request.get_json(force=True)
user = user_from_token(token) user = request.user
if 'full_name' in json: if 'full_name' in json:
LOG.debug('Fullname = {fullname}'.format(fullname=json['full_name'])) LOG.debug('Fullname = {fullname}'.format(fullname=json['full_name']))
@ -75,10 +76,10 @@ def update_user(token):
return jsonify(status='OK') return jsonify(status='OK')
@users.route('<token>/', methods=['DELETE']) @users.route('/', methods=['DELETE'])
def delete_user(token): @auth
def delete_user():
"""Delete a user. No confirmation is send.""" """Delete a user. No confirmation is send."""
user = user_from_token(token) db.session.delete(request.user)
db.session.delete(user)
db.session.commit() db.session.commit()
return jsonify(status='OK') return jsonify(status='OK')

14
luncho/helpers.py

@ -3,6 +3,8 @@
"""Helper functions.""" """Helper functions."""
import logging
from functools import wraps from functools import wraps
from flask import request from flask import request
@ -15,6 +17,8 @@ from luncho.exceptions import MissingFieldsException
from luncho.exceptions import UserNotFoundException from luncho.exceptions import UserNotFoundException
from luncho.exceptions import AuthorizationRequiredException from luncho.exceptions import AuthorizationRequiredException
LOG = logging.getLogger('luncho.helpers')
class ForceJSON(object): class ForceJSON(object):
"""Decorator to check if the request is in JSON format.""" """Decorator to check if the request is in JSON format."""
@ -41,24 +45,26 @@ class ForceJSON(object):
return check_json return check_json
class Auth(object): def auth(func):
"""Validate the token in the Basic Auth header."""
def __call__(self, func):
@wraps(func) @wraps(func)
def check_auth(*args, **kwargs): def check_auth(*args, **kwargs):
if not request.authorization: if not request.authorization:
LOG.debug('There is no basic auth in the headers')
raise AuthorizationRequiredException raise AuthorizationRequiredException
token = request.authorization.username token = request.authorization.username
user = User.query.filter_by(token=token).first() user = User.query.filter_by(token=token).first()
if not user: if not user:
LOG.debug('No user with token {token}'.format(token=token))
raise UserNotFoundException() raise UserNotFoundException()
if not user.valid_token(token): if not user.valid_token(token):
raise InvalidTokenException() raise InvalidTokenException()
request.user = user
return func(*args, **kwargs) return func(*args, **kwargs)
return check_auth
def user_from_token(token): def user_from_token(token):

28
tests/base.py

@ -3,10 +3,22 @@
import unittest import unittest
import json import json
import base64
from luncho import server from luncho import server
def _token_header(token=None):
"""Generate the headers required for using the token as an auth."""
if not token:
return None
message = '{token}:Ignored'.format(token=token)
headers = {'Authorization': 'Basic {code}'.format(
code=base64.b64encode(message))}
return headers
class LunchoTests(unittest.TestCase): class LunchoTests(unittest.TestCase):
"""Base testing for all Lunch-o tests.""" """Base testing for all Lunch-o tests."""
@ -75,22 +87,26 @@ class LunchoTests(unittest.TestCase):
# Easy way to convert the data to JSON and do requests # Easy way to convert the data to JSON and do requests
# ------------------------------------------------------------ # ------------------------------------------------------------
def post(self, url, data): def post(self, url, data, token=None):
"""Send a POST request to the URL.""" """Send a POST request to the URL."""
return self.app.post(url, return self.app.post(url,
data=json.dumps(data), data=json.dumps(data),
headers=_token_header(token),
content_type='application/json') content_type='application/json')
def put(self, url, data): def put(self, url, data, token=None):
"""Send a PUT request to the URL.""" """Send a PUT request to the URL."""
return self.app.put(url, return self.app.put(url,
data=json.dumps(data), data=json.dumps(data),
headers=_token_header(token),
content_type='application/json') content_type='application/json')
def delete(self, url): def delete(self, url, token=None):
"""Send a DELETE request to the URL. There is no data to be send.""" """Send a DELETE request to the URL. There is no data to be send."""
return self.app.delete(url) return self.app.delete(url,
headers=_token_header(token))
def get(self, url): def get(self, url, token=None):
"""Send a GET request to the URL. There is no data to be send.""" """Send a GET request to the URL. There is no data to be send."""
return self.app.get(url) return self.app.get(url,
headers=_token_header(token))

23
tests/users_tests.py

@ -2,7 +2,6 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
import unittest import unittest
import json
from luncho import server from luncho import server
@ -67,10 +66,10 @@ class TestExistingUsers(LunchoTests):
"""Update user details.""" """Update user details."""
request = {'full_name': 'New User Name', request = {'full_name': 'New User Name',
'password': 'newhash'} 'password': 'newhash'}
rv = self.post('/user/{token}/'.format(token=self.user.token), rv = self.post('/user/',
request) request,
self.user.token)
expected = {'status': 'OK'}
self.assertJsonOk(rv) self.assertJsonOk(rv)
# check in the database # check in the database
@ -82,8 +81,9 @@ class TestExistingUsers(LunchoTests):
"""Send a request with an unexisting token.""" """Send a request with an unexisting token."""
request = {'full_name': 'New User Name', request = {'full_name': 'New User Name',
'password': 'newhash'} 'password': 'newhash'}
rv = self.post('/user/{token}/'.format(token='no-token'), rv = self.post('/user/',
request) request,
'no-token')
self.assertJsonError(rv, 404, 'User not found (via token)') self.assertJsonError(rv, 404, 'User not found (via token)')
@ -96,14 +96,15 @@ class TestExistingUsers(LunchoTests):
request = {'full_name': 'New User Name', request = {'full_name': 'New User Name',
'password': 'newhash'} 'password': 'newhash'}
rv = self.post('/user/{token}/'.format(token=self.user.token), rv = self.post('/user/',
request) request,
self.user.token)
self.assertJsonError(rv, 400, 'Invalid token') self.assertJsonError(rv, 400, 'Invalid token')
def test_delete_user(self): def test_delete_user(self):
"""Delete a user.""" """Delete a user."""
rv = self.delete('/user/{token}/'.format(token=self.user.token)) rv = self.delete('/user/', token=self.user.token)
self.assertJsonOk(rv) self.assertJsonOk(rv)
# check the database # check the database
@ -112,7 +113,7 @@ class TestExistingUsers(LunchoTests):
def test_delete_wrong_token(self): def test_delete_wrong_token(self):
"""Send a delete to a non-existing token.""" """Send a delete to a non-existing token."""
rv = self.delete('/user/{token}/'.format(token='no-token')) rv = self.delete('/user/', token='no-token')
self.assertJsonError(rv, 404, 'User not found (via token)') self.assertJsonError(rv, 404, 'User not found (via token)')
@ -122,7 +123,7 @@ class TestExistingUsers(LunchoTests):
self.user.token = 'expired' self.user.token = 'expired'
server.db.session.commit() server.db.session.commit()
rv = self.delete('/user/{token}/'.format(token=self.user.token)) rv = self.delete('/user/', token=self.user.token)
self.assertJsonError(rv, 400, 'Invalid token') self.assertJsonError(rv, 400, 'Invalid token')

Loading…
Cancel
Save