diff options
author | Lars Wirzenius <liw@liw.fi> | 2017-09-05 12:49:22 +0000 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2017-09-05 12:49:22 +0000 |
commit | 17431040c1ad62dd7347cb35510af5b21f43af9e (patch) | |
tree | 0ba2380f187755682b692c4ae9a25efeddac5e7e | |
parent | cd65fd197515c1cd83c388c57ba780c7dea94c6a (diff) | |
download | apifw-17431040c1ad62dd7347cb35510af5b21f43af9e.tar.gz |
Fix: status codes, headers for error returns
This matches what Qvarn expects now.
-rw-r--r-- | apifw/bottleapp.py | 39 |
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: |