From 96fcf0f240b254f0f104a7ec6479c8bd9467b694 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 7 Jun 2013 14:55:16 +0000 Subject: [PATCH 1/6] Updated the way tokensetter works --- flask_oauthlib/provider/oauth2.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index 418b2cb7..05255d23 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -146,6 +146,25 @@ def bearer_token(access_token=None, refresh_token=None): def tokensetter(self, f): """Register a function to save the bearer token. + + The function accepts the folllowing parameters: + + - access_token: A string token + - scopes: A list of scopes for the token + - client: The client object + - user: The user object + - expires_in: Number of seconds until token should expire + - refresh_token: Either a string token or None + + Implement the token setter:: + + @oauth.tokensetter + def set_token(access_token, scopes, client, user, + expires_in, refresh_token): + expires_at = datetime.now() + timedelta(seconds=expires_in) + save_token(access_token, scopes, client, user, + expires_at, refresh_token) + """ self._tokensetter = f @@ -447,7 +466,14 @@ def save_authorization_code(self, client_id, code, request, def save_bearer_token(self, token, request, *args, **kwargs): """Persist the Bearer token.""" log.debug('Save bearer token %r', token) - self._tokensetter(token, request, *args, **kwargs) + self._tokensetter( + access_token = token['access_token'], + scopes = request.scopes + client = request.client, + user = request.user, + expires_in = token['expires_in'], + refresh_token = token.get('refresh_token', None) + ) return request.client.default_redirect_uri def validate_bearer_token(self, token, scopes, request): From 44e45457e3dafe648ce56a5f17bfdf52c72b26eb Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 7 Jun 2013 15:21:07 +0000 Subject: [PATCH 2/6] Fixed testing and modified provider again for the token setting with more explict arguments. --- flask_oauthlib/provider/oauth2.py | 4 +++- tests/oauth2_server.py | 15 +++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index 05255d23..5c260cd5 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -150,6 +150,7 @@ def tokensetter(self, f): The function accepts the folllowing parameters: - access_token: A string token + - token_type: A string describing the type of token provided - scopes: A list of scopes for the token - client: The client object - user: The user object @@ -468,7 +469,8 @@ def save_bearer_token(self, token, request, *args, **kwargs): log.debug('Save bearer token %r', token) self._tokensetter( access_token = token['access_token'], - scopes = request.scopes + token_type = token['token_type'], + scopes = request.scopes, client = request.client, user = request.user, expires_in = token['expires_in'], diff --git a/tests/oauth2_server.py b/tests/oauth2_server.py index b3e3a121..b39eb71f 100644 --- a/tests/oauth2_server.py +++ b/tests/oauth2_server.py @@ -152,12 +152,19 @@ def set_grant(client_id, code, request, *args, **kwargs): db.session.commit() @oauth.tokensetter - def set_token(token, request, *args, **kwargs): + def set_token(access_token, token_type, scopes, client, user, + expires_in, refresh_token): # In real project, a token is unique bound to user and client. # Which means, you don't need to create a token every time. - tok = Token(**token) - tok.user_id = request.user.id - tok.client_id = request.client.client_id + tok = Token( + access_token=access_token, + token_type=token_type, + expires_in=expires_in, + refresh_token=refresh_token, + scope=' '.join(scopes) + ) + tok.user_id = user.id + tok.client_id = client.client_id db.session.add(tok) db.session.commit() From f2a2ab916a74798c0e377e3443e07eedc52d85cc Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 10 Jun 2013 15:38:40 +0000 Subject: [PATCH 3/6] Updated the way the grant getter and set operated --- flask_oauthlib/provider/oauth2.py | 29 ++++++++++++++++++++++++----- tests/oauth2_server.py | 18 ++++++++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index 5c260cd5..6f82dbd9 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -180,6 +180,8 @@ def grant(client_id, code): It returns a grant object with at least these information: + - user: The user for the grant + - scopes: A list of scopes provided by the grant - delete: A function to delete itself """ self._grantgetter = f @@ -187,11 +189,20 @@ def grant(client_id, code): def grantsetter(self, f): """Register a function to save the grant code. - The function accepts `client_id`, `code`, `request` and more:: + The function accepts the following arguments: + + - code: A string authorization code + - redirect_uri: A string representing the redirect uri + - user: The user object + - client: The client object + - scopes: A list of scopes for the code + - state: A string provided to prevent CSS + + Here is an exmample implementation of the setter:: @oauth.grantsetter - def set_grant(client_id, code, request, *args, **kwargs): - save_grant(client_id, code, request.user, request.scopes) + def set_grant(code, redirect_uri, user, client, scopes, state): + save_grant(code, redirect_uri, user, client, scopes, state) """ self._grantsetter = f @@ -461,7 +472,15 @@ def save_authorization_code(self, client_id, code, request, code, client_id ) request.client = request.client or self._clientgetter(client_id) - self._grantsetter(client_id, code, request, *args, **kwargs) + request.user = request.user or self._usergetter() + self._grantsetter( + code=code['code'], + redirect_uri=request.redirect_uri, + user=request.user, + client=request.client, + scopes=request.scopes, + state=request.state + ) return request.client.default_redirect_uri def save_bearer_token(self, token, request, *args, **kwargs): @@ -534,7 +553,7 @@ def validate_code(self, client_id, code, client, request, *args, **kwargs): datetime.datetime.utcnow() > grant.expires: log.debug('Grant is expired.') return False - request.state = kwargs.get('state') + request.state = grant.state request.user = grant.user request.scopes = grant.scopes return True diff --git a/tests/oauth2_server.py b/tests/oauth2_server.py index b39eb71f..73cf4d5c 100644 --- a/tests/oauth2_server.py +++ b/tests/oauth2_server.py @@ -55,6 +55,7 @@ class Grant(db.Model): code = db.Column(db.Unicode(255), index=True, nullable=False) redirect_uri = db.Column(db.Unicode(255)) + state = db.Column(db.Unicode(255)) scope = db.Column(db.UnicodeText) expires = db.Column(db.DateTime) @@ -138,15 +139,16 @@ def get_token(access_token=None, refresh_token=None): return None @oauth.grantsetter - def set_grant(client_id, code, request, *args, **kwargs): + def set_grant(code, redirect_uri, user, client, scopes, state): expires = datetime.datetime.utcnow() + datetime.timedelta(seconds=100) grant = Grant( - client_id=client_id, - code=code['code'], - redirect_uri=request.redirect_uri, - scope=' '.join(request.scopes), - user_id=g.user.id, + client_id=client.client_id, + code=code, + redirect_uri=redirect_uri, + scope=' '.join(scopes), + user_id=user.id, expires=expires, + state=state, ) db.session.add(grant) db.session.commit() @@ -168,6 +170,10 @@ def set_token(access_token, token_type, scopes, client, user, db.session.add(tok) db.session.commit() + @oauth.usergetter + def get_user(): + return g.user + @app.before_request def load_current_user(): user = User.query.get(1) From 7c9650fcfdfb51b889ab03db420b10b86a07e35b Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 10 Jun 2013 17:00:08 +0000 Subject: [PATCH 4/6] Fixed previous merge issue, moved the current usergetter to usernamegetter to specify the difference between the two. --- flask_oauthlib/provider/oauth2.py | 40 +++++++++++++++++++++---------- tests/oauth2_server.py | 8 ++++++- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index f37ab2b5..0dda6729 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -84,17 +84,19 @@ def server(self): hasattr(self, '_tokengetter') and \ hasattr(self, '_tokensetter') and \ hasattr(self, '_grantgetter') and \ - hasattr(self, '_grantsetter'): + hasattr(self, '_grantsetter') and \ + hasattr(self, '_usergetter'): - usergetter = None - if hasattr(self, '_usergetter'): - usergetter = self._usergetter + usernamegetter = None + if hasattr(self, '_usernamegetter'): + usernamegetter = self._usernamegetter validator = OAuth2RequestValidator( clientgetter=self._clientgetter, tokengetter=self._tokengetter, grantgetter=self._grantgetter, usergetter=usergetter, + usernamegetter=usernamegetter, tokensetter=self._tokensetter, grantsetter=self._grantsetter, ) @@ -151,17 +153,29 @@ def bearer_token(access_token=None, refresh_token=None): """ self._tokengetter = f - def usergetter(self, f): - """Register a function as the user getter. + def usernamegetter(self, f): + """Register a function as the username getter. This decorator is only required for password credential authorization:: - @oauth.usergetter - def get_user(username=username, password=password, + @oauth.usernamegetter + def get_user(username=None, password=None, *args, **kwargs): return get_user_by_username(username, password) """ + self._usernamegetter = f + + def usergetter(self, f): + """Register a function as the user getter. + + The function is used to retrieve the currently logged + in user:: + + @oauth.usergetter + def get_user(): + return current_user + """ self._usergetter = f def tokensetter(self, f): @@ -360,10 +374,12 @@ class OAuth2RequestValidator(RequestValidator): :param grantsetter: a function to save grant token """ def __init__(self, clientgetter, tokengetter, grantgetter, - usergetter=None, tokensetter=None, grantsetter=None): + usergetter=None, usernamegetter=None, tokensetter=None, + grantsetter=None): self._clientgetter = clientgetter self._tokengetter = tokengetter self._usergetter = usergetter + self._usernamegetter = usernamegetter self._tokensetter = tokensetter self._grantgetter = grantgetter self._grantsetter = grantsetter @@ -601,7 +617,7 @@ def validate_grant_type(self, client_id, grant_type, client, request, It is suggested that `allowed_grant_types` should contain at least `authorization_code` and `refresh_token`. """ - if self._usergetter is None and grant_type == 'password': + if self._usernamegetter is None and grant_type == 'password': log.debug('Password credential authorization is disabled.') return False @@ -677,8 +693,8 @@ def validate_user(self, username, password, client, request, """ log.debug('Validating username %r and password %r', username, password) - if self._usergetter is not None: - user = self._usergetter( + if self._usernamegetter is not None: + user = self._usernamegetter( username, password, client, request, *args, **kwargs ) if user: diff --git a/tests/oauth2_server.py b/tests/oauth2_server.py index 5aae69c3..3345a2f3 100644 --- a/tests/oauth2_server.py +++ b/tests/oauth2_server.py @@ -190,12 +190,18 @@ def set_token(access_token, token_type, scopes, client, user, db.session.add(tok) db.session.commit() - @oauth.usergetter + @oauth.usernamegetter def get_user(username, password, *args, **kwargs): # This is optional, if you don't need password credential # there is no need to implement this method return User.query.get(1) + @oauth.usergetter + def get_active_user(): + # This is used to retrieve the user object on the currently + # logged in user. + return User.query.get(1) + @app.before_request def load_current_user(): user = User.query.get(1) From dea0eadba4d54591db3d80bd72257c58ea62d802 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 10 Jun 2013 17:06:17 +0000 Subject: [PATCH 5/6] Changed bug associated with setting usergetter for validator. --- 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 0dda6729..4eea28f7 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -95,7 +95,7 @@ def server(self): clientgetter=self._clientgetter, tokengetter=self._tokengetter, grantgetter=self._grantgetter, - usergetter=usergetter, + usergetter=self._usergetter, usernamegetter=usernamegetter, tokensetter=self._tokensetter, grantsetter=self._grantsetter, From df5d26bbc7273d1b1f3c7280ac6e2b2b616a51ca Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 11 Jun 2013 13:37:47 +0000 Subject: [PATCH 6/6] Fixed pep8 issues --- flask_oauthlib/provider/oauth2.py | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/flask_oauthlib/provider/oauth2.py b/flask_oauthlib/provider/oauth2.py index 4eea28f7..4c29a7ad 100644 --- a/flask_oauthlib/provider/oauth2.py +++ b/flask_oauthlib/provider/oauth2.py @@ -185,19 +185,19 @@ def tokensetter(self, f): - access_token: A string token - token_type: A string describing the type of token provided - - scopes: A list of scopes for the token - - client: The client object - - user: The user object + - scopes: A list of scopes for the token + - client: The client object + - user: The user object - expires_in: Number of seconds until token should expire - refresh_token: Either a string token or None - + Implement the token setter:: - + @oauth.tokensetter - def set_token(access_token, scopes, client, user, + def set_token(access_token, scopes, client, user, expires_in, refresh_token): expires_at = datetime.now() + timedelta(seconds=expires_in) - save_token(access_token, scopes, client, user, + save_token(access_token, scopes, client, user, expires_at, refresh_token) """ @@ -231,7 +231,7 @@ def grantsetter(self, f): - client: The client object - scopes: A list of scopes for the code - state: A string provided to prevent CSS - + Here is an exmample implementation of the setter:: @oauth.grantsetter @@ -374,7 +374,7 @@ class OAuth2RequestValidator(RequestValidator): :param grantsetter: a function to save grant token """ def __init__(self, clientgetter, tokengetter, grantgetter, - usergetter=None, usernamegetter=None, tokensetter=None, + usergetter=None, usernamegetter=None, tokensetter=None, grantsetter=None): self._clientgetter = clientgetter self._tokengetter = tokengetter @@ -521,8 +521,8 @@ def save_authorization_code(self, client_id, code, request, request.client = request.client or self._clientgetter(client_id) request.user = request.user or self._usergetter() self._grantsetter( - code=code['code'], - redirect_uri=request.redirect_uri, + code=code['code'], + redirect_uri=request.redirect_uri, user=request.user, client=request.client, scopes=request.scopes, @@ -534,13 +534,13 @@ def save_bearer_token(self, token, request, *args, **kwargs): """Persist the Bearer token.""" log.debug('Save bearer token %r', token) self._tokensetter( - access_token = token['access_token'], - token_type = token['token_type'], - scopes = request.scopes, - client = request.client, - user = request.user, - expires_in = token['expires_in'], - refresh_token = token.get('refresh_token', None) + access_token=token['access_token'], + token_type=token['token_type'], + scopes=request.scopes, + client=request.client, + user=request.user, + expires_in=token['expires_in'], + refresh_token=token.get('refresh_token', None) ) return request.client.default_redirect_uri