diff --git a/pillar/__init__.py b/pillar/__init__.py index eeea3524..e4cd3db2 100644 --- a/pillar/__init__.py +++ b/pillar/__init__.py @@ -115,7 +115,6 @@ class PillarServer(Eve): # Configure authentication self.login_manager = auth.config_login_manager(self) - self.oauth_blender_id = auth.config_oauth_login(self) self._config_caching() diff --git a/pillar/api/blender_id.py b/pillar/api/blender_id.py index 21ecfdea..01b876ef 100644 --- a/pillar/api/blender_id.py +++ b/pillar/api/blender_id.py @@ -9,7 +9,8 @@ import logging import requests from bson import tz_util -from flask import Blueprint, request, current_app, jsonify +from rauth import OAuth2Session +from flask import Blueprint, request, current_app, jsonify, session from requests.adapters import HTTPAdapter from pillar.api.utils import authentication @@ -175,23 +176,26 @@ def fetch_blenderid_user() -> dict: bid_url = '%s/api/user' % blender_id_endpoint() log.debug('Fetching user info from %s', bid_url) - try: - bid_resp = current_app.oauth_blender_id.get(bid_url) + client_id = current_app.config['OAUTH_CREDENTIALS']['blender-id']['id'] + client_secret = current_app.config['OAUTH_CREDENTIALS']['blender-id']['secret'] + oauth_session = OAuth2Session( + client_id, client_secret, access_token=session['blender_id_oauth_token']) + bid_resp = oauth_session.get(bid_url) except httplib2.HttpLib2Error: log.exception('Error getting %s from BlenderID', bid_url) return {} - if bid_resp.status != 200: - log.warning('Error %i from BlenderID %s: %s', bid_resp.status, bid_url, bid_resp.data) + if bid_resp.status_code != 200: + log.warning('Error %i from BlenderID %s: %s', bid_resp.status_code, bid_url, bid_resp.data) return {} - if not bid_resp.data: + if not bid_resp.json(): log.warning('Empty data returned from BlenderID %s', bid_url) return {} - log.debug('BlenderID returned %s', bid_resp.data) - return bid_resp.data + log.debug('BlenderID returned %s', bid_resp.json()) + return bid_resp.json() def setup_app(app, url_prefix): diff --git a/pillar/auth/__init__.py b/pillar/auth/__init__.py index 8ebe6e97..d10962fc 100644 --- a/pillar/auth/__init__.py +++ b/pillar/auth/__init__.py @@ -6,7 +6,6 @@ import typing from flask import session, g import flask_login -import flask_oauthlib.client from werkzeug.local import LocalProxy from pillar import current_app @@ -222,35 +221,6 @@ def get_blender_id_oauth_token(): return None -def config_oauth_login(app): - config = app.config - if not config.get('SOCIAL_BLENDER_ID'): - log.info('OAuth Blender-ID login not set up, no app config SOCIAL_BLENDER_ID.') - return None - if not config.get('BLENDER_ID_OAUTH_URL'): - log.error('Unable to use Blender ID, missing configuration BLENDER_ID_OAUTH_URL.') - return None - - oauth = flask_oauthlib.client.OAuth(app) - social_blender_id = config.get('SOCIAL_BLENDER_ID') - - oauth_blender_id = oauth.remote_app( - 'blender_id', - consumer_key=social_blender_id['app_id'], - consumer_secret=social_blender_id['app_secret'], - request_token_params={'scope': 'email'}, - base_url=config['BLENDER_ID_OAUTH_URL'], - request_token_url=None, - access_token_url=config['BLENDER_ID_BASE_ACCESS_TOKEN_URL'], - authorize_url=config['BLENDER_ID_AUTHORIZE_URL'] - ) - - oauth_blender_id.tokengetter(get_blender_id_oauth_token) - log.info('OAuth Blender-ID login setup as %s', social_blender_id['app_id']) - - return oauth_blender_id - - def _get_current_user() -> UserClass: """Returns the current user as a UserClass instance. diff --git a/pillar/auth/oauth.py b/pillar/auth/oauth.py index 8e3a73d8..05f879f7 100644 --- a/pillar/auth/oauth.py +++ b/pillar/auth/oauth.py @@ -1,10 +1,10 @@ import json from rauth import OAuth2Service -from flask import current_app, url_for, request, redirect +from flask import current_app, url_for, request, redirect, session -class OAuthSignIn(object): +class OAuthSignIn: providers = None def __init__(self, provider_name): @@ -27,6 +27,7 @@ class OAuthSignIn(object): def get_provider(cls, provider_name): if cls.providers is None: cls.providers = {} + # TODO convert to the new __init_subclass__ for provider_class in cls.__subclasses__(): provider = provider_class() cls.providers[provider.provider_name] = provider @@ -35,7 +36,7 @@ class OAuthSignIn(object): class BlenderIdSignIn(OAuthSignIn): def __init__(self): - super(BlenderIdSignIn, self).__init__('blender-id') + super().__init__('blender-id') base_url = current_app.config['OAUTH_CREDENTIALS']['blender-id'].get( 'base_url', 'https://www.blender.org/id/') @@ -73,6 +74,7 @@ class BlenderIdSignIn(OAuthSignIn): me = oauth_session.get('user').json() # TODO handle case when user chooses not to disclose en email + session['blender_id_oauth_token'] = oauth_session.access_token return ( me['id'], me.get('email'), @@ -82,7 +84,7 @@ class BlenderIdSignIn(OAuthSignIn): class FacebookSignIn(OAuthSignIn): def __init__(self): - super(FacebookSignIn, self).__init__('facebook') + super().__init__('facebook') self.service = OAuth2Service( name='facebook', client_id=self.consumer_id, @@ -122,7 +124,7 @@ class FacebookSignIn(OAuthSignIn): class GoogleSignIn(OAuthSignIn): def __init__(self): - super(GoogleSignIn, self).__init__('google') + super().__init__('google') self.service = OAuth2Service( name='google', client_id=self.consumer_id, diff --git a/pillar/web/users/routes.py b/pillar/web/users/routes.py index 31bc3b82..85da6036 100644 --- a/pillar/web/users/routes.py +++ b/pillar/web/users/routes.py @@ -1,12 +1,10 @@ import json import logging -import requests from werkzeug import exceptions as wz_exceptions from flask import abort, Blueprint, current_app, flash, redirect, render_template, request, session,\ url_for from flask_login import login_required, logout_user, current_user -from flask_oauthlib.client import OAuthException from pillarsdk import exceptions as sdk_exceptions from pillarsdk.users import User @@ -16,6 +14,7 @@ import pillar.auth from pillar.web import system_util from pillar.api.local_auth import generate_and_store_token, get_local_user from pillar.api.utils.authentication import find_user_in_db, upsert_user +from pillar.api.blender_cloud.subscription import update_subscription from pillar.auth.oauth import OAuthSignIn from . import forms @@ -45,24 +44,20 @@ def oauth_callback(provider): if social_id is None: log.debug('Authentication failed for user with {}'.format(provider)) return redirect(url_for('main.homepage')) - # If login from Blender ID we use the token to create the user - if provider == 'blender-id': - session['blender_id_oauth_token'] = (access_token, '') - pillar.auth.login_user(access_token) - if current_user is not None: - # Check with the store for user roles. If the user has an active - # subscription, we apply the 'subscriber' role - api = system_util.pillar_api(token=access_token) - api.get('bcloud/update-subscription') - else: - # Find or create user - user_info = {'id': social_id, 'email': email, 'full_name': ''} - db_user = find_user_in_db(user_info, provider=provider) - db_id, status = upsert_user(db_user) - token = generate_and_store_token(db_id) - # Login user - pillar.auth.login_user(token['token']) + # Find or create user + user_info = {'id': social_id, 'email': email, 'full_name': ''} + db_user = find_user_in_db(user_info, provider=provider) + db_id, status = upsert_user(db_user) + token = generate_and_store_token(db_id) + + # Login user + pillar.auth.login_user(token['token'], load_from_db=True) + + if provider == 'blender-id' and current_user is not None: + # Check with the store for user roles. If the user has an active subscription, we apply + # the 'subscriber' role + update_subscription() next_after_login = session.pop('next_after_login', None) if next_after_login: diff --git a/requirements.txt b/requirements.txt index dd45c1fc..93ed09ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,6 @@ Flask==0.12.2 Flask-Cache==0.13.1 Flask-Script==2.0.5 Flask-Login==0.3.2 -Flask-OAuthlib==0.9.3 Flask-WTF==0.12 gcloud==0.12.0 google-apitools==0.4.11 @@ -24,6 +23,7 @@ ndg-httpsclient==0.4.0 Pillow==4.1.1 pycrypto==2.6.1 python-dateutil==2.5.3 +rauth==0.7.3 redis==2.10.5 WebOb==1.5.0 wheel==0.29.0