def googledrive_oauth_start(auth, **kwargs): """View function that does OAuth Authorization and returns access token""" # Run through the OAuth flow and retrieve credentials # Store the node ID on the session in order to get the correct redirect URL # upon finishing the flow user = auth.user nid = kwargs.get('nid') or kwargs.get('pid') node = models.Node.load(nid) if nid else None node_addon = user.get_addon('googledrive') # Fail if node provided and user not contributor if node and not node.is_contributor(user): raise HTTPError(http.FORBIDDEN) # Handle if user has already authorized google drive if node_addon and node_addon.has_auth: return redirect(web_url_for('user_addons')) client = GoogleAuthClient() authorization_url, state = client.start() session.data['googledrive_auth_state'] = state if nid: session.data['googledrive_auth_nid'] = nid return redirect(authorization_url)
def refresh_access_token(self, force=False): if self._needs_refresh() or force: client = GoogleAuthClient() token = client.refresh(self.access_token, self.refresh_token) self.access_token = token['access_token'] self.refresh_token = token['refresh_token'] self.expires_at = datetime.utcfromtimestamp(token['expires_at']) self.save()
def googledrive_oauth_finish(auth, **kwargs): """View called when the Oauth flow is completed. Adds a new GoogleDriveUserSettings record to the user and saves the user's access token and account info. """ user = auth.user node = Node.load(session.data.pop('googledrive_auth_nid', None)) # Handle request cancellations from Google's API if request.args.get('error'): flash('Google Drive authorization request cancelled.') if node: return redirect(node.web_url_for('node_setting')) return redirect(web_url_for('user_addons')) user.add_addon('googledrive') user.save() code = request.args.get('code') user_settings = user.get_addon('googledrive') state = session.data.pop('googledrive_auth_state') if state != request.args.get('state'): raise HTTPError(http.BAD_REQUEST) if code is None: raise HTTPError(http.BAD_REQUEST) auth_client = GoogleAuthClient() token = auth_client.finish(code) info = auth_client.userinfo(token['access_token']) # Attempt to attach an existing oauth settings model oauth_settings = GoogleDriveOAuthSettings.load(info['sub']) # Create a new oauth settings model if not oauth_settings: oauth_settings = GoogleDriveOAuthSettings() oauth_settings.user_id = info['sub'] oauth_settings.save() user_settings.oauth_settings = oauth_settings user_settings.username = info['name'] user_settings.access_token = token['access_token'] user_settings.refresh_token = token['refresh_token'] user_settings.expires_at = datetime.utcfromtimestamp(token['expires_at']) user_settings.save() flash('Successfully authorized Google Drive', 'success') if node: if node.has_addon('googledrive'): node_addon = node.get_addon('googledrive') node_addon.set_user_auth(user_settings) node_addon.save() return redirect(node.web_url_for('node_setting')) return redirect(web_url_for('user_addons'))
def revoke_access_token(self): # if there is only one osf user linked to this google drive user oauth, revoke the token, # otherwise, disconnect the osf user from the googledriveoauthsettings if len(self.googledriveusersettings__accessed) <= 1: client = GoogleAuthClient() try: client.revoke(self.access_token) except: # no need to fail, revoke is opportunistic pass # remove the object as its the last instance. GoogleDriveOAuthSettings.remove_one(self)
class GoogleDriveProvider(ExternalProvider): name = 'Google Drive' short_name = 'googledrive' client_id = drive_settings.CLIENT_ID client_secret = drive_settings.CLIENT_SECRET auth_url_base = '{}{}'.format( drive_settings.OAUTH_BASE_URL, 'auth?access_type=offline&approval_prompt=force') callback_url = '{}{}'.format(drive_settings.API_BASE_URL, 'oauth2/v3/token') auto_refresh_url = callback_url refresh_time = drive_settings.REFRESH_TIME default_scopes = drive_settings.OAUTH_SCOPE _auth_client = GoogleAuthClient() _drive_client = GoogleDriveClient() def handle_callback(self, response): client = self._auth_client info = client.userinfo(response['access_token']) return { 'provider_id': info['sub'], 'display_name': info['name'], 'profile_url': info.get('profile', None) } def fetch_access_token(self, force_refresh=False): self.refresh_oauth_key(force=force_refresh) return self.account.oauth_key
class GoogleDriveProvider(ExternalProvider): name = 'Google Drive' short_name = 'googledrive' client_id = drive_settings.CLIENT_ID client_secret = drive_settings.CLIENT_SECRET auth_url_base = '{}{}'.format( drive_settings.OAUTH_BASE_URL, 'auth?access_type=offline&approval_prompt=force') callback_url = '{}{}'.format(drive_settings.API_BASE_URL, 'oauth2/v3/token') default_scopes = drive_settings.OAUTH_SCOPE _auth_client = GoogleAuthClient() _drive_client = GoogleDriveClient() def handle_callback(self, response): client = self._auth_client info = client.userinfo(response['access_token']) return { 'provider_id': info['sub'], 'display_name': info['name'], 'profile_url': info.get('profile', None) } def _refresh_token(self, access_token, refresh_token): """ Handles the actual request to refresh tokens :param str access_token: Access token (oauth key) associated with this account :param str refresh_token: Refresh token used to request a new access token :return dict token: New set of tokens """ client = self._auth_client if refresh_token: token = client.refresh(access_token, refresh_token) return token else: return False def fetch_access_token(self, force_refresh=False): self.refresh_access_token(force=force_refresh) return self.account.oauth_key def refresh_access_token(self, force=False): """ If the token has expired or will soon, handles refreshing and the storage of new tokens :param bool force: Indicates whether or not to force the refreshing process, for the purpose of ensuring that authorization has not been unexpectedly removed. """ if self._needs_refresh() or force: token = self._refresh_token(self.account.oauth_key, self.account.refresh_token) self.account.oauth_key = token['access_token'] self.account.refresh_token = token['refresh_token'] self.account.expires_at = datetime.utcfromtimestamp( token['expires_at']) self.account.save() def _needs_refresh(self): if self.account.expires_at is None: return False return (self.account.expires_at - datetime.utcnow() ).total_seconds() < drive_settings.REFRESH_TIME