Revert "Initialize enterprise api client with provided user"
This commit is contained in:
committed by
Douglas Hall
parent
ab71318104
commit
bf3ecc6715
@@ -30,8 +30,8 @@ from openedx.core.lib.api.permissions import ApiKeyHeaderPermission, ApiKeyHeade
|
||||
from openedx.core.lib.exceptions import CourseNotFoundError
|
||||
from openedx.core.lib.log_utils import audit_log
|
||||
from openedx.features.enterprise_support.api import (
|
||||
ConsentApiServiceClient,
|
||||
EnterpriseApiServiceClient,
|
||||
ConsentApiClient,
|
||||
EnterpriseApiClient,
|
||||
EnterpriseApiException,
|
||||
enterprise_enabled
|
||||
)
|
||||
@@ -598,8 +598,8 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
enterprise_course_consent = request.data.get('enterprise_course_consent')
|
||||
explicit_linked_enterprise = request.data.get('linked_enterprise_customer')
|
||||
if (enterprise_course_consent or explicit_linked_enterprise) and has_api_key_permissions and enterprise_enabled():
|
||||
enterprise_api_client = EnterpriseApiServiceClient()
|
||||
consent_client = ConsentApiServiceClient()
|
||||
enterprise_api_client = EnterpriseApiClient()
|
||||
consent_client = ConsentApiClient()
|
||||
# We received an explicitly-linked EnterpriseCustomer for the enrollment
|
||||
if explicit_linked_enterprise is not None:
|
||||
try:
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
"""
|
||||
APIs providing support for enterprise functionality.
|
||||
"""
|
||||
import hashlib
|
||||
import logging
|
||||
from functools import wraps
|
||||
|
||||
import six
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.cache import cache
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.shortcuts import redirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.translation import ugettext as _
|
||||
from edx_rest_api_client.client import EdxRestApiClient
|
||||
from requests.exceptions import ConnectionError, Timeout
|
||||
from slumber.exceptions import HttpClientError, HttpNotFoundError, HttpServerError, SlumberBaseException
|
||||
|
||||
from openedx.core.djangoapps.catalog.models import CatalogIntegration
|
||||
from openedx.core.djangoapps.catalog.utils import create_catalog_api_client
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.lib.token_utils import JwtBuilder
|
||||
from third_party_auth.pipeline import get as get_partial_pipeline
|
||||
@@ -24,7 +30,6 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
CONSENT_FAILED_PARAMETER = 'consent_failed'
|
||||
LOGGER = logging.getLogger("edx.enterprise_helpers")
|
||||
|
||||
@@ -41,12 +46,12 @@ class ConsentApiClient(object):
|
||||
Class for producing an Enterprise Consent service API client
|
||||
"""
|
||||
|
||||
def __init__(self, user):
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize an authenticated Consent service API client by using the
|
||||
provided user.
|
||||
Initialize a consent service API client, authenticated using the Enterprise worker username.
|
||||
"""
|
||||
jwt = JwtBuilder(user).build_token([])
|
||||
self.user = User.objects.get(username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME)
|
||||
jwt = JwtBuilder(self.user).build_token([])
|
||||
url = configuration_helpers.get_value('ENTERPRISE_CONSENT_API_URL', settings.ENTERPRISE_CONSENT_API_URL)
|
||||
self.client = EdxRestApiClient(
|
||||
url,
|
||||
@@ -92,38 +97,17 @@ class ConsentApiClient(object):
|
||||
return response['consent_required']
|
||||
|
||||
|
||||
class EnterpriseServiceClientMixin(object):
|
||||
"""
|
||||
Class for initializing an Enterprise API clients with service user.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize an authenticated Enterprise API client by using the
|
||||
Enterprise worker user by default.
|
||||
"""
|
||||
user = User.objects.get(username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME)
|
||||
super(EnterpriseServiceClientMixin, self).__init__(user)
|
||||
|
||||
|
||||
class ConsentApiServiceClient(EnterpriseServiceClientMixin, ConsentApiClient):
|
||||
"""
|
||||
Class for producing an Enterprise Consent API client with service user.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class EnterpriseApiClient(object):
|
||||
"""
|
||||
Class for producing an Enterprise service API client.
|
||||
"""
|
||||
|
||||
def __init__(self, user):
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize an authenticated Enterprise service API client by using the
|
||||
provided user.
|
||||
Initialize an Enterprise service API client, authenticated using the Enterprise worker username.
|
||||
"""
|
||||
jwt = JwtBuilder(user).build_token([])
|
||||
self.user = User.objects.get(username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME)
|
||||
jwt = JwtBuilder(self.user).build_token([])
|
||||
self.client = EdxRestApiClient(
|
||||
configuration_helpers.get_value('ENTERPRISE_API_URL', settings.ENTERPRISE_API_URL),
|
||||
jwt=jwt
|
||||
@@ -257,13 +241,6 @@ class EnterpriseApiClient(object):
|
||||
return response
|
||||
|
||||
|
||||
class EnterpriseApiServiceClient(EnterpriseServiceClientMixin, EnterpriseApiClient):
|
||||
"""
|
||||
Class for producing an Enterprise service API client with service user.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def data_sharing_consent_required(view_func):
|
||||
"""
|
||||
Decorator which makes a view method redirect to the Data Sharing Consent form if:
|
||||
@@ -317,7 +294,7 @@ def enterprise_customer_for_request(request):
|
||||
if not enterprise_enabled():
|
||||
return None
|
||||
|
||||
enterprise_customer = None
|
||||
ec = None
|
||||
sso_provider_id = request.GET.get('tpa_hint')
|
||||
|
||||
running_pipeline = get_partial_pipeline(request)
|
||||
@@ -334,38 +311,34 @@ def enterprise_customer_for_request(request):
|
||||
# Check if there's an Enterprise Customer such that the linked SSO provider
|
||||
# has an ID equal to the ID we got from the running pipeline or from the
|
||||
# request tpa_hint URL parameter.
|
||||
enterprise_customer_uuid = EnterpriseCustomer.objects.get(
|
||||
ec_uuid = EnterpriseCustomer.objects.get(
|
||||
enterprise_customer_identity_provider__provider_id=sso_provider_id
|
||||
).uuid
|
||||
except EnterpriseCustomer.DoesNotExist:
|
||||
# If there is not an EnterpriseCustomer linked to this SSO provider, set
|
||||
# the UUID variable to be null.
|
||||
enterprise_customer_uuid = None
|
||||
ec_uuid = None
|
||||
else:
|
||||
# Check if we got an Enterprise UUID passed directly as either a query
|
||||
# parameter, or as a value in the Enterprise cookie.
|
||||
enterprise_customer_uuid = request.GET.get('enterprise_customer') or request.COOKIES.get(
|
||||
settings.ENTERPRISE_CUSTOMER_COOKIE_NAME
|
||||
)
|
||||
ec_uuid = request.GET.get('enterprise_customer') or request.COOKIES.get(settings.ENTERPRISE_CUSTOMER_COOKIE_NAME)
|
||||
|
||||
if not enterprise_customer_uuid and request.user.is_authenticated():
|
||||
if not ec_uuid and request.user.is_authenticated():
|
||||
# If there's no way to get an Enterprise UUID for the request, check to see
|
||||
# if there's already an Enterprise attached to the requesting user on the backend.
|
||||
learner_data = get_enterprise_learner_data(request.site, request.user)
|
||||
if learner_data:
|
||||
enterprise_customer_uuid = learner_data[0]['enterprise_customer']['uuid']
|
||||
if enterprise_customer_uuid:
|
||||
ec_uuid = learner_data[0]['enterprise_customer']['uuid']
|
||||
if ec_uuid:
|
||||
# If we were able to obtain an EnterpriseCustomer UUID, go ahead
|
||||
# and use it to attempt to retrieve EnterpriseCustomer details
|
||||
# from the EnterpriseCustomer API.
|
||||
try:
|
||||
enterprise_customer = EnterpriseApiClient(user=request.user).get_enterprise_customer(
|
||||
enterprise_customer_uuid
|
||||
)
|
||||
ec = EnterpriseApiClient().get_enterprise_customer(ec_uuid)
|
||||
except HttpNotFoundError:
|
||||
enterprise_customer = None
|
||||
ec = None
|
||||
|
||||
return enterprise_customer
|
||||
return ec
|
||||
|
||||
|
||||
def consent_needed_for_course(request, user, course_id, enrollment_exists=False):
|
||||
@@ -385,7 +358,7 @@ def consent_needed_for_course(request, user, course_id, enrollment_exists=False)
|
||||
if not enterprise_learner_details:
|
||||
consent_needed = False
|
||||
else:
|
||||
client = ConsentApiClient(user=request.user)
|
||||
client = ConsentApiClient()
|
||||
consent_needed = any(
|
||||
client.consent_required(
|
||||
username=user.username,
|
||||
@@ -453,7 +426,7 @@ def get_enterprise_learner_data(site, user):
|
||||
if not enterprise_enabled():
|
||||
return None
|
||||
|
||||
enterprise_learner_data = EnterpriseApiClient(user=user).fetch_enterprise_learner_data(site=site, user=user)
|
||||
enterprise_learner_data = EnterpriseApiClient().fetch_enterprise_learner_data(site=site, user=user)
|
||||
if enterprise_learner_data:
|
||||
return enterprise_learner_data['results']
|
||||
|
||||
@@ -488,7 +461,7 @@ def get_dashboard_consent_notification(request, user, course_enrollments):
|
||||
enrollment = course_enrollment
|
||||
break
|
||||
|
||||
client = ConsentApiClient(user=request.user)
|
||||
client = ConsentApiClient()
|
||||
consent_needed = client.consent_required(
|
||||
enterprise_customer_uuid=enterprise_customer['uuid'],
|
||||
username=user.username,
|
||||
|
||||
@@ -8,20 +8,16 @@ import ddt
|
||||
import httpretty
|
||||
import mock
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from openedx.features.enterprise_support.api import (
|
||||
ConsentApiClient,
|
||||
ConsentApiServiceClient,
|
||||
consent_needed_for_course,
|
||||
data_sharing_consent_required,
|
||||
EnterpriseApiClient,
|
||||
EnterpriseApiServiceClient,
|
||||
enterprise_customer_for_request,
|
||||
enterprise_enabled,
|
||||
get_dashboard_consent_notification,
|
||||
get_enterprise_consent_url,
|
||||
)
|
||||
@@ -48,86 +44,21 @@ class TestEnterpriseApi(EnterpriseServiceMockMixin, TestCase):
|
||||
"""
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = UserFactory.create(
|
||||
username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME,
|
||||
UserFactory.create(
|
||||
username='enterprise_worker',
|
||||
email='ent_worker@example.com',
|
||||
password='password123',
|
||||
)
|
||||
super(TestEnterpriseApi, cls).setUpTestData()
|
||||
|
||||
def _assert_api_service_client(self, api_client, mocked_jwt_builder):
|
||||
"""
|
||||
Verify that the provided api client uses the enterprise service user to generate
|
||||
JWT token for auth.
|
||||
"""
|
||||
mocked_jwt_builder.return_value.build_token.return_value = 'test-token'
|
||||
enterprise_service_user = User.objects.get(username=settings.ENTERPRISE_SERVICE_WORKER_USERNAME)
|
||||
enterprise_api_service_client = api_client()
|
||||
|
||||
mocked_jwt_builder.assert_called_once_with(enterprise_service_user)
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(enterprise_api_service_client.client._store['session'].auth.token, 'test-token')
|
||||
|
||||
def _assert_api_client_with_user(self, api_client, mocked_jwt_builder):
|
||||
"""
|
||||
Verify that the provided api client uses the expected user to generate
|
||||
JWT token for auth.
|
||||
"""
|
||||
mocked_jwt_builder.return_value.build_token.return_value = 'test-token'
|
||||
dummy_enterprise_user = UserFactory.create(
|
||||
username='dummy-enterprise-user',
|
||||
email='dummy-enterprise-user@example.com',
|
||||
password='password123',
|
||||
)
|
||||
enterprise_api_service_client = api_client(dummy_enterprise_user)
|
||||
|
||||
mocked_jwt_builder.assert_called_once_with(dummy_enterprise_user)
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(enterprise_api_service_client.client._store['session'].auth.token, 'test-token')
|
||||
|
||||
@httpretty.activate
|
||||
@mock.patch('openedx.features.enterprise_support.api.JwtBuilder')
|
||||
def test_enterprise_api_client_with_service_user(self, mock_jwt_builder):
|
||||
"""
|
||||
Verify that enterprise API service client uses enterprise service user
|
||||
by default to authenticate and access enterprise API.
|
||||
"""
|
||||
self._assert_api_service_client(EnterpriseApiServiceClient, mock_jwt_builder)
|
||||
|
||||
@httpretty.activate
|
||||
@mock.patch('openedx.features.enterprise_support.api.JwtBuilder')
|
||||
def test_enterprise_api_client_with_user(self, mock_jwt_builder):
|
||||
"""
|
||||
Verify that enterprise API client uses the provided user to
|
||||
authenticate and access enterprise API.
|
||||
"""
|
||||
self._assert_api_client_with_user(EnterpriseApiClient, mock_jwt_builder)
|
||||
|
||||
@httpretty.activate
|
||||
@mock.patch('openedx.features.enterprise_support.api.JwtBuilder')
|
||||
def test_enterprise_consent_api_client_with_service_user(self, mock_jwt_builder):
|
||||
"""
|
||||
Verify that enterprise API consent service client uses enterprise
|
||||
service user by default to authenticate and access enterprise API.
|
||||
"""
|
||||
self._assert_api_service_client(ConsentApiServiceClient, mock_jwt_builder)
|
||||
|
||||
@httpretty.activate
|
||||
@mock.patch('openedx.features.enterprise_support.api.JwtBuilder')
|
||||
def test_enterprise_consent_api_client_with_user(self, mock_jwt_builder):
|
||||
"""
|
||||
Verify that enterprise API consent service client uses the provided
|
||||
user to authenticate and access enterprise API.
|
||||
"""
|
||||
self._assert_api_client_with_user(ConsentApiClient, mock_jwt_builder)
|
||||
|
||||
@httpretty.activate
|
||||
@override_settings(ENTERPRISE_SERVICE_WORKER_USERNAME='enterprise_worker')
|
||||
def test_consent_needed_for_course(self):
|
||||
user = mock.MagicMock(
|
||||
username='janedoe',
|
||||
is_authenticated=lambda: True,
|
||||
)
|
||||
request = mock.MagicMock(session={}, user=user)
|
||||
request = mock.MagicMock(session={})
|
||||
self.mock_enterprise_learner_api()
|
||||
self.mock_consent_missing(user.username, 'fake-course', 'cf246b88-d5f6-4908-a522-fc307e0b0c59')
|
||||
self.assertTrue(consent_needed_for_course(request, user, 'fake-course'))
|
||||
@@ -143,65 +74,63 @@ class TestEnterpriseApi(EnterpriseServiceMockMixin, TestCase):
|
||||
@mock.patch('openedx.features.enterprise_support.api.EnterpriseCustomer')
|
||||
@mock.patch('openedx.features.enterprise_support.api.get_partial_pipeline')
|
||||
@mock.patch('openedx.features.enterprise_support.api.Registry')
|
||||
@override_settings(ENTERPRISE_SERVICE_WORKER_USERNAME='enterprise_worker')
|
||||
def test_enterprise_customer_for_request(
|
||||
self,
|
||||
mock_registry,
|
||||
mock_partial,
|
||||
mock_enterprise_customer_model,
|
||||
mock_ec_model,
|
||||
mock_get_el_data
|
||||
):
|
||||
def mock_get_enterprise_customer(**kwargs):
|
||||
def mock_get_ec(**kwargs):
|
||||
uuid = kwargs.get('enterprise_customer_identity_provider__provider_id')
|
||||
if uuid:
|
||||
return mock.MagicMock(uuid=uuid, user=self.user)
|
||||
return mock.MagicMock(uuid=uuid)
|
||||
raise Exception
|
||||
|
||||
dummy_request = mock.MagicMock(session={}, user=self.user)
|
||||
mock_enterprise_customer_model.objects.get.side_effect = mock_get_enterprise_customer
|
||||
mock_enterprise_customer_model.DoesNotExist = Exception
|
||||
mock_ec_model.objects.get.side_effect = mock_get_ec
|
||||
mock_ec_model.DoesNotExist = Exception
|
||||
|
||||
mock_partial.return_value = True
|
||||
mock_registry.get_from_pipeline.return_value.provider_id = 'real-ent-uuid'
|
||||
|
||||
self.mock_get_enterprise_customer('real-ent-uuid', {'real': 'enterprisecustomer'}, 200)
|
||||
self.mock_get_enterprise_customer('real-ent-uuid', {"real": "enterprisecustomer"}, 200)
|
||||
|
||||
enterprise_customer = enterprise_customer_for_request(dummy_request)
|
||||
ec = enterprise_customer_for_request(mock.MagicMock())
|
||||
|
||||
self.assertEqual(enterprise_customer, {'real': 'enterprisecustomer'})
|
||||
self.assertEqual(ec, {"real": "enterprisecustomer"})
|
||||
|
||||
httpretty.reset()
|
||||
|
||||
self.mock_get_enterprise_customer('real-ent-uuid', {'detail': 'Not found.'}, 404)
|
||||
self.mock_get_enterprise_customer('real-ent-uuid', {"detail": "Not found."}, 404)
|
||||
|
||||
enterprise_customer = enterprise_customer_for_request(dummy_request)
|
||||
ec = enterprise_customer_for_request(mock.MagicMock())
|
||||
|
||||
self.assertIsNone(enterprise_customer)
|
||||
self.assertIsNone(ec)
|
||||
|
||||
mock_registry.get_from_pipeline.return_value.provider_id = None
|
||||
|
||||
httpretty.reset()
|
||||
|
||||
self.mock_get_enterprise_customer('real-ent-uuid', {'real': 'enterprisecustomer'}, 200)
|
||||
self.mock_get_enterprise_customer('real-ent-uuid', {"real": "enterprisecustomer"}, 200)
|
||||
|
||||
enterprise_customer = enterprise_customer_for_request(
|
||||
mock.MagicMock(GET={'enterprise_customer': 'real-ent-uuid'}, user=self.user)
|
||||
ec = enterprise_customer_for_request(mock.MagicMock(GET={"enterprise_customer": 'real-ent-uuid'}))
|
||||
|
||||
self.assertEqual(ec, {"real": "enterprisecustomer"})
|
||||
|
||||
ec = enterprise_customer_for_request(
|
||||
mock.MagicMock(GET={}, COOKIES={settings.ENTERPRISE_CUSTOMER_COOKIE_NAME: 'real-ent-uuid'})
|
||||
)
|
||||
|
||||
self.assertEqual(enterprise_customer, {'real': 'enterprisecustomer'})
|
||||
|
||||
enterprise_customer = enterprise_customer_for_request(
|
||||
mock.MagicMock(GET={}, COOKIES={settings.ENTERPRISE_CUSTOMER_COOKIE_NAME: 'real-ent-uuid'}, user=self.user)
|
||||
)
|
||||
|
||||
self.assertEqual(enterprise_customer, {'real': 'enterprisecustomer'})
|
||||
self.assertEqual(ec, {"real": "enterprisecustomer"})
|
||||
|
||||
mock_get_el_data.return_value = [{'enterprise_customer': {'uuid': 'real-ent-uuid'}}]
|
||||
|
||||
enterprise_customer = enterprise_customer_for_request(
|
||||
mock.MagicMock(GET={}, COOKIES={}, user=self.user, site=1)
|
||||
ec = enterprise_customer_for_request(
|
||||
mock.MagicMock(GET={}, COOKIES={}, user=mock.MagicMock(is_authenticated=lambda: True), site=1)
|
||||
)
|
||||
|
||||
self.assertEqual(enterprise_customer, {'real': 'enterprisecustomer'})
|
||||
self.assertEqual(ec, {"real": "enterprisecustomer"})
|
||||
|
||||
def check_data_sharing_consent(self, consent_required=False, consent_url=None):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user