Skip to content

Commit

Permalink
Add support for custom auth endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamie Cressey authored and Jamie Cressey committed Aug 1, 2016
1 parent f79577a commit ef25f68
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 12 deletions.
30 changes: 30 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,36 @@ auto policy generator detects actions that it would like to add or remove::

.. quick-start-end
Tutorial: Using Custom Authentication
===========================

AWS API Gateway routes can be authenticated in multiple ways:
- API Key
- Custom Auth Handler

# API Key

.. code-block:: python
@app.route('/authenticated', methods=['GET'], api_key_required=True)
def authenticated(key):
return {"secure": True}
Only requests sent with a valid `X-Api-Key` header will be accepted.

# Custom Auth Handler

A custom Authorizer is required for this to work, details can be found here;
http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html

.. code-block:: python
@app.route('/authenticated', methods=['GET'], authorization_type='CUSTOM', authorizer_id='ab12cd')
def authenticated(key):
return {"secure": True}
Only requests sent with a valid `X-Api-Key` header will be accepted.

Backlog
=======

Expand Down
26 changes: 24 additions & 2 deletions chalice/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,22 @@ def to_dict(self):

class RouteEntry(object):

def __init__(self, view_function, view_name, path, methods):
def __init__(
self,
view_function,
view_name,
path,
methods,
authorization_type=None,
authorizer_id=None,
api_key_required=False):
self.view_function = view_function
self.view_name = view_name
self.uri_pattern = path
self.methods = methods
self.authorization_type = authorization_type
self.authorizer_id = authorizer_id
self.api_key_required = api_key_required
#: A list of names to extract from path:
#: e.g, '/foo/{bar}/{baz}/qux -> ['bar', 'baz']
self.view_args = self._parse_view_args()
Expand Down Expand Up @@ -132,7 +143,18 @@ def _register_view(view_func):
def _add_route(self, path, view_func, **kwargs):
name = kwargs.get('name', view_func.__name__)
methods = kwargs.get('methods', ['GET'])
self.routes[path] = RouteEntry(view_func, name, path, methods)
authorization_type = kwargs.get('authorization_type', None)
authorizer_id = kwargs.get('authorizer_id', None)
api_key_required = kwargs.get('api_key_required', None)

self.routes[path] = RouteEntry(
view_func,
name,
path,
methods,
authorization_type,
authorizer_id,
api_key_required)

def __call__(self, event, context):
# This is what's invoked via lambda.
Expand Down
27 changes: 21 additions & 6 deletions chalice/deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import hashlib
import inspect
import time
import re

from typing import Any, Tuple, Callable, Optional # noqa
import botocore.session
Expand Down Expand Up @@ -572,15 +573,29 @@ def build_resources(self, chalice_trie):
rest_api_id=self.rest_api_id),
)

def _camel_convert(self, name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

def _configure_resource_route(self, node, http_method):
# type: (Dict[str, Any], str) -> None
c = self.client
c.put_method(
restApiId=self.rest_api_id,
resourceId=node['resource_id'],
httpMethod=http_method,
authorizationType='NONE'
)
put_method_cfg = {
'restApiId': self.rest_api_id,
'resourceId': node['resource_id'],
'httpMethod': http_method,
'authorizationType': 'NONE'
}

for attr in ['authorizationType', 'authorizerId', 'apiKeyRequired']:
try:
_attr = getattr(node['route_entry'], self._camel_convert(attr))
if _attr:
put_method_cfg[attr] = _attr
except AttributeError:
pass

c.put_method(**put_method_cfg)
c.put_integration(
restApiId=self.rest_api_id,
resourceId=node['resource_id'],
Expand Down
12 changes: 11 additions & 1 deletion docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Chalice
app = Chalice(app_name="appname")
app.debug = True
.. method:: route(path, \* , [methods [, name]])
.. method:: route(path, \* , [methods [, name], authorization_type, authorizer_id, api_key_required])

Register a view function for a particular URI path. This method
is intended to be used as a decorator for a view function. For example:
Expand Down Expand Up @@ -64,6 +64,16 @@ Chalice
function. You generally do not need to set this value. The name
of the view function is used as the default value for the view name.

:param str authorization_type: Optional parameter to specify the type
of authorization used for the view.

:param str authorizer_id: Optional parameter to specify the identifier
of an Authorizer to use on this view, if the authorization_type is
CUSTOM.

:param boolean api_key_required: Optional parameter to specify whether
the method required a valid ApiKey


Request
=======
Expand Down
6 changes: 3 additions & 3 deletions docs/source/topics/routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ In the function above, if the user provides a ``?include-greeting=true`` in the
HTTP request, then an additional ``greeting`` key will be returned::

$ http https://endpoint/dev/users/bob

{
"name": "bob"
}

$ http https://endpoint/dev/users/bob?include-greeting=true

{
"greeting": "Hello, bob",
"name": "bob"
Expand Down
1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pytest==2.9.2
py==1.4.31
pygments==2.1.3

0 comments on commit ef25f68

Please sign in to comment.