venv added, updated
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# flake8: noqa
|
||||
|
||||
from .authorization_server import AuthorizationServer
|
||||
from .resource_protector import ResourceProtector, current_credential
|
||||
from .cache import (
|
||||
register_nonce_hooks,
|
||||
register_temporary_credential_hooks,
|
||||
create_exists_nonce_func,
|
||||
)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,182 @@
|
||||
import logging
|
||||
from werkzeug.utils import import_string
|
||||
from flask import Response
|
||||
from flask import request as flask_req
|
||||
from authlib.oauth1 import (
|
||||
OAuth1Request,
|
||||
AuthorizationServer as _AuthorizationServer,
|
||||
)
|
||||
from authlib.common.security import generate_token
|
||||
from authlib.common.urls import url_encode
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AuthorizationServer(_AuthorizationServer):
|
||||
"""Flask implementation of :class:`authlib.rfc5849.AuthorizationServer`.
|
||||
Initialize it with Flask app instance, client model class and cache::
|
||||
|
||||
server = AuthorizationServer(app=app, query_client=query_client)
|
||||
# or initialize lazily
|
||||
server = AuthorizationServer()
|
||||
server.init_app(app, query_client=query_client)
|
||||
|
||||
:param app: A Flask app instance
|
||||
:param query_client: A function to get client by client_id. The client
|
||||
model class MUST implement the methods described by
|
||||
:class:`~authlib.oauth1.rfc5849.ClientMixin`.
|
||||
:param token_generator: A function to generate token
|
||||
"""
|
||||
|
||||
def __init__(self, app=None, query_client=None, token_generator=None):
|
||||
self.app = app
|
||||
self.query_client = query_client
|
||||
self.token_generator = token_generator
|
||||
|
||||
self._hooks = {
|
||||
'exists_nonce': None,
|
||||
'create_temporary_credential': None,
|
||||
'get_temporary_credential': None,
|
||||
'delete_temporary_credential': None,
|
||||
'create_authorization_verifier': None,
|
||||
'create_token_credential': None,
|
||||
}
|
||||
if app is not None:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app, query_client=None, token_generator=None):
|
||||
if query_client is not None:
|
||||
self.query_client = query_client
|
||||
if token_generator is not None:
|
||||
self.token_generator = token_generator
|
||||
|
||||
if self.token_generator is None:
|
||||
self.token_generator = self.create_token_generator(app)
|
||||
|
||||
methods = app.config.get('OAUTH1_SUPPORTED_SIGNATURE_METHODS')
|
||||
if methods and isinstance(methods, (list, tuple)):
|
||||
self.SUPPORTED_SIGNATURE_METHODS = methods
|
||||
|
||||
self.app = app
|
||||
|
||||
def register_hook(self, name, func):
|
||||
if name not in self._hooks:
|
||||
raise ValueError('Invalid "name" of hook')
|
||||
self._hooks[name] = func
|
||||
|
||||
def create_token_generator(self, app):
|
||||
token_generator = app.config.get('OAUTH1_TOKEN_GENERATOR')
|
||||
|
||||
if isinstance(token_generator, str):
|
||||
token_generator = import_string(token_generator)
|
||||
else:
|
||||
length = app.config.get('OAUTH1_TOKEN_LENGTH', 42)
|
||||
|
||||
def token_generator():
|
||||
return generate_token(length)
|
||||
|
||||
secret_generator = app.config.get('OAUTH1_TOKEN_SECRET_GENERATOR')
|
||||
if isinstance(secret_generator, str):
|
||||
secret_generator = import_string(secret_generator)
|
||||
else:
|
||||
length = app.config.get('OAUTH1_TOKEN_SECRET_LENGTH', 48)
|
||||
|
||||
def secret_generator():
|
||||
return generate_token(length)
|
||||
|
||||
def create_token():
|
||||
return {
|
||||
'oauth_token': token_generator(),
|
||||
'oauth_token_secret': secret_generator()
|
||||
}
|
||||
return create_token
|
||||
|
||||
def get_client_by_id(self, client_id):
|
||||
return self.query_client(client_id)
|
||||
|
||||
def exists_nonce(self, nonce, request):
|
||||
func = self._hooks['exists_nonce']
|
||||
if callable(func):
|
||||
timestamp = request.timestamp
|
||||
client_id = request.client_id
|
||||
token = request.token
|
||||
return func(nonce, timestamp, client_id, token)
|
||||
|
||||
raise RuntimeError('"exists_nonce" hook is required.')
|
||||
|
||||
def create_temporary_credential(self, request):
|
||||
func = self._hooks['create_temporary_credential']
|
||||
if callable(func):
|
||||
token = self.token_generator()
|
||||
return func(token, request.client_id, request.redirect_uri)
|
||||
raise RuntimeError(
|
||||
'"create_temporary_credential" hook is required.'
|
||||
)
|
||||
|
||||
def get_temporary_credential(self, request):
|
||||
func = self._hooks['get_temporary_credential']
|
||||
if callable(func):
|
||||
return func(request.token)
|
||||
|
||||
raise RuntimeError(
|
||||
'"get_temporary_credential" hook is required.'
|
||||
)
|
||||
|
||||
def delete_temporary_credential(self, request):
|
||||
func = self._hooks['delete_temporary_credential']
|
||||
if callable(func):
|
||||
return func(request.token)
|
||||
|
||||
raise RuntimeError(
|
||||
'"delete_temporary_credential" hook is required.'
|
||||
)
|
||||
|
||||
def create_authorization_verifier(self, request):
|
||||
func = self._hooks['create_authorization_verifier']
|
||||
if callable(func):
|
||||
verifier = generate_token(36)
|
||||
func(request.credential, request.user, verifier)
|
||||
return verifier
|
||||
|
||||
raise RuntimeError(
|
||||
'"create_authorization_verifier" hook is required.'
|
||||
)
|
||||
|
||||
def create_token_credential(self, request):
|
||||
func = self._hooks['create_token_credential']
|
||||
if callable(func):
|
||||
temporary_credential = request.credential
|
||||
token = self.token_generator()
|
||||
return func(token, temporary_credential)
|
||||
|
||||
raise RuntimeError(
|
||||
'"create_token_credential" hook is required.'
|
||||
)
|
||||
|
||||
def check_authorization_request(self):
|
||||
req = self.create_oauth1_request(None)
|
||||
self.validate_authorization_request(req)
|
||||
return req
|
||||
|
||||
def create_authorization_response(self, request=None, grant_user=None):
|
||||
return super()\
|
||||
.create_authorization_response(request, grant_user)
|
||||
|
||||
def create_token_response(self, request=None):
|
||||
return super().create_token_response(request)
|
||||
|
||||
def create_oauth1_request(self, request):
|
||||
if request is None:
|
||||
request = flask_req
|
||||
if request.method in ('POST', 'PUT'):
|
||||
body = request.form.to_dict(flat=True)
|
||||
else:
|
||||
body = None
|
||||
return OAuth1Request(request.method, request.url, body, request.headers)
|
||||
|
||||
def handle_response(self, status_code, payload, headers):
|
||||
return Response(
|
||||
url_encode(payload),
|
||||
status=status_code,
|
||||
headers=headers
|
||||
)
|
||||
@@ -0,0 +1,80 @@
|
||||
from authlib.oauth1 import TemporaryCredential
|
||||
|
||||
|
||||
def register_temporary_credential_hooks(
|
||||
authorization_server, cache, key_prefix='temporary_credential:'):
|
||||
"""Register temporary credential related hooks to authorization server.
|
||||
|
||||
:param authorization_server: AuthorizationServer instance
|
||||
:param cache: Cache instance
|
||||
:param key_prefix: key prefix for temporary credential
|
||||
"""
|
||||
|
||||
def create_temporary_credential(token, client_id, redirect_uri):
|
||||
key = key_prefix + token['oauth_token']
|
||||
token['client_id'] = client_id
|
||||
if redirect_uri:
|
||||
token['oauth_callback'] = redirect_uri
|
||||
|
||||
cache.set(key, token, timeout=86400) # cache for one day
|
||||
return TemporaryCredential(token)
|
||||
|
||||
def get_temporary_credential(oauth_token):
|
||||
if not oauth_token:
|
||||
return None
|
||||
key = key_prefix + oauth_token
|
||||
value = cache.get(key)
|
||||
if value:
|
||||
return TemporaryCredential(value)
|
||||
|
||||
def delete_temporary_credential(oauth_token):
|
||||
if oauth_token:
|
||||
key = key_prefix + oauth_token
|
||||
cache.delete(key)
|
||||
|
||||
def create_authorization_verifier(credential, grant_user, verifier):
|
||||
key = key_prefix + credential.get_oauth_token()
|
||||
credential['oauth_verifier'] = verifier
|
||||
credential['user_id'] = grant_user.get_user_id()
|
||||
cache.set(key, credential, timeout=86400)
|
||||
return credential
|
||||
|
||||
authorization_server.register_hook(
|
||||
'create_temporary_credential', create_temporary_credential)
|
||||
authorization_server.register_hook(
|
||||
'get_temporary_credential', get_temporary_credential)
|
||||
authorization_server.register_hook(
|
||||
'delete_temporary_credential', delete_temporary_credential)
|
||||
authorization_server.register_hook(
|
||||
'create_authorization_verifier', create_authorization_verifier)
|
||||
|
||||
|
||||
def create_exists_nonce_func(cache, key_prefix='nonce:', expires=86400):
|
||||
"""Create an ``exists_nonce`` function that can be used in hooks and
|
||||
resource protector.
|
||||
|
||||
:param cache: Cache instance
|
||||
:param key_prefix: key prefix for temporary credential
|
||||
:param expires: Expire time for nonce
|
||||
"""
|
||||
def exists_nonce(nonce, timestamp, client_id, oauth_token):
|
||||
key = f'{key_prefix}{nonce}-{timestamp}-{client_id}'
|
||||
if oauth_token:
|
||||
key = f'{key}-{oauth_token}'
|
||||
rv = cache.has(key)
|
||||
cache.set(key, 1, timeout=expires)
|
||||
return rv
|
||||
return exists_nonce
|
||||
|
||||
|
||||
def register_nonce_hooks(
|
||||
authorization_server, cache, key_prefix='nonce:', expires=86400):
|
||||
"""Register nonce related hooks to authorization server.
|
||||
|
||||
:param authorization_server: AuthorizationServer instance
|
||||
:param cache: Cache instance
|
||||
:param key_prefix: key prefix for temporary credential
|
||||
:param expires: Expire time for nonce
|
||||
"""
|
||||
exists_nonce = create_exists_nonce_func(cache, key_prefix, expires)
|
||||
authorization_server.register_hook('exists_nonce', exists_nonce)
|
||||
@@ -0,0 +1,113 @@
|
||||
import functools
|
||||
from flask import g, json, Response
|
||||
from flask import request as _req
|
||||
from werkzeug.local import LocalProxy
|
||||
from authlib.consts import default_json_headers
|
||||
from authlib.oauth1 import ResourceProtector as _ResourceProtector
|
||||
from authlib.oauth1.errors import OAuth1Error
|
||||
|
||||
|
||||
class ResourceProtector(_ResourceProtector):
|
||||
"""A protecting method for resource servers. Initialize a resource
|
||||
protector with the these method:
|
||||
|
||||
1. query_client
|
||||
2. query_token,
|
||||
3. exists_nonce
|
||||
|
||||
Usually, a ``query_client`` method would look like (if using SQLAlchemy)::
|
||||
|
||||
def query_client(client_id):
|
||||
return Client.query.filter_by(client_id=client_id).first()
|
||||
|
||||
A ``query_token`` method accept two parameters, ``client_id`` and ``oauth_token``::
|
||||
|
||||
def query_token(client_id, oauth_token):
|
||||
return Token.query.filter_by(client_id=client_id, oauth_token=oauth_token).first()
|
||||
|
||||
And for ``exists_nonce``, if using cache, we have a built-in hook to create this method::
|
||||
|
||||
from authlib.integrations.flask_oauth1 import create_exists_nonce_func
|
||||
|
||||
exists_nonce = create_exists_nonce_func(cache)
|
||||
|
||||
Then initialize the resource protector with those methods::
|
||||
|
||||
require_oauth = ResourceProtector(
|
||||
app, query_client=query_client,
|
||||
query_token=query_token, exists_nonce=exists_nonce,
|
||||
)
|
||||
"""
|
||||
def __init__(self, app=None, query_client=None,
|
||||
query_token=None, exists_nonce=None):
|
||||
self.query_client = query_client
|
||||
self.query_token = query_token
|
||||
self._exists_nonce = exists_nonce
|
||||
|
||||
self.app = app
|
||||
if app:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app, query_client=None, query_token=None,
|
||||
exists_nonce=None):
|
||||
if query_client is not None:
|
||||
self.query_client = query_client
|
||||
if query_token is not None:
|
||||
self.query_token = query_token
|
||||
if exists_nonce is not None:
|
||||
self._exists_nonce = exists_nonce
|
||||
|
||||
methods = app.config.get('OAUTH1_SUPPORTED_SIGNATURE_METHODS')
|
||||
if methods and isinstance(methods, (list, tuple)):
|
||||
self.SUPPORTED_SIGNATURE_METHODS = methods
|
||||
|
||||
self.app = app
|
||||
|
||||
def get_client_by_id(self, client_id):
|
||||
return self.query_client(client_id)
|
||||
|
||||
def get_token_credential(self, request):
|
||||
return self.query_token(request.client_id, request.token)
|
||||
|
||||
def exists_nonce(self, nonce, request):
|
||||
if not self._exists_nonce:
|
||||
raise RuntimeError('"exists_nonce" function is required.')
|
||||
|
||||
timestamp = request.timestamp
|
||||
client_id = request.client_id
|
||||
token = request.token
|
||||
return self._exists_nonce(nonce, timestamp, client_id, token)
|
||||
|
||||
def acquire_credential(self):
|
||||
req = self.validate_request(
|
||||
_req.method,
|
||||
_req.url,
|
||||
_req.form.to_dict(flat=True),
|
||||
_req.headers
|
||||
)
|
||||
g.authlib_server_oauth1_credential = req.credential
|
||||
return req.credential
|
||||
|
||||
def __call__(self, scope=None):
|
||||
def wrapper(f):
|
||||
@functools.wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
try:
|
||||
self.acquire_credential()
|
||||
except OAuth1Error as error:
|
||||
body = dict(error.get_body())
|
||||
return Response(
|
||||
json.dumps(body),
|
||||
status=error.status_code,
|
||||
headers=default_json_headers,
|
||||
)
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
return wrapper
|
||||
|
||||
|
||||
def _get_current_credential():
|
||||
return g.get('authlib_server_oauth1_credential')
|
||||
|
||||
|
||||
current_credential = LocalProxy(_get_current_credential)
|
||||
Reference in New Issue
Block a user