def get_user_google_token( user: User, ) -> Tuple[Optional[SocialToken], Optional[SocialApp]]: """ Get a Google `SocialToken` for the user. If necessary will refresh the OAuth2 access token and update it in the database so that the refresh does not need to be done again within the next hour (at time of writing the expiry time for tokens). In most contexts that this function is used the Google `SocialApp` is also needed (e.g. for it's client_id etc) so we return that too. To avoid exceptions during development where there might not be a Google `SocialApp` we return None. """ token = get_user_social_token(user, Provider.google) try: app = SocialApp.objects.get(provider=Provider.google.name) except SocialApp.DoesNotExist: app = None if token is None: return None, app # If the token has not expired just return it if token.expires_at is None or token.expires_at > timezone.now() - timezone.timedelta( seconds=90 ): return token, app # The folowing are all required for a token refresh so if any # are missing, and the token has expired, return no token. if not (token.token and token.token_secret and token.expires_at): return None, app # Refresh the token credentials = GoogleCredentials( access_token=token.token, client_id=app.client_id, client_secret=app.secret, refresh_token=token.token_secret, token_expiry=token.expires_at, token_uri="https://accounts.google.com/o/oauth2/token", user_agent="Stencila Hub Client", ) credentials.refresh(http=transport.get_http_object()) info = credentials.get_access_token() # Save the new access token and expiry time token.token = info.access_token token.expires_at = timezone.now() + timezone.timedelta(seconds=info.expires_in) token.save() return token, app
def _check_user_info(credentials, expected_email): http = credentials.authorize(transport.get_http_object()) response, content = transport.request(http, USER_INFO) if response.status != http_client.OK: raise ValueError('Expected 200 OK response.') content = content.decode('utf-8') payload = json.loads(content) if payload['email'] != expected_email: raise ValueError('User info email does not match credentials.')
def http(self, *args, **kwargs): """Returns an authorized http instance. Must only be called from within an @oauth_required decorated method, or from within an @oauth_aware decorated method where has_credentials() returns True. Args: *args: Positional arguments passed to httplib2.Http constructor. **kwargs: Positional arguments passed to httplib2.Http constructor. """ return self.credentials.authorize( transport.get_http_object(*args, **kwargs))
def http(self, *args, **kwargs): """Returns an authorized http instance. Can only be called if there are valid credentials for the user, such as inside of a view that is decorated with @required. Args: *args: Positional arguments passed to httplib2.Http constructor. **kwargs: Positional arguments passed to httplib2.Http constructor. Raises: ValueError if no credentials are available. """ if not self.credentials: raise ValueError('No credentials available.') return self.credentials.authorize( transport.get_http_object(*args, **kwargs))
def test_token_info(self): credentials = gce.AppAssertionCredentials([]) http = transport.get_http_object() # First refresh to get the access token. self.assertIsNone(credentials.access_token) credentials.refresh(http) self.assertIsNotNone(credentials.access_token) # Then check the access token against the token info API. query_params = {'access_token': credentials.access_token} token_uri = (oauth2client.GOOGLE_TOKEN_INFO_URI + '?' + urllib.parse.urlencode(query_params)) response, content = transport.request(http, token_uri) self.assertEqual(response.status, http_client.OK) content = content.decode('utf-8') payload = json.loads(content) self.assertEqual(payload['access_type'], 'offline') self.assertLessEqual(int(payload['expires_in']), 3600)
def http(self): """Helper: create HTTP client authorized with OAuth2 credentials.""" if self.has_credentials(): return self.credentials.authorize(transport.get_http_object()) return None
def test_it(self, http_klass): result = transport.get_http_object() self.assertEqual(result, http_klass.return_value)
def test_with_args(self, http_klass): result = transport.get_http_object(1, 2, foo='bar') self.assertEqual(result, http_klass.return_value) http_klass.assert_called_once_with(1, 2, foo='bar')
def test_it(self, http_klass): result = transport.get_http_object() self.assertEqual(result, http_klass.return_value) http_klass.assert_called_once_with()