diff options
author | Lars Wirzenius <liw@liw.fi> | 2017-08-24 09:23:33 +0000 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2017-08-24 09:23:33 +0000 |
commit | bb97fb549413e47ae8e798c26c2efe301ac0a1a2 (patch) | |
tree | e9cf6cb01e9ab18194d76793cc9de09b2b4ec1c4 | |
parent | c775b905b7a456eff43ba83f9e55aab3e8e4bb20 (diff) | |
download | apifw-bb97fb549413e47ae8e798c26c2efe301ac0a1a2.tar.gz |
Add: allos routes to not require authorization
-rw-r--r-- | apifw.yarn | 6 | ||||
-rw-r--r-- | apifw/bottleapp.py | 38 | ||||
-rw-r--r-- | apitest.py | 1 |
3 files changed, 38 insertions, 7 deletions
@@ -24,13 +24,11 @@ It's a silly name. Please suggest something better. GIVEN a running apitest using gunicorn3 WHEN client requests GET /version without token - THEN HTTP status code is 401 Unauthorized - AND response has header WWW-Authenticate containing "Bearer" + THEN HTTP status code is 200 OK WHEN client gets an authorization token with scope "no_version_scope" AND client requests GET /version using token - THEN HTTP status code is 401 Unauthorized - AND response has header WWW-Authenticate containing "Bearer" + THEN HTTP status code is 200 OK WHEN client gets an authorization token with scope "uapi_version_get" AND client requests GET /version using token diff --git a/apifw/bottleapp.py b/apifw/bottleapp.py index 6ca9659..012a48b 100644 --- a/apifw/bottleapp.py +++ b/apifw/bottleapp.py @@ -78,6 +78,7 @@ class BottleAuthorizationPlugin: self.pubkey = None self.iss = None self.aud = None + self._authz_routes = set() def set_token_signing_public_key(self, pubkey): self.pubkey = Crypto.PublicKey.RSA.importKey(pubkey) @@ -88,16 +89,41 @@ class BottleAuthorizationPlugin: def set_expected_audience(self, aud): self.aud = aud - def apply(self, callback, route): + def set_route_authorization(self, route): + key = self.route_key(route) + if route.get('needs-authorization', True): + self._authz_routes.add(key) + logging.info('Route %r does DOES need authorization', key) + else: + logging.info('Route %r does NOT need authorization', key) + + def route_key(self, route): + method = route.get('method', 'GET') + path = route.get('path', route.get('rule')) + return (method, path) + def apply(self, callback, route): def wrapper(*args, **kwargs): - if self.is_authorized(route): + + 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') return wrapper + def needs_authorization(self, route): + key = self.route_key(route) + logging.debug('route: %r', route) + logging.debug('route_key: %r', key) + logging.debug('authz_routes: %r', self._authz_routes) + return key in self._authz_routes + def is_authorized(self, route): value = self.get_authorization_header(bottle.request) token = self.parse_authorization_header(value) @@ -109,7 +135,7 @@ class BottleAuthorizationPlugin: value = request.get_header('Authorization', '') if not value: self.raise_unauthorized('No Authorization header') - logging.debug('Request has Authorization header: {!r}'.format(value)) + logging.debug('Request has Authorization header: %r', value) return value def parse_authorization_header(self, value): @@ -170,10 +196,14 @@ class BottleApplication: self._bottleapp = bottleapp self._bottleapp.add_hook('before_request', self._add_missing_route) self._api = api + self._authz = None def add_plugin(self, plugin): self._bottleapp.install(plugin) + def set_authorization_plugin(self, plugin): + self._authz = plugin + def _add_missing_route(self): try: self._bottleapp.match(bottle.request.environ) @@ -188,6 +218,7 @@ class BottleApplication: 'callback': callback, } self._bottleapp.route(**route_dict) + self._authz.set_route_authorization(route) else: raise @@ -233,5 +264,6 @@ def create_bottle_application(api, counter, logger, config): authz.set_expected_issuer(config['token-issuer']) authz.set_expected_audience(config['token-audience']) app.add_plugin(authz) + app.set_authorization_plugin(authz) return bottleapp @@ -38,6 +38,7 @@ class Api(apifw.Api): { 'path': '/version', 'callback': self.version, + 'needs-authorization': False, }, { 'method': 'PUT', |