summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2017-09-05 12:49:22 +0000
committerLars Wirzenius <liw@liw.fi>2017-09-05 12:49:22 +0000
commit17431040c1ad62dd7347cb35510af5b21f43af9e (patch)
tree0ba2380f187755682b692c4ae9a25efeddac5e7e
parentcd65fd197515c1cd83c388c57ba780c7dea94c6a (diff)
downloadapifw-17431040c1ad62dd7347cb35510af5b21f43af9e.tar.gz
Fix: status codes, headers for error returns
This matches what Qvarn expects now.
-rw-r--r--apifw/bottleapp.py39
1 files changed, 23 insertions, 16 deletions
diff --git a/apifw/bottleapp.py b/apifw/bottleapp.py
index 9cc9d08..76602c6 100644
--- a/apifw/bottleapp.py
+++ b/apifw/bottleapp.py
@@ -110,15 +110,9 @@ class BottleAuthorizationPlugin:
def apply(self, callback, route):
def wrapper(*args, **kwargs):
- call = False
if self.needs_authorization(route):
- call = self.is_authorized(route)
- else:
- call = True
- if call:
- return callback(*args, **kwargs)
-
- self.raise_unauthorized('Something went wrong')
+ self.assert_authorized(route)
+ return callback(*args, **kwargs)
return wrapper
@@ -129,24 +123,28 @@ class BottleAuthorizationPlugin:
logging.debug('authz_routes: %r', self._authz_routes)
return key in self._authz_routes
- def is_authorized(self, route):
+ def assert_authorized(self, route):
value = self.get_authorization_header(bottle.request)
token = self.parse_authorization_header(value)
claims = self.parse_token(token)
self.check_issuer(claims)
- return self.scope_allows_route(claims['scope'], route)
+ if not self.scope_allows_route(claims['scope'], route):
+ self.raise_forbidden(
+ 'insufficient_scope', 'scope does not allow route')
def get_authorization_header(self, request):
value = request.get_header('Authorization', '')
if not value:
- self.raise_unauthorized('No Authorization header')
+ self.raise_unauthorized(
+ 'no_authorization', 'No Authorization header')
logging.debug('Request has Authorization header: %r', value)
return value
def parse_authorization_header(self, value):
words = value.split()
if len(words) != 2 or words[0].lower() != 'bearer':
- self.raise_unauthorized('Authorization should be "Bearer TOKEN"')
+ self.raise_unauthorized(
+ 'bad_authorization', 'Authorization should be "Bearer TOKEN"')
logging.debug(
'Request Authorization header looks like a bearer token: good')
return words[1]
@@ -158,11 +156,12 @@ class BottleAuthorizationPlugin:
logging.debug('Token: %r', token)
return token
except jwt.InvalidTokenError as e:
- self.raise_unauthorized(str(e))
+ self.raise_unauthorized('invalid_token', str(e))
def check_issuer(self, claims):
if claims['iss'] != self.iss:
self.raise_unauthorized(
+ 'bad_issuer',
'Expected issuer %s, got %s' % (self.iss, claims['iss']))
logging.debug('Token issuer is correct: good')
@@ -183,11 +182,19 @@ class BottleAuthorizationPlugin:
scope = 'uapi%s_%s' % (scope, method)
return scope.lower()
- def raise_unauthorized(self, explanation):
+ def raise_unauthorized(self, error, explanation):
+ headers = {
+ 'WWW-Authenticate': 'Bearer error="{}"'.format(error),
+ }
+ raise bottle.HTTPError(
+ apifw.HTTP_UNAUTHORIZED, body=explanation, headers=headers)
+
+ def raise_forbidden(self, error, explanation):
headers = {
- 'WWW-Authenticate': 'Bearer',
+ 'WWW-Authenticate': 'Bearer error="{}"'.format(error),
}
- raise bottle.HTTPError(401, body=explanation, headers=headers)
+ raise bottle.HTTPError(
+ apifw.HTTP_FORBIDDEN, body=explanation, headers=headers)
class BottleApplication: