OAuth signin: streamlined instantiation of OAuthSignIn subclasses

This commit is contained in:
Sybren A. Stüvel 2017-08-25 12:35:08 +02:00
parent add2538655
commit c7c867f1c7

View File

@ -1,6 +1,7 @@
import abc
import attr
import json
import logging
from rauth import OAuth2Service
from flask import current_app, url_for, request, redirect, session, Response
@ -32,14 +33,22 @@ class OAuthCodeNotProvided(OAuthError):
"""Raised when the 'code' arg is not provided in the OAuth callback."""
class OAuthSignIn(metaclass=abc.ABCMeta):
_providers = None # initialized in get_provider()
class ProviderNotConfigured:
"""Dummy class that indicates a provider isn't configured."""
def __init__(self, provider_name):
self.provider_name = provider_name
credentials = current_app.config['OAUTH_CREDENTIALS'].get(provider_name)
class OAuthSignIn(metaclass=abc.ABCMeta):
provider_name: str = None # set in each subclass.
_providers = None # initialized in get_provider()
_log = logging.getLogger(f'{__name__}.OAuthSignIn')
def __init__(self):
credentials = current_app.config['OAUTH_CREDENTIALS'].get(self.provider_name)
if not credentials:
raise ProviderConfigurationMissing(f'Missing OAuth credentials for {provider_name}')
raise ProviderConfigurationMissing(
f'Missing OAuth credentials for {self.provider_name}')
self.consumer_id = credentials['id']
self.consumer_secret = credentials['secret']
@ -90,25 +99,37 @@ class OAuthSignIn(metaclass=abc.ABCMeta):
@classmethod
def get_provider(cls, provider_name) -> 'OAuthSignIn':
if cls._providers is None:
cls._init_providers()
try:
provider = cls._providers[provider_name]
except KeyError:
raise ProviderNotImplemented(f'No such OAuth provider {provider_name}')
if provider is ProviderNotConfigured:
raise ProviderConfigurationMissing(f'OAuth provider {provider_name} not configured')
return provider
@classmethod
def _init_providers(cls):
cls._providers = {}
# TODO convert to the new __init_subclass__
for provider_class in cls.__subclasses__():
try:
provider = provider_class()
except ProviderConfigurationMissing:
# TODO: log this at info level
pass
else:
cls._providers[provider.provider_name] = provider
try:
return cls._providers[provider_name]
except KeyError:
raise ProviderNotImplemented(f'No such OAuth provider {provider_name}')
cls._log.info('OAuth provider %s not configured',
provider_class.provider_name)
provider = ProviderNotConfigured
cls._providers[provider_class.provider_name] = provider
class BlenderIdSignIn(OAuthSignIn):
provider_name = 'blender-id'
def __init__(self):
super().__init__('blender-id')
super().__init__()
base_url = current_app.config['OAUTH_CREDENTIALS']['blender-id'].get(
'base_url', 'https://www.blender.org/id/')
@ -139,8 +160,10 @@ class BlenderIdSignIn(OAuthSignIn):
class FacebookSignIn(OAuthSignIn):
provider_name = 'facebook'
def __init__(self):
super().__init__('facebook')
super().__init__()
self.service = OAuth2Service(
name='facebook',
client_id=self.consumer_id,
@ -167,8 +190,10 @@ class FacebookSignIn(OAuthSignIn):
class GoogleSignIn(OAuthSignIn):
provider_name = 'google'
def __init__(self):
super().__init__('google')
super().__init__()
self.service = OAuth2Service(
name='google',
client_id=self.consumer_id,