From 74d167172a4ddb56c710e54e2455a626880aa282 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Tue, 24 Apr 2018 23:35:36 +0300 Subject: [PATCH] Add some inline documentation and missing OPTIONS check in scoped decorator --- .gitignore | 1 + sanic_jwt/authentication.py | 32 +++++++++++++++++++++++++++++++- sanic_jwt/decorators.py | 6 ++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8b8676a..6362a7e 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ htmlcov/ .coverage .coverage.* .cache +.pytest_cache/ nosetests.xml coverage.xml *.cover diff --git a/sanic_jwt/authentication.py b/sanic_jwt/authentication.py index 1874457..751e952 100644 --- a/sanic_jwt/authentication.py +++ b/sanic_jwt/authentication.py @@ -66,6 +66,10 @@ async def add_scopes_to_payload(self, *args, **kwargs): class Authentication(BaseAuthentication): def _decode(self, token, verify=True): + """ + Take a JWT and return a decoded payload. Optionally, will verify + the claims on the token. + """ secret = self._get_secret() algorithm = self._get_algorithm() kwargs = {} @@ -82,7 +86,8 @@ def _decode(self, token, verify=True): kwargs["audience"] = self.config.claim_aud() if "claim_iss" in self.config: kwargs["issuer"] = self.config.claim_iss() - return jwt.decode( + + decoded = jwt.decode( token, secret, algorithms=[algorithm], @@ -90,11 +95,15 @@ def _decode(self, token, verify=True): options={"verify_exp": self.config.verify_exp()}, **kwargs ) + return decoded def _get_algorithm(self): return self.config.algorithm() async def _get_payload(self, user): + """ + Given a user object, create a payload and extend it as configured. + """ payload = await utils.call(self.build_payload, user) if ( @@ -136,6 +145,9 @@ def _get_secret(self, encode=False): return self.config.secret() def _get_token(self, request, refresh_token=False): + """ + Extract a token from a request object. + """ if self.config.cookie_set(): cookie_token_name_key = "cookie_access_token_name" if refresh_token is False else "cookie_refresh_token_name" cookie_token_name = getattr(self.config, cookie_token_name_key) @@ -168,6 +180,9 @@ def _get_token(self, request, refresh_token=False): raise exceptions.MissingAuthorizationHeader() async def _get_refresh_token(self, request): + """ + Extract a refresh token from a request object. + """ return self._get_token(request, refresh_token=True) async def _get_user_id(self, user): @@ -183,6 +198,9 @@ async def _get_user_id(self, user): return user_id async def get_access_token(self, user): + """ + Generate an access token for a given user. + """ payload = await self._get_payload(user) secret = self._get_secret(True) algorithm = self._get_algorithm() @@ -190,6 +208,9 @@ async def get_access_token(self, user): return jwt.encode(payload, secret, algorithm=algorithm).decode("utf-8") async def get_refresh_token(self, request, user): + """ + Generate a refresh token for a given user. + """ refresh_token = await utils.call(self.config.generate_refresh_token()) user_id = await self._get_user_id(user) await utils.call( @@ -215,6 +236,9 @@ def is_authenticated(self, request, *args, **kwargs): def verify( self, request, return_payload=False, verify=True, *args, **kwargs ): + """ + Verify that a request object is authenticated. + """ token = self._get_token(request) is_valid = True reason = None @@ -244,11 +268,17 @@ async def retrieve_refresh_token_from_request(self, request): return await self._get_refresh_token(request) def retrieve_scopes(self, request): + """ + Extract scopes from a request object. + """ payload = self.extract_payload(request) scopes_attribute = self.config.scopes_name() return payload.get(scopes_attribute, None) def extract_payload(self, request, verify=True, *args, **kwargs): + """ + Extract a payload from a request object. + """ payload = self.verify( request, return_payload=True, verify=verify, *args, **kwargs ) diff --git a/sanic_jwt/decorators.py b/sanic_jwt/decorators.py index 7c6bea8..13b45c6 100644 --- a/sanic_jwt/decorators.py +++ b/sanic_jwt/decorators.py @@ -93,6 +93,12 @@ async def decorated_function(request, *args, **kwargs): instance = request.app with instant_config(instance, request=request, **kw): + if request.method == "OPTIONS": + response = f(request, *args, **kwargs) + if isawaitable(response): + response = await response + return response + try: is_authenticated, status, reasons = instance.auth.is_authenticated( request, *args, **kwargs