def create_app(): app = Flask(__name__) app.config.from_pyfile('config.py') cache.init_app(app, config=app.config['CACHE_CONFIG']) cors.init_app(app, origins=app.config['ALLOWED_ORIGINS']) db.init_app(app) migrate.init_app(app, db) scheduler.init_app(app) scheduler.start() authenticator = HeaderApiKeyAuthenticator(header=app.config['AUTH_HEADER']) authenticator.register_key(key=app.config['AUTH_KEY'], app_name=app.config['AUTH_ALLOWED_CLIENT']) registry.set_default_authenticator(authenticator) # IMPORTANT: import the views before rebar initialisation from backend.example.endpoints import get_user rebar.init_app(app) # suppress werkzeug logging (see README) log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) # log with our app logger @app.after_request def log_request(response): app.logger.info(response.status) return response return app
def create_app(name): app = Flask(name) authenticator = HeaderApiKeyAuthenticator(header="X-MyApp-Key") # The HeaderApiKeyAuthenticator does super simple authentication, designed for # service-to-service authentication inside of a protected network, by looking for a # shared secret in the specified header. Here we define what that shared secret is. authenticator.register_key(key="my-api-key") registry.set_default_authenticator(authenticator=authenticator) rebar.init_app(app=app) return app
def register_multiple_authenticators(registry): default_authenticator = HeaderApiKeyAuthenticator( header=DEFAULT_AUTH_HEADER, name="default") default_authenticator.register_key(app_name="internal", key=DEFAULT_AUTH_SECRET) alternative_default_authenticator = HeaderApiKeyAuthenticator( header=DEFAULT_ALTERNATIVE_AUTH_HEADER, name="alternative") alternative_default_authenticator.register_key( app_name="internal", key=DEFAULT_ALTERNATIVE_AUTH_SECRET) registry.set_default_authenticators( (default_authenticator, alternative_default_authenticator))
def test_override_authenticator(self): auth_header = 'x-overridden-auth' auth_secret = 'BLAM!' rebar = Rebar() registry = rebar.create_handler_registry() register_default_authenticator(registry) authenticator = HeaderApiKeyAuthenticator(header=auth_header) authenticator.register_key(app_name='internal', key=auth_secret) register_endpoint(registry, authenticator=authenticator) app = create_rebar_app(rebar) resp = app.test_client().get(path='/foos/1', headers=auth_headers(header=auth_header, secret=auth_secret)) self.assertEqual(resp.status_code, 200) self.assertEqual(get_json_from_resp(resp), DEFAULT_RESPONSE) # The default authentication doesn't work anymore! resp = app.test_client().get(path='/foos/1', headers=auth_headers()) self.assertEqual(resp.status_code, 401)
import marshmallow as m from flask_rebar import Rebar from flask_rebar import HeaderApiKeyAuthenticator from flask_rebar import compat from flask_rebar.swagger_generation import SwaggerV2Generator, SwaggerV3Generator rebar = Rebar() registry = rebar.create_handler_registry() swagger_v2_generator = SwaggerV2Generator() swagger_v3_generator_with_hidden = SwaggerV3Generator(include_hidden=True) normal_swagger_v3_generator = SwaggerV3Generator() authenticator = HeaderApiKeyAuthenticator(header="x-auth") default_authenticator = HeaderApiKeyAuthenticator(header="x-another", name="default") class HeaderSchema(m.Schema): user_id = compat.set_data_key(field=m.fields.String(required=True), key="X-UserId") class FooSchema(m.Schema): __swagger_title__ = "Foo" uid = m.fields.String() name = m.fields.String() class NestedFoosSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True)
def register_default_authenticator(registry): default_authenticator = HeaderApiKeyAuthenticator( header=DEFAULT_AUTH_HEADER, name='default') default_authenticator.register_key(app_name='internal', key=DEFAULT_AUTH_SECRET) registry.set_default_authenticator(default_authenticator)
def get_security_requirements(self, instance, context): return [{ "openIDConnect": instance.required_scopes, "application_key": [] }] authenticator_converter_registry.register_types([ HeaderApiKeyConverter(), HTTPAuthorizationAuthenticatorConverter(), OAuth2AuthenticatorConverter(), ComplexAuthenticatorConverter(), ]) default_authenticator = FakeOAuth2Authenticator(required_scopes=["read:stuff"]) alternative_default_authenticator = HeaderApiKeyAuthenticator( header="x-api-key") authenticator = FakeHTTPAuthorizationAuthenticator() alternative_authenticator = FakeComplexAuthenticator( header="x-app-id", url="https://exmaple.com/openconnect", required_scopes=["write:junk", "write:stuff"], ) customer_authenticator_converter_registry = [ HTTPAuthorizationAuthenticatorConverter(), OAuth2AuthenticatorConverter(), ComplexAuthenticatorConverter(), ]
def test_generate_swagger(self): rebar = Rebar() registry = rebar.create_handler_registry() authenticator = HeaderApiKeyAuthenticator(header='x-auth') default_authenticator = HeaderApiKeyAuthenticator(header='x-another', name='default') class HeaderSchema(m.Schema): user_id = m.fields.String(load_from='x-userid', required=True) class FooSchema(m.Schema): __swagger_title__ = 'Foo' uid = m.fields.String() name = m.fields.String() class ListOfFooSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True) class FooUpdateSchema(m.Schema): __swagger_title = 'FooUpdate' name = m.fields.String() class FooListSchema(m.Schema): name = m.fields.String() @registry.handles(rule='/foos/<uuid_string:foo_uid>', method='GET', marshal_schema={200: FooSchema()}, headers_schema=HeaderSchema()) def get_foo(foo_uid): """helpful description""" pass @registry.handles(rule='/foos/<foo_uid>', method='PATCH', marshal_schema={200: FooSchema()}, request_body_schema=FooUpdateSchema(), authenticator=authenticator) def update_foo(foo_uid): pass @registry.handles( rule='/foos', method='GET', marshal_schema={200: ListOfFooSchema()}, query_string_schema=FooListSchema(), authenticator=None # Override the default! ) def list_foos(): pass registry.set_default_authenticator(default_authenticator) host = 'swag.com' schemes = ['http'] consumes = ['application/json'] produces = ['application/vnd.plangrid+json'] title = 'Test API' version = '2.1.0' class Error(m.Schema): message = m.fields.String() details = m.fields.Dict() generator = SwaggerV2Generator(host=host, schemes=schemes, consumes=consumes, produces=produces, title=title, version=version, default_response_schema=Error()) swagger = generator.generate(registry) expected_swagger = { 'swagger': '2.0', 'host': host, 'info': { 'title': title, 'version': version, 'description': '', }, 'schemes': schemes, 'consumes': consumes, 'produces': produces, 'security': [{ 'default': [] }], 'securityDefinitions': { 'sharedSecret': { 'type': 'apiKey', 'in': 'header', 'name': 'x-auth' }, 'default': { 'type': 'apiKey', 'in': 'header', 'name': 'x-another' } }, 'paths': { '/foos/{foo_uid}': { 'parameters': [{ 'name': 'foo_uid', 'in': 'path', 'required': True, 'type': 'string' }], 'get': { 'operationId': 'get_foo', 'description': 'helpful description', 'responses': { '200': { 'description': 'Foo', 'schema': { '$ref': '#/definitions/Foo' } }, 'default': { 'description': 'Error', 'schema': { '$ref': '#/definitions/Error' } } }, 'parameters': [{ 'name': 'x-userid', 'in': 'header', 'required': True, 'type': 'string' }] }, 'patch': { 'operationId': 'update_foo', 'responses': { '200': { 'description': 'Foo', 'schema': { '$ref': '#/definitions/Foo' } }, 'default': { 'description': 'Error', 'schema': { '$ref': '#/definitions/Error' } } }, 'parameters': [{ 'name': 'FooUpdateSchema', 'in': 'body', 'required': True, 'schema': { '$ref': '#/definitions/FooUpdateSchema' } }], 'security': [{ 'sharedSecret': [] }] } }, '/foos': { 'get': { 'operationId': 'list_foos', 'responses': { '200': { 'description': 'ListOfFooSchema', 'schema': { '$ref': '#/definitions/ListOfFooSchema' } }, 'default': { 'description': 'Error', 'schema': { '$ref': '#/definitions/Error' } } }, 'parameters': [{ 'name': 'name', 'in': 'query', 'required': False, 'type': 'string' }], 'security': [] } } }, 'definitions': { 'Foo': { 'type': 'object', 'title': 'Foo', 'properties': { 'uid': { 'type': 'string' }, 'name': { 'type': 'string' } } }, 'FooUpdateSchema': { 'type': 'object', 'title': 'FooUpdateSchema', 'properties': { 'name': { 'type': 'string' } } }, 'ListOfFooSchema': { 'type': 'object', 'title': 'ListOfFooSchema', 'properties': { 'data': { 'type': 'array', 'items': { '$ref': '#/definitions/Foo' } } } }, 'Error': { 'type': 'object', 'title': 'Error', 'properties': { 'message': { 'type': 'string' }, 'details': { 'type': 'object' } } } } } # Uncomment these lines to just dump the result to the terminal: # import json # print(json.dumps(swagger, indent=2)) # self.assertTrue(False) # This will raise an error if validation fails validate_swagger(expected_swagger) self.assertEqual(swagger, expected_swagger)
import marshmallow as m from flask_rebar import Rebar from flask_rebar import HeaderApiKeyAuthenticator from flask_rebar import compat from flask_rebar.authenticators import USE_DEFAULT rebar = Rebar() registry = rebar.create_handler_registry() authenticator = HeaderApiKeyAuthenticator(header="x-auth") default_authenticator = HeaderApiKeyAuthenticator(header="x-another", name="default") alternative_default_authenticator = HeaderApiKeyAuthenticator( header="x-api", name="alternative") class HeaderSchema(m.Schema): user_id = compat.set_data_key(field=m.fields.String(required=True), key="X-UserId") class FooSchema(m.Schema): __swagger_title__ = "Foo" uid = m.fields.String() name = m.fields.String() class NestedFoosSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True)
def test_generate_swagger(self): rebar = Rebar() registry = rebar.create_handler_registry() authenticator = HeaderApiKeyAuthenticator(header="x-auth") default_authenticator = HeaderApiKeyAuthenticator( header="x-another", name="default" ) class HeaderSchema(m.Schema): user_id = compat.set_data_key( field=m.fields.String(required=True), key="X-UserId" ) class FooSchema(m.Schema): __swagger_title__ = "Foo" uid = m.fields.String() name = m.fields.String() class NestedFoosSchema(m.Schema): data = m.fields.Nested(FooSchema, many=True) class FooUpdateSchema(m.Schema): __swagger_title = "FooUpdate" name = m.fields.String() class NameAndOtherSchema(m.Schema): name = m.fields.String() other = m.fields.String() @registry.handles( rule="/foos/<uuid_string:foo_uid>", method="GET", marshal_schema={200: FooSchema()}, headers_schema=HeaderSchema(), ) def get_foo(foo_uid): """helpful description""" pass @registry.handles( rule="/foos/<foo_uid>", method="PATCH", marshal_schema={200: FooSchema()}, request_body_schema=FooUpdateSchema(), authenticator=authenticator, ) def update_foo(foo_uid): pass # Test using Schema(many=True) without using a nested Field. # https://github.com/plangrid/flask-rebar/issues/41 @registry.handles( rule="/foo_list", method="GET", marshal_schema={200: FooSchema(many=True)}, authenticator=None, # Override the default! ) def list_foos(): pass @registry.handles( rule="/foos", method="GET", marshal_schema={200: NestedFoosSchema()}, query_string_schema=NameAndOtherSchema(), authenticator=None, # Override the default! ) def nested_foos(): pass @registry.handles(rule="/tagged_foos", tags=["bar", "baz"]) def tagged_foos(): pass registry.set_default_authenticator(default_authenticator) host = "swag.com" schemes = ["http"] consumes = ["application/json"] produces = ["application/json"] title = "Test API" version = "2.1.0" class Error(m.Schema): message = m.fields.String() details = m.fields.Dict() generator = SwaggerV2Generator( host=host, schemes=schemes, consumes=consumes, produces=produces, title=title, version=version, default_response_schema=Error(), tags=[ Tag( name="bar", description="baz", external_docs=ExternalDocumentation( url="http://bardocs.com", description="qux" ), ) ], ) swagger = generator.generate(registry) expected_swagger = { "swagger": "2.0", "host": host, "info": {"title": title, "version": version, "description": ""}, "schemes": schemes, "consumes": consumes, "produces": produces, "security": [{"default": []}], "securityDefinitions": { "sharedSecret": {"type": "apiKey", "in": "header", "name": "x-auth"}, "default": {"type": "apiKey", "in": "header", "name": "x-another"}, }, "tags": [ { "name": "bar", "description": "baz", "externalDocs": {"url": "http://bardocs.com", "description": "qux"}, } ], "paths": { "/foos/{foo_uid}": { "parameters": [ { "name": "foo_uid", "in": "path", "required": True, "type": "string", } ], "get": { "operationId": "get_foo", "description": "helpful description", "responses": { "200": { "description": "Foo", "schema": {"$ref": "#/definitions/Foo"}, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "parameters": [ { "name": "X-UserId", "in": "header", "required": True, "type": "string", } ], }, "patch": { "operationId": "update_foo", "responses": { "200": { "description": "Foo", "schema": {"$ref": "#/definitions/Foo"}, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "parameters": [ { "name": "FooUpdateSchema", "in": "body", "required": True, "schema": {"$ref": "#/definitions/FooUpdateSchema"}, } ], "security": [{"sharedSecret": []}], }, }, "/foo_list": { "get": { "operationId": "list_foos", "responses": { "200": { "description": "Foo", "schema": { "type": "array", "items": {"$ref": "#/definitions/Foo"}, }, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "security": [], } }, "/foos": { "get": { "operationId": "nested_foos", "responses": { "200": { "description": "NestedFoosSchema", "schema": {"$ref": "#/definitions/NestedFoosSchema"}, }, "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, }, }, "parameters": [ { "name": "name", "in": "query", "required": False, "type": "string", }, { "name": "other", "in": "query", "required": False, "type": "string", }, ], "security": [], } }, "/tagged_foos": { "get": { "tags": ["bar", "baz"], "operationId": "tagged_foos", "responses": { "default": { "description": "Error", "schema": {"$ref": "#/definitions/Error"}, } }, } }, }, "definitions": { "Foo": { "type": "object", "title": "Foo", "properties": { "uid": {"type": "string"}, "name": {"type": "string"}, }, }, "FooUpdateSchema": { "type": "object", "title": "FooUpdateSchema", "properties": {"name": {"type": "string"}}, }, "NestedFoosSchema": { "type": "object", "title": "NestedFoosSchema", "properties": { "data": { "type": "array", "items": {"$ref": "#/definitions/Foo"}, } }, }, "Error": { "type": "object", "title": "Error", "properties": { "message": {"type": "string"}, "details": {"type": "object"}, }, }, }, } # Uncomment these lines to just dump the result to the terminal: # import json # print(json.dumps(swagger, indent=2)) # print(json.dumps(expected_swagger, indent=2)) # self.assertTrue(False) # This will raise an error if validation fails validate_swagger(expected_swagger) self.assertEqual(swagger, expected_swagger)
# -*- coding: utf-8 -*- """ REST API - Endpoint routing Author(s): Adam Mitchell, [email protected] """ from flask import current_app, request from flask_rebar import HeaderApiKeyAuthenticator, Rebar, response from rest_api.schemas import * authenticator = HeaderApiKeyAuthenticator(header='X-MyApp-ApiKey') authenticator.register_key(key='my-super-secret-key') rebar = Rebar() registry = rebar.create_handler_registry() @registry.handles(rule='/generic_greeting', method='GET', marshal_schema={200: GetGenericGreetingSchema()}, authenticator=authenticator) def getGenericGreeting(): return ({'message': 'Hello, Generic Person!'}, 200) @registry.handles(rule='/personalised_greeting', method='GET', marshal_schema={200: GetGenericGreetingSchema()}, query_string_schema=GetPersonalisedGreetingSchema(), authenticator=authenticator) def getPersonalisedGreeting():