Added subclient token verification & storage.

This commit is contained in:
2016-04-08 18:45:35 +02:00
parent 771b091626
commit 3d9fe76271
4 changed files with 122 additions and 4 deletions

View File

@@ -380,5 +380,7 @@ file_storage.setup_app(app, url_prefix='/storage')
# The encoding module (receive notification and report progress)
from modules.encoding import encoding
from modules.blender_id import blender_id
app.register_blueprint(encoding, url_prefix='/encoding')
app.register_blueprint(blender_id, url_prefix='/blender_id')

View File

@@ -0,0 +1,106 @@
"""Blender ID subclient endpoint."""
import logging
from pprint import pformat
import requests
from flask import Blueprint, request, current_app, abort
from eve.methods.post import post_internal
from eve.methods.put import put_internal
from application.utils import authentication, remove_private_keys
blender_id = Blueprint('blender_id', __name__)
log = logging.getLogger(__name__)
@blender_id.route('/store_scst', methods=['POST'])
def store_subclient_token():
"""Verifies & stores a user's subclient-specific token."""
user_id = request.form['user_id']
scst = request.form['scst']
# Verify with Blender ID
log.debug('Storing SCST for BlenderID user %s', user_id)
user_info = validate_subclient_token(user_id, scst)
if user_info is None:
log.warning('Unable to verify subclient token with Blender ID.')
return 'BLENDER ID ERROR', 403
# Store the user info in MongoDB.
log.info('Obtained user info from Blender ID: %s', 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:
db_id = db_user['_id']
r, _, _, status = put_internal('users', remove_private_keys(db_user), _id=db_id)
else:
r, _, _, status = post_internal('users', db_user)
if status != 200:
log.error('internal response: %r %r', status, r)
return abort(500)
return 'OK', 200
def validate_subclient_token(user_id, scst):
"""Verifies a subclient token with Blender ID.
:returns: the user information from Blender ID on success, in a dict
{'email': 'a@b', 'full_name': 'AB'}, or None on failure.
:rtype: dict
"""
client_id = current_app.config['BLENDER_ID_CLIENT_ID']
subclient_id = current_app.config['BLENDER_ID_SUBCLIENT_ID']
log.debug('Validating subclient token %s for Blender ID user %s', scst, user_id)
payload = {'client_id': client_id,
'subclient_id': subclient_id,
'user_id': user_id,
'scst': scst}
url = '{0}/subclients/validate_token'.format(authentication.blender_id_endpoint())
log.debug('POSTing to %r', url)
# POST to Blender ID, handling errors as negative verification results.
try:
r = requests.post(url, data=payload)
except requests.exceptions.ConnectionError as e:
log.error('Connection error trying to POST to %s, handling as invalid token.', url)
return None
if r.status_code != 200:
log.info('Token invalid, HTTP status %i returned', r.status_code)
return None
resp = r.json()
if resp['status'] != 'success':
log.warning('Failed response from %s: %s', url, resp)
return None
return resp['user']
def find_user_in_db(user_id, scst, email, full_name):
users = current_app.data.driver.db['users']
query = {'auth': {'$elemMatch': {'user_id': user_id, 'provider': 'blender-id'}}}
log.debug('Querying: %s', query)
db_user = users.find_one(query)
if db_user:
log.debug('User %r already in our database, updating with info from Blender ID.', user_id)
db_user['full_name'] = full_name
db_user['email'] = email
auth = next(auth for auth in db_user['auth'] if auth['provider'] == 'blender-id')
auth['token'] = scst
return db_user
log.debug('User %r not yet in our database, create a new one.', user_id)
db_user = authentication.create_new_user_document(email, user_id, full_name, token=scst)
db_user['username'] = authentication.make_unique_username(email)
return db_user

View File

@@ -134,6 +134,15 @@ def create_new_user(email, username, user_id):
@returns: the user ID from our local database.
"""
user_data = create_new_user_document(email, user_id, username)
r = post_internal('users', user_data)
user_id = r[0]['_id']
return user_id
def create_new_user_document(email, user_id, username, token=''):
"""Creates a new user document, without storing it in MongoDB."""
user_data = {
'full_name': username,
'username': username,
@@ -141,14 +150,12 @@ def create_new_user(email, username, user_id):
'auth': [{
'provider': 'blender-id',
'user_id': str(user_id),
'token': ''}],
'token': token}],
'settings': {
'email_communications': 1
}
}
r = post_internal('users', user_data)
user_id = r[0]['_id']
return user_id
return user_data
def make_unique_username(email):

View File

@@ -64,3 +64,6 @@ FILE_LINK_VALIDITY = defaultdict(
gcs=3600 * 23, # 23 hours for Google Cloud Storage.
)
# Client and Subclient IDs for Blender ID
BLENDER_ID_CLIENT_ID = 'SPECIAL-SNOWFLAKE-57'
BLENDER_ID_SUBCLIENT_ID = 'PILLAR'