From ad89345c8221ee9ef2fb6129238aa65b5c493355 Mon Sep 17 00:00:00 2001 From: Israel Brewster Date: Thu, 16 Mar 2017 11:24:06 -0800 Subject: [PATCH 1/4] Fix "Scopes must be set on post auth." exception According to the OAuth RFC, the Authorization Code grant can be requested without explicitly providing a list of scopes. This change enables that behavior by using the default scopes the OAuth request was initially populated with. --- flask_oauthlib/provider/oauth2.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index 9c6c3c67..dcef6970 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -429,13 +429,17 @@ def decorated(*args, **kwargs): # denied by user e = oauth2.AccessDeniedError() return redirect(e.in_uri(redirect_uri)) - return self.confirm_authorization_request() + + # Pass the scopes list as a string to match the format of a URL request + return self.confirm_authorization_request(" ".join(kwargs['request'].scopes)) return decorated - def confirm_authorization_request(self): + def confirm_authorization_request(self, default_scopes = None): """When consumer confirm the authorization.""" server = self.server - scope = request.values.get('scope') or '' + # Use the value of scope provided in the URL, if any, the default scopes + # from the client object if not, or, failing that, use an empty list. + scope = request.values.get('scope') or default_scopes or '' scopes = scope.split() credentials = dict( client_id=request.values.get('client_id'), From 69a121cedd35b587a6aee0b7a3fb594ba0e231fc Mon Sep 17 00:00:00 2001 From: Israel Brewster Date: Fri, 17 Mar 2017 10:20:21 -0800 Subject: [PATCH 2/4] Use locally defined scopes variable Use the locally defined scopes variable rather than trying to pull from the request object, which may not exist in certain requests. --- flask_oauthlib/provider/oauth2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index dcef6970..2a77961f 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -431,7 +431,7 @@ def decorated(*args, **kwargs): return redirect(e.in_uri(redirect_uri)) # Pass the scopes list as a string to match the format of a URL request - return self.confirm_authorization_request(" ".join(kwargs['request'].scopes)) + return self.confirm_authorization_request(" ".join(scopes)) return decorated def confirm_authorization_request(self, default_scopes = None): From c90bd4ff481921eb5e1877263286a674738106df Mon Sep 17 00:00:00 2001 From: Israel Brewster Date: Fri, 17 Mar 2017 10:34:56 -0800 Subject: [PATCH 3/4] Check to see where we can find scopes Check to make sure scopes is defined locally or request exists in kwargs and has a scopes attribute. If not, fall back to the old behavior of not declaring default scopes and hope they are not needed. --- flask_oauthlib/provider/oauth2.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index 2a77961f..b70bc643 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -431,7 +431,13 @@ def decorated(*args, **kwargs): return redirect(e.in_uri(redirect_uri)) # Pass the scopes list as a string to match the format of a URL request - return self.confirm_authorization_request(" ".join(scopes)) + default_scopes = "" # default fallback if no scopes provided. + try: + default_scopes = " ".join(scopes) + except UnboundLocalError: + if 'request' in kwargs and hasattr(kwargs['request'], scopes): + default_scopes = " ".join(kwargs['request'].scopes) + return self.confirm_authorization_request(default_scopes) return decorated def confirm_authorization_request(self, default_scopes = None): From bce64062ec337a5e451e71ba5b5b1a303c458b35 Mon Sep 17 00:00:00 2001 From: Israel Brewster Date: Fri, 24 Mar 2017 10:08:03 -0800 Subject: [PATCH 4/4] Remove unneeded line Remove unused line that wasn't being covered by tests. --- flask_oauthlib/provider/oauth2.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index b70bc643..d0d91c7c 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -435,8 +435,9 @@ def decorated(*args, **kwargs): try: default_scopes = " ".join(scopes) except UnboundLocalError: - if 'request' in kwargs and hasattr(kwargs['request'], scopes): - default_scopes = " ".join(kwargs['request'].scopes) + pass #Just use the default of empty scopes, which will likely return an error later + #if 'request' in kwargs and hasattr(kwargs['request'], scopes): + # default_scopes = " ".join(kwargs['request'].scopes) return self.confirm_authorization_request(default_scopes) return decorated