-
-
Save dcramer/35dd269c17ddac11274a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import absolute_import, print_function | |
from urllib import urlencode | |
from sentry.auth import Implementation, AuthView | |
from sentry.http import safe_urlopen, safe_urlread | |
from sentry.utils import json | |
from sentry.utils.http import absolute_uri | |
AUTHORIZE_URL = 'https://accounts.google.com/o/oauth2/auth' | |
ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token' | |
SCOPE = 'email' | |
CLIENT_ID = None | |
CLIENT_SECRET = None | |
USER_DETAILS_ENDPOINT = 'https://www.googleapis.com/plus/v1/people/me' | |
class FetchUser(AuthView): | |
def __init__(self, domain=None, *args, **kwargs): | |
super(FetchUser, self).__init__(*args, **kwargs) | |
def dispatch(self, request): | |
req = safe_urlopen('{0}?{1}'.format( | |
USER_DETAILS_ENDPOINT, | |
urlencode({ | |
'access_token': data['access_token'], | |
}), | |
)) | |
body = safe_urlread(req) | |
data = json.loads(body) | |
if self.domain and domain != data['domain']: | |
raise NotImplementedError | |
self.bind_session(request, 'user', data) | |
# there is actually no reason for us to redirect, but we need a good mechanism for flow | |
# control that says "im done with this step, but I have no response and you should continue" | |
return self.redirect(self.get_next_url()) | |
class GoogleOAuth2Implementation(OAuth2Implementation): | |
def __init__(self, domain=None, **config): | |
self.domain = domain | |
super(GoogleOAuth2Implementation, self).__init__(**config) | |
def get_auth_pipeline(self): | |
return [ | |
OAuth2Login( | |
authorize_url=AUTHORIZE_URL, | |
scope=SCOPE, | |
client_id=CLIENT_ID, | |
), | |
OAuth2Callback( | |
access_token_url=ACCESS_TOKEN_URL, | |
client_id=CLIENT_ID, | |
client_secret=CLIENT_SECRET, | |
), | |
FetchUser(domain=self.domain), | |
] | |
def get_identity(self, data): | |
# data.user => { | |
# "displayName": "David Cramer", | |
# "emails": [{"value": "david@getsentry.com", "type": "account"}], | |
# "domain": "getsentry.com", | |
# "verified": false | |
# } | |
user_data = data['user'] | |
return { | |
# TODO: is there a "correct" email? | |
'email': user_data['emails'][0]['value'], | |
'name': user_data['displayName'], | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My biggest issue right now is how we treat the step flow control, which honestly probably won't even work.
We need a clean way to handle these situations:
I don't like returning different data types (in fact, I won't allow that), so the alternative is that we return some kind of tuple (success, [response]), but that's a bit obscure and to me always feels unpythonic. The general alternative to this is using exceptions as flow control (i.e. raise Authenticated) but that's super shitty. Another alternative would be to do something like return self.the_kind_of_action(), but that has scoping issues as we need to bind the implementation instance in this area, and we need the outer controller (which realistically is where the
the_kind_of_action
would come from).