subclient tokens: bugfix & return proper data.

Also introduces responses, as an alternative to httpretty (it works
better).
This commit is contained in:
Sybren A. Stüvel 2016-04-12 15:24:50 +02:00
parent e0460f8518
commit aeee165ad8
5 changed files with 76 additions and 15 deletions

View File

@ -4,7 +4,7 @@ import logging
from pprint import pformat from pprint import pformat
import requests import requests
from flask import Blueprint, request, current_app, abort from flask import Blueprint, request, current_app, abort, jsonify
from eve.methods.post import post_internal from eve.methods.post import post_internal
from eve.methods.put import put_internal from eve.methods.put import put_internal
@ -18,7 +18,7 @@ log = logging.getLogger(__name__)
def store_subclient_token(): def store_subclient_token():
"""Verifies & stores a user's subclient-specific token.""" """Verifies & stores a user's subclient-specific token."""
user_id = request.form['user_id'] user_id = request.form['user_id'] # User ID at BlenderID
scst = request.form['scst'] scst = request.form['scst']
# Verify with Blender ID # Verify with Blender ID
@ -27,23 +27,28 @@ def store_subclient_token():
if user_info is None: if user_info is None:
log.warning('Unable to verify subclient token with Blender ID.') log.warning('Unable to verify subclient token with Blender ID.')
return 'BLENDER ID ERROR', 403 return jsonify({'status': 'fail',
'error': 'BLENDER ID ERROR'}), 403
# Store the user info in MongoDB. # Store the user info in MongoDB.
log.info('Obtained user info from Blender ID: %s', user_info) log.info('Obtained user info from Blender ID: %s', user_info)
db_user = find_user_in_db(user_id, scst, **user_info) db_user = find_user_in_db(user_id, scst, **user_info)
log.debug('Storing updated/created user:\n%s', pformat(db_user))
if '_id' in db_user: if '_id' in db_user:
# Update the existing user
db_id = db_user['_id'] db_id = db_user['_id']
r, _, _, status = put_internal('users', remove_private_keys(db_user), _id=db_id) r, _, _, status = put_internal('users', remove_private_keys(db_user), _id=db_id)
else: else:
# Create a new user
r, _, _, status = post_internal('users', db_user) r, _, _, status = post_internal('users', db_user)
if status != 200: db_id = r['_id']
if status not in (200, 201):
log.error('internal response: %r %r', status, r) log.error('internal response: %r %r', status, r)
return abort(500) return abort(500)
return 'OK', 200 return jsonify({'status': 'success',
'subclient_user_id': str(db_id)}), status
def validate_subclient_token(user_id, scst): def validate_subclient_token(user_id, scst):

View File

@ -26,3 +26,4 @@ zencoder==0.6.5
# development requirements # development requirements
httpretty==0.8.14 httpretty==0.8.14
pytest==2.9.1 pytest==2.9.1
responses==0.5.1

View File

@ -3,6 +3,7 @@ import copy
import sys import sys
import logging import logging
import os import os
import base64
from bson import ObjectId from bson import ObjectId
from eve.tests import TestMinimal from eve.tests import TestMinimal
@ -101,3 +102,7 @@ class AbstractPillarTest(TestMinimal):
'status': 'success'}), 'status': 'success'}),
content_type="application/json") content_type="application/json")
def make_header(self, username, password=''):
"""Returns a Basic HTTP Authentication header value."""
return 'basic ' + base64.b64encode('%s:%s' % (username, password))

View File

@ -1,15 +1,8 @@
import base64
import httpretty import httpretty
from common_test_class import AbstractPillarTest, TEST_EMAIL_USER, TEST_EMAIL_ADDRESS from common_test_class import AbstractPillarTest, TEST_EMAIL_USER, TEST_EMAIL_ADDRESS
def make_header(username, password=''):
"""Returns a Basic HTTP Authentication header value."""
return 'basic ' + base64.b64encode('%s:%s' % (username, password))
class AuthenticationTests(AbstractPillarTest): class AuthenticationTests(AbstractPillarTest):
def test_make_unique_username(self): def test_make_unique_username(self):
from application.utils import authentication as auth from application.utils import authentication as auth
@ -36,7 +29,8 @@ class AuthenticationTests(AbstractPillarTest):
from application.utils import authentication as auth from application.utils import authentication as auth
self.htp_blenderid_validate_unhappy() self.htp_blenderid_validate_unhappy()
with self.app.test_request_context(headers={'Authorization': make_header('unknowntoken')}): with self.app.test_request_context(
headers={'Authorization': self.make_header('unknowntoken')}):
self.assertFalse(auth.validate_token()) self.assertFalse(auth.validate_token())
@httpretty.activate @httpretty.activate
@ -46,5 +40,6 @@ class AuthenticationTests(AbstractPillarTest):
from application.utils import authentication as auth from application.utils import authentication as auth
self.htp_blenderid_validate_happy() self.htp_blenderid_validate_happy()
with self.app.test_request_context(headers={'Authorization': make_header('knowntoken')}): with self.app.test_request_context(
headers={'Authorization': self.make_header('knowntoken')}):
self.assertTrue(auth.validate_token()) self.assertTrue(auth.validate_token())

View File

@ -0,0 +1,55 @@
# -*- encoding: utf-8 -*-
import responses
import json
from bson import ObjectId
from common_test_class import AbstractPillarTest
TEST_FULL_NAME = u'врач Сергей'
TEST_EMAIL = 'jemoeder@example.com'
TEST_SUBCLIENT_TOKEN = 'my-subclient-token-for-pillar'
BLENDER_ID_TEST_USERID = 1896
BLENDER_ID_USER_RESPONSE = {'status': 'success',
'user': {'email': TEST_EMAIL, 'full_name': TEST_FULL_NAME}}
class BlenderIdSubclientTest(AbstractPillarTest):
@responses.activate
def test_store_scst_new_user(self):
self._common_user_test(201)
@responses.activate
def test_store_scst_existing_user(self):
# Make sure the user exists in our database.
from application.utils.authentication import create_new_user
with self.app.test_request_context():
create_new_user(TEST_EMAIL, 'apekoppie', BLENDER_ID_TEST_USERID)
self._common_user_test(200)
def _common_user_test(self, expected_status_code):
responses.add(responses.POST,
'%s/subclients/validate_token' % self.app.config['BLENDER_ID_ENDPOINT'],
json=BLENDER_ID_USER_RESPONSE,
status=200)
resp = self.client.post('/blender_id/store_scst',
data={'user_id': BLENDER_ID_TEST_USERID,
'scst': TEST_SUBCLIENT_TOKEN})
self.assertEqual(expected_status_code, resp.status_code)
user_info = json.loads(resp.data) # {'status': 'success', 'subclient_user_id': '...'}
self.assertEqual('success', user_info['status'])
# Check that the user was correctly updated
with self.app.test_request_context():
users = self.app.data.driver.db['users']
db_user = users.find_one(ObjectId(user_info['subclient_user_id']))
self.assertIsNotNone(db_user, 'user %r not found' % user_info['subclient_user_id'])
self.assertEqual(TEST_EMAIL, db_user['email'])
self.assertEqual(TEST_FULL_NAME, db_user['full_name'])
self.assertEqual(TEST_SUBCLIENT_TOKEN, db_user['auth'][0]['token'])
self.assertEqual(str(BLENDER_ID_TEST_USERID), db_user['auth'][0]['user_id'])
self.assertEqual('blender-id', db_user['auth'][0]['provider'])