Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ask users to provide a new google oauth credential if current one is invalid #2326

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion onadata/libs/tests/utils/test_api_export_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from collections import OrderedDict, defaultdict

import mock
import datetime
from google.oauth2.credentials import Credentials
from celery.backends.rpc import BacklogLimitExceeded
from django.http import Http404
from django.test.utils import override_settings
Expand All @@ -13,12 +15,14 @@

from onadata.apps.logger.models import XForm
from onadata.apps.main.tests.test_base import TestBase
from onadata.apps.main.models import TokenStorageModel
from onadata.apps.viewer.models.export import Export, ExportConnectionError
from onadata.libs.exceptions import ServiceUnavailable
from onadata.libs.utils.api_export_tools import (
get_async_response, process_async_export,
response_for_format,
get_metadata_format
get_metadata_format,
_get_google_credential
)
from onadata.libs.utils.async_status import SUCCESSFUL, status_msg

Expand All @@ -28,6 +32,15 @@ class TestApiExportTools(TestBase):
Test api_export_tools.
"""

google_credential = {
"refresh_token": "refresh-token",
"token_uri": "https://oauth2.googleapis.com/token",
"client_id": "client-id",
"client_secret": "client-secret",
"scopes": ["https://www.googleapis.com/auth/drive.file"],
"expiry": datetime.datetime(2016, 8, 18, 12, 43, 30, 316792)
}

def _create_old_export(self, xform, export_type, options, filename=None):
options = OrderedDict(sorted(options.items()))
Export(
Expand All @@ -40,6 +53,49 @@ def _create_old_export(self, xform, export_type, options, filename=None):
self.export = Export.objects.filter(
xform=xform, export_type=export_type)[0]

def test_get_google_credentials(self):
"""
Test create_async_export deletes credential when invalid
"""
request = self.factory.get('/')
request.user = self.user
request.query_params = {}
request.data = {}
credential = self.google_credential
t = TokenStorageModel(id=self.user,
credential=Credentials(**credential, token=None))
t.save()
self.assertFalse(t.credential.valid)
response = _get_google_credential(request)

self.assertEqual(response.status_code, 302)
self.assertEqual(
response.url[:71],
'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id='
)
with self.assertRaises(TokenStorageModel.DoesNotExist):
TokenStorageModel.objects.get(id=self.user)

def test_get_google_credentials_valid(self):
"""
Test create_async_export does not get rid of valid credential
"""

request = self.factory.get('/')
request.user = self.user
request.query_params = {}
request.data = {}
self.google_credential['expiry'] = \
datetime.datetime.utcnow() + datetime.timedelta(seconds=300)
credential = self.google_credential
t = TokenStorageModel(id=self.user,
credential=Credentials(**credential, token="token"))
t.save()
self.assertTrue(t.credential.valid)
credential = _get_google_credential(request)

self.assertEqual(credential.to_json(), t.credential.to_json())

# pylint: disable=invalid-name
def test_process_async_export_creates_new_export(self):
"""
Expand Down
15 changes: 14 additions & 1 deletion onadata/libs/utils/api_export_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import sys
from datetime import datetime

from google.auth.transport.requests import Request
from google.auth.exceptions import RefreshError
from google.oauth2.credentials import Credentials # noqa

from django.conf import settings
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404
Expand All @@ -15,7 +19,6 @@
import six
from celery.backends.rpc import BacklogLimitExceeded
from celery.result import AsyncResult
from google.oauth2.credentials import Credentials # noqa
from kombu.exceptions import OperationalError
from rest_framework import exceptions, status
from rest_framework.response import Response
Expand Down Expand Up @@ -627,6 +630,7 @@ def generate_google_web_flow(request):

def _get_google_credential(request):
credential = None
storage = None
if request.user.is_authenticated:
try:
storage = TokenStorageModel.objects.get(id=request.user)
Expand All @@ -636,6 +640,15 @@ def _get_google_credential(request):
elif request.session.get("access_token"):
credential = Credentials(token=request.session["access_token"])

if credential and not credential.valid:
DavisRayM marked this conversation as resolved.
Show resolved Hide resolved
try:
credential.refresh(Request())
DavisRayM marked this conversation as resolved.
Show resolved Hide resolved
storage.credential = credential
storage.save()
except RefreshError:
storage.delete()
credential = None

if not credential:
google_flow = generate_google_web_flow(request)
authorization_url, _state = google_flow.authorization_url(
Expand Down