Remove Flask-OAuthlib and oauth_blender_id from Pillar
We switch completely to a rauth-based approach, allowing multiple providers for authentication.
This commit is contained in:
@@ -115,7 +115,6 @@ class PillarServer(Eve):
|
|||||||
|
|
||||||
# Configure authentication
|
# Configure authentication
|
||||||
self.login_manager = auth.config_login_manager(self)
|
self.login_manager = auth.config_login_manager(self)
|
||||||
self.oauth_blender_id = auth.config_oauth_login(self)
|
|
||||||
|
|
||||||
self._config_caching()
|
self._config_caching()
|
||||||
|
|
||||||
|
@@ -9,7 +9,8 @@ import logging
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
from bson import tz_util
|
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 requests.adapters import HTTPAdapter
|
||||||
|
|
||||||
from pillar.api.utils import authentication
|
from pillar.api.utils import authentication
|
||||||
@@ -175,23 +176,26 @@ def fetch_blenderid_user() -> dict:
|
|||||||
|
|
||||||
bid_url = '%s/api/user' % blender_id_endpoint()
|
bid_url = '%s/api/user' % blender_id_endpoint()
|
||||||
log.debug('Fetching user info from %s', bid_url)
|
log.debug('Fetching user info from %s', bid_url)
|
||||||
|
|
||||||
try:
|
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:
|
except httplib2.HttpLib2Error:
|
||||||
log.exception('Error getting %s from BlenderID', bid_url)
|
log.exception('Error getting %s from BlenderID', bid_url)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if bid_resp.status != 200:
|
if bid_resp.status_code != 200:
|
||||||
log.warning('Error %i from BlenderID %s: %s', bid_resp.status, bid_url, bid_resp.data)
|
log.warning('Error %i from BlenderID %s: %s', bid_resp.status_code, bid_url, bid_resp.data)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not bid_resp.data:
|
if not bid_resp.json():
|
||||||
log.warning('Empty data returned from BlenderID %s', bid_url)
|
log.warning('Empty data returned from BlenderID %s', bid_url)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
log.debug('BlenderID returned %s', bid_resp.data)
|
log.debug('BlenderID returned %s', bid_resp.json())
|
||||||
return bid_resp.data
|
return bid_resp.json()
|
||||||
|
|
||||||
|
|
||||||
def setup_app(app, url_prefix):
|
def setup_app(app, url_prefix):
|
||||||
|
@@ -6,7 +6,6 @@ import typing
|
|||||||
|
|
||||||
from flask import session, g
|
from flask import session, g
|
||||||
import flask_login
|
import flask_login
|
||||||
import flask_oauthlib.client
|
|
||||||
from werkzeug.local import LocalProxy
|
from werkzeug.local import LocalProxy
|
||||||
|
|
||||||
from pillar import current_app
|
from pillar import current_app
|
||||||
@@ -222,35 +221,6 @@ def get_blender_id_oauth_token():
|
|||||||
return None
|
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:
|
def _get_current_user() -> UserClass:
|
||||||
"""Returns the current user as a UserClass instance.
|
"""Returns the current user as a UserClass instance.
|
||||||
|
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from rauth import OAuth2Service
|
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
|
providers = None
|
||||||
|
|
||||||
def __init__(self, provider_name):
|
def __init__(self, provider_name):
|
||||||
@@ -27,6 +27,7 @@ class OAuthSignIn(object):
|
|||||||
def get_provider(cls, provider_name):
|
def get_provider(cls, provider_name):
|
||||||
if cls.providers is None:
|
if cls.providers is None:
|
||||||
cls.providers = {}
|
cls.providers = {}
|
||||||
|
# TODO convert to the new __init_subclass__
|
||||||
for provider_class in cls.__subclasses__():
|
for provider_class in cls.__subclasses__():
|
||||||
provider = provider_class()
|
provider = provider_class()
|
||||||
cls.providers[provider.provider_name] = provider
|
cls.providers[provider.provider_name] = provider
|
||||||
@@ -35,7 +36,7 @@ class OAuthSignIn(object):
|
|||||||
|
|
||||||
class BlenderIdSignIn(OAuthSignIn):
|
class BlenderIdSignIn(OAuthSignIn):
|
||||||
def __init__(self):
|
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 = current_app.config['OAUTH_CREDENTIALS']['blender-id'].get(
|
||||||
'base_url', 'https://www.blender.org/id/')
|
'base_url', 'https://www.blender.org/id/')
|
||||||
@@ -73,6 +74,7 @@ class BlenderIdSignIn(OAuthSignIn):
|
|||||||
|
|
||||||
me = oauth_session.get('user').json()
|
me = oauth_session.get('user').json()
|
||||||
# TODO handle case when user chooses not to disclose en email
|
# TODO handle case when user chooses not to disclose en email
|
||||||
|
session['blender_id_oauth_token'] = oauth_session.access_token
|
||||||
return (
|
return (
|
||||||
me['id'],
|
me['id'],
|
||||||
me.get('email'),
|
me.get('email'),
|
||||||
@@ -82,7 +84,7 @@ class BlenderIdSignIn(OAuthSignIn):
|
|||||||
|
|
||||||
class FacebookSignIn(OAuthSignIn):
|
class FacebookSignIn(OAuthSignIn):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(FacebookSignIn, self).__init__('facebook')
|
super().__init__('facebook')
|
||||||
self.service = OAuth2Service(
|
self.service = OAuth2Service(
|
||||||
name='facebook',
|
name='facebook',
|
||||||
client_id=self.consumer_id,
|
client_id=self.consumer_id,
|
||||||
@@ -122,7 +124,7 @@ class FacebookSignIn(OAuthSignIn):
|
|||||||
|
|
||||||
class GoogleSignIn(OAuthSignIn):
|
class GoogleSignIn(OAuthSignIn):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(GoogleSignIn, self).__init__('google')
|
super().__init__('google')
|
||||||
self.service = OAuth2Service(
|
self.service = OAuth2Service(
|
||||||
name='google',
|
name='google',
|
||||||
client_id=self.consumer_id,
|
client_id=self.consumer_id,
|
||||||
|
@@ -1,12 +1,10 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import requests
|
|
||||||
|
|
||||||
from werkzeug import exceptions as wz_exceptions
|
from werkzeug import exceptions as wz_exceptions
|
||||||
from flask import abort, Blueprint, current_app, flash, redirect, render_template, request, session,\
|
from flask import abort, Blueprint, current_app, flash, redirect, render_template, request, session,\
|
||||||
url_for
|
url_for
|
||||||
from flask_login import login_required, logout_user, current_user
|
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 import exceptions as sdk_exceptions
|
||||||
from pillarsdk.users import User
|
from pillarsdk.users import User
|
||||||
@@ -16,6 +14,7 @@ import pillar.auth
|
|||||||
from pillar.web import system_util
|
from pillar.web import system_util
|
||||||
from pillar.api.local_auth import generate_and_store_token, get_local_user
|
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.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 pillar.auth.oauth import OAuthSignIn
|
||||||
from . import forms
|
from . import forms
|
||||||
|
|
||||||
@@ -45,24 +44,20 @@ def oauth_callback(provider):
|
|||||||
if social_id is None:
|
if social_id is None:
|
||||||
log.debug('Authentication failed for user with {}'.format(provider))
|
log.debug('Authentication failed for user with {}'.format(provider))
|
||||||
return redirect(url_for('main.homepage'))
|
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
|
# Find or create user
|
||||||
user_info = {'id': social_id, 'email': email, 'full_name': ''}
|
user_info = {'id': social_id, 'email': email, 'full_name': ''}
|
||||||
db_user = find_user_in_db(user_info, provider=provider)
|
db_user = find_user_in_db(user_info, provider=provider)
|
||||||
db_id, status = upsert_user(db_user)
|
db_id, status = upsert_user(db_user)
|
||||||
token = generate_and_store_token(db_id)
|
token = generate_and_store_token(db_id)
|
||||||
|
|
||||||
# Login user
|
# Login user
|
||||||
pillar.auth.login_user(token['token'])
|
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)
|
next_after_login = session.pop('next_after_login', None)
|
||||||
if next_after_login:
|
if next_after_login:
|
||||||
|
@@ -14,7 +14,6 @@ Flask==0.12.2
|
|||||||
Flask-Cache==0.13.1
|
Flask-Cache==0.13.1
|
||||||
Flask-Script==2.0.5
|
Flask-Script==2.0.5
|
||||||
Flask-Login==0.3.2
|
Flask-Login==0.3.2
|
||||||
Flask-OAuthlib==0.9.3
|
|
||||||
Flask-WTF==0.12
|
Flask-WTF==0.12
|
||||||
gcloud==0.12.0
|
gcloud==0.12.0
|
||||||
google-apitools==0.4.11
|
google-apitools==0.4.11
|
||||||
@@ -24,6 +23,7 @@ ndg-httpsclient==0.4.0
|
|||||||
Pillow==4.1.1
|
Pillow==4.1.1
|
||||||
pycrypto==2.6.1
|
pycrypto==2.6.1
|
||||||
python-dateutil==2.5.3
|
python-dateutil==2.5.3
|
||||||
|
rauth==0.7.3
|
||||||
redis==2.10.5
|
redis==2.10.5
|
||||||
WebOb==1.5.0
|
WebOb==1.5.0
|
||||||
wheel==0.29.0
|
wheel==0.29.0
|
||||||
|
Reference in New Issue
Block a user