Skip to content

Commit

Permalink
Added combined authentication examples to the recipes doc.
Browse files Browse the repository at this point in the history
  • Loading branch information
airstandley committed Sep 25, 2019
1 parent 2fc0592 commit 6e99be8
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions docs/recipes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,129 @@ Here is a simple recipe for using Flask-Rebar with these pluggable views:
This isn't a super slick, classed based interface for Flask-Rebar, but it *is* a way to use unadulterated Flask views to their full intent with minimal `DRY <https://en.wikipedia.org/wiki/Don%27t_repeat_yourself>`_ violations.


Combining Security/Authentication
=================================

Authentication is hard, and complicated. Flask-Rebar supports custom Authenticator classes so that you can make
your authentication as complicated as your heart desires.

Sometime though you want to combine security requirements.
Maybe an endpoint should allow either an admin user or a user with an "edit" permission,
maybe you want to allow requests to use Auth0 or an Api Key,
maybe you want to only authenticate if it's Sunday and Jupiter is in retrograde?

Here are some simple recipes for what Flask-Rebar currently supports:


Allow a user with either scope "A" OR scope "B"

.. code-block:: python
from flask import g
from my_app import authenticator, registry
from my_app.scheme import EditStuffSchema, StuffSchema
# Allow a user with the "admin" scope OR the "edit:stuff" scope
@registry.handles(
rule="/stuff/<uid:thing>/",
method="POST",e
request_body_schema=EditStuffSchema(),
response_body_schema=StuffSchema(),
authenticators=[authenticator.with_scope("admin"), authenticator.with_scope("edit:stuff")]
)
def edit_stuff(thing):
update_stuff(thing, g.validated_body)
return thing
Allow a request with either valid Auth0 OR an API-Key

.. code-block:: python
from flask import g
from flask_rebar.authenticators import HeaderApiKeyAuthenticator
from flask_rebar_auth0 import get_authenticated_user
from my_app import authenticator, registry
# Allow Auth0 or API Key
@registry.handles(
rule="/rate_limit/",
method="GET",
response_body_schema=RateLimitSchema(),
authenticators=[authenticator, HeaderApiKeyAuthenticator("X-API-KEY")]
)
def get_limits():
requester = g.authenticated_app_name or get_authenticated_user()
rate_limit = get_limits_for_app_or_user(requester)
return rate_limit
Allow a request with Auth0 AND an API-Key

.. note::
This currently requires some workarounds. Better support is planned.

.. code-block:: python
from flask_rebar.authenticators import HeaderApiKeyAuthenticator
from flask_rebar_auth0 import get_authenticated_user, Auth0Authenticator
from my_app import authenticator
from flask_rebar.swagger_generation.authenticator_to_swagger import (
AuthenticatorConverter, authenticator_converter_registry
)
class CombindedAuthenticator(Auth0Authenticator, HeaderApiKeyAuthenticator):
def __init__(app, header):
Auth0Authenticator.__init__(self, app)
HeaderApiKeyAuthenticator.__init__(self, header)
def authenticate(self):
authenticator.authenticate(self)
HeaderAPIKeyAuthenticator.authenticate(self)
auth0_converter = authenticator_converter_registry._get_converter_for_type(authenticator)
header_api_converter = authenticator_converter_registry._get_converter_for_type(HeaderApiKeyAuthenticator("header"))
class CombinedAuthenticatorConverter(AuthenticatorConverter):
AUTHENTICATOR_TYPE = CombindedAuthenticator
def get_security_schemes(self, obj, context):
definition = dict()
definition.update(auth0_converter.get_security_schemes(obj, context))
definition.update(header_api_converter.get_security_schemes(obj, context))
return definition
def get_security_requirements(self, obj, context):
auth_requirement = auth0_converter.get_security_requirements(obj, context)[0]
header_requirement = header_api_converter.get_security_requirements(obj, context)[0]
combined_requirement = dict()
combined_requirement.update(auth_requirement)
combined_requirement.update(header_requirement)
return [
combined_requirement
]
authenticator_converter_registry.register_type(CombinedAuthenticatorConverter)
@registry.handles(
rule="/user/me/api_token",
method="GET",
authenticators=CombinedAuthenticatorConverter(app, "X-API-Key")
)
def check_token():
return 200

0 comments on commit 6e99be8

Please sign in to comment.