def test_utils_with_enterprise_disabled(self):
     """
     Test that disabling the enterprise integration flag causes
     the utilities to return the expected default values.
     """
     self.assertFalse(enterprise_enabled())
     self.assertEqual(insert_enterprise_pipeline_elements(None), None)
예제 #2
0
 def test_utils_with_enterprise_disabled(self):
     """
     Test that disabling the enterprise integration flag causes
     the utilities to return the expected default values.
     """
     self.assertFalse(enterprise_enabled())
     self.assertEqual(insert_enterprise_pipeline_elements(None), None)
 def test_utils_with_enterprise_enabled(self):
     """
     Test that enabling enterprise integration (which is currently on by default) causes the
     the utilities to return the expected values.
     """
     self.assertTrue(enterprise_enabled())
     pipeline = ['abc', 'social.pipeline.social_auth.load_extra_data', 'def']
     insert_enterprise_pipeline_elements(pipeline)
     self.assertEqual(pipeline, ['abc',
                                 'enterprise.tpa_pipeline.handle_enterprise_logistration',
                                 'social.pipeline.social_auth.load_extra_data',
                                 'def'])
예제 #4
0
 def test_utils_with_enterprise_enabled(self):
     """
     Test that enabling enterprise integration (which is currently on by default) causes the
     the utilities to return the expected values.
     """
     self.assertTrue(enterprise_enabled())
     pipeline = [
         'abc', 'social.pipeline.social_auth.load_extra_data', 'def'
     ]
     insert_enterprise_pipeline_elements(pipeline)
     self.assertEqual(pipeline, [
         'abc', 'enterprise.tpa_pipeline.handle_enterprise_logistration',
         'social.pipeline.social_auth.load_extra_data', 'def'
     ])
예제 #5
0
class SettingsUnitTest(testutil.TestCase):
    """Unit tests for settings management code."""

    # Allow access to protected methods (or module-protected methods) under test.
    # pylint: disable=protected-access
    # Suppress sprurious no-member warning on fakes.
    # pylint: disable=no-member

    def setUp(self):
        super(SettingsUnitTest, self).setUp()
        self.settings = testutil.FakeDjangoSettings(_SETTINGS_MAP)

    def test_apply_settings_adds_exception_middleware(self):
        settings.apply_settings(self.settings)
        for middleware_name in settings._MIDDLEWARE_CLASSES:
            self.assertIn(middleware_name, self.settings.MIDDLEWARE_CLASSES)

    def test_apply_settings_adds_fields_stored_in_session(self):
        settings.apply_settings(self.settings)
        self.assertEqual(settings._FIELDS_STORED_IN_SESSION,
                         self.settings.FIELDS_STORED_IN_SESSION)

    @unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED,
                         'third_party_auth not enabled')
    def test_apply_settings_enables_no_providers_by_default(self):
        # Providers are only enabled via ConfigurationModels in the database
        settings.apply_settings(self.settings)
        self.assertEqual([], provider.Registry.enabled())

    def test_apply_settings_turns_off_raising_social_exceptions(self):
        # Guard against submitting a conf change that's convenient in dev but
        # bad in prod.
        settings.apply_settings(self.settings)
        self.assertFalse(self.settings.SOCIAL_AUTH_RAISE_EXCEPTIONS)

    @unittest.skipUnless(enterprise_enabled(), 'enterprise not enabled')
    def test_enterprise_elements_inserted(self):
        settings.apply_settings(self.settings)
        self.assertIn(
            'enterprise.tpa_pipeline.set_data_sharing_consent_record',
            self.settings.SOCIAL_AUTH_PIPELINE)
        self.assertIn('enterprise.tpa_pipeline.verify_data_sharing_consent',
                      self.settings.SOCIAL_AUTH_PIPELINE)
예제 #6
0
urlpatterns += (url(r'^debug/show_parameters$',
                    'debug.views.show_parameters'), )

# Third-party auth.
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
    urlpatterns += (
        url(r'', include('third_party_auth.urls')),
        url(r'api/third_party_auth/', include('third_party_auth.api.urls')),
        # NOTE: The following login_oauth_token endpoint is DEPRECATED.
        # Please use the exchange_access_token endpoint instead.
        url(r'^login_oauth_token/(?P<backend>[^/]+)/$',
            'student.views.login_oauth_token'),
    )

# Enterprise
if enterprise_enabled():
    urlpatterns += (url(r'', include('enterprise.urls')), )

# OAuth token exchange
if settings.FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
    urlpatterns += (url(r'^oauth2/login/$',
                        LoginWithAccessTokenView.as_view(),
                        name="login_with_access_token"), )

# Certificates
urlpatterns += (
    url(
        r'^certificates/',
        include('certificates.urls',
                app_name="certificates",
                namespace="certificates")),
예제 #7
0
    url(r'^debug/show_parameters$', 'debug.views.show_parameters'),
)


# Third-party auth.
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
    urlpatterns += (
        url(r'', include('third_party_auth.urls')),
        url(r'api/third_party_auth/', include('third_party_auth.api.urls')),
        # NOTE: The following login_oauth_token endpoint is DEPRECATED.
        # Please use the exchange_access_token endpoint instead.
        url(r'^login_oauth_token/(?P<backend>[^/]+)/$', 'student.views.login_oauth_token'),
    )

# Enterprise
if enterprise_enabled():
    urlpatterns += (
        url(r'', include('enterprise.urls')),
    )

# OAuth token exchange
if settings.FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
    urlpatterns += (
        url(
            r'^oauth2/login/$',
            LoginWithAccessTokenView.as_view(),
            name="login_with_access_token"
        ),
    )

# Certificates
 def test_enterprise_enabled(self):
     """
     The test settings inherit from common, which have the enterprise
     app installed; therefore, it should appear installed here.
     """
     self.assertTrue(enterprise_enabled())
예제 #9
0
 def test_enterprise_enabled(self):
     """
     The test settings inherit from common, which have the enterprise
     app installed; therefore, it should appear installed here.
     """
     self.assertTrue(enterprise_enabled())
예제 #10
0
    def post(self, request):
        """Enrolls the currently logged-in user in a course.

        Server-to-server calls may deactivate or modify the mode of existing enrollments. All other requests
        go through `add_enrollment()`, which allows creation of new and reactivation of old enrollments.
        """
        # Get the User, Course ID, and Mode from the request.

        username = request.data.get('user', request.user.username)
        course_id = request.data.get('course_details', {}).get('course_id')

        if not course_id:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={"message": u"Course ID must be specified to create a new enrollment."}
            )

        try:
            course_id = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message": u"No course '{course_id}' found for enrollment".format(course_id=course_id)
                }
            )

        mode = request.data.get('mode')

        has_api_key_permissions = self.has_api_key_permissions(request)

        # Check that the user specified is either the same user, or this is a server-to-server request.
        if not username:
            username = request.user.username
        if username != request.user.username and not has_api_key_permissions:
            # Return a 404 instead of a 403 (Unauthorized). If one user is looking up
            # other users, do not let them deduce the existence of an enrollment.
            return Response(status=status.HTTP_404_NOT_FOUND)

        if mode not in (CourseMode.AUDIT, CourseMode.HONOR, None) and not has_api_key_permissions:
            return Response(
                status=status.HTTP_403_FORBIDDEN,
                data={
                    "message": u"User does not have permission to create enrollment with mode [{mode}].".format(
                        mode=mode
                    )
                }
            )

        try:
            # Lookup the user, instead of using request.user, since request.user may not match the username POSTed.
            user = User.objects.get(username=username)
        except ObjectDoesNotExist:
            return Response(
                status=status.HTTP_406_NOT_ACCEPTABLE,
                data={
                    'message': u'The user {} does not exist.'.format(username)
                }
            )

        embargo_response = embargo_api.get_embargo_response(request, course_id, user)

        if embargo_response:
            return embargo_response

        try:
            is_active = request.data.get('is_active')
            # Check if the requested activation status is None or a Boolean
            if is_active is not None and not isinstance(is_active, bool):
                return Response(
                    status=status.HTTP_400_BAD_REQUEST,
                    data={
                        'message': (u"'{value}' is an invalid enrollment activation status.").format(value=is_active)
                    }
                )

            enterprise_course_consent = request.data.get('enterprise_course_consent')
            # Check if the enterprise_course_enrollment is a boolean
            if has_api_key_permissions and enterprise_enabled() and enterprise_course_consent is not None:
                if not isinstance(enterprise_course_consent, bool):
                    return Response(
                        status=status.HTTP_400_BAD_REQUEST,
                        data={
                            'message': (u"'{value}' is an invalid enterprise course consent value.").format(
                                value=enterprise_course_consent
                            )
                        }
                    )
                try:
                    EnterpriseApiClient().post_enterprise_course_enrollment(
                        username,
                        unicode(course_id),
                        enterprise_course_consent
                    )
                except EnterpriseApiException as error:
                    log.exception("An unexpected error occurred while creating the new EnterpriseCourseEnrollment "
                                  "for user [%s] in course run [%s]", username, course_id)
                    raise CourseEnrollmentError(error.message)

            enrollment_attributes = request.data.get('enrollment_attributes')
            enrollment = api.get_enrollment(username, unicode(course_id))
            mode_changed = enrollment and mode is not None and enrollment['mode'] != mode
            active_changed = enrollment and is_active is not None and enrollment['is_active'] != is_active
            missing_attrs = []
            if enrollment_attributes:
                actual_attrs = [
                    u"{namespace}:{name}".format(**attr)
                    for attr in enrollment_attributes
                ]
                missing_attrs = set(REQUIRED_ATTRIBUTES.get(mode, [])) - set(actual_attrs)
            if has_api_key_permissions and (mode_changed or active_changed):
                if mode_changed and active_changed and not is_active:
                    # if the requester wanted to deactivate but specified the wrong mode, fail
                    # the request (on the assumption that the requester had outdated information
                    # about the currently active enrollment).
                    msg = u"Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate.".format(
                        enrollment["mode"], mode
                    )
                    log.warning(msg)
                    return Response(status=status.HTTP_400_BAD_REQUEST, data={"message": msg})

                if len(missing_attrs) > 0:
                    msg = u"Missing enrollment attributes: requested mode={} required attributes={}".format(
                        mode, REQUIRED_ATTRIBUTES.get(mode)
                    )
                    log.warning(msg)
                    return Response(status=status.HTTP_400_BAD_REQUEST, data={"message": msg})

                response = api.update_enrollment(
                    username,
                    unicode(course_id),
                    mode=mode,
                    is_active=is_active,
                    enrollment_attributes=enrollment_attributes
                )
            else:
                # Will reactivate inactive enrollments.
                response = api.add_enrollment(username, unicode(course_id), mode=mode, is_active=is_active)

            email_opt_in = request.data.get('email_opt_in', None)
            if email_opt_in is not None:
                org = course_id.org
                update_email_opt_in(request.user, org, email_opt_in)

            log.info('The user [%s] has already been enrolled in course run [%s].', username, course_id)
            return Response(response)
        except CourseModeNotFoundError as error:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message": (
                        u"The [{mode}] course mode is expired or otherwise unavailable for course run [{course_id}]."
                    ).format(mode=mode, course_id=course_id),
                    "course_details": error.data
                })
        except CourseNotFoundError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message": u"No course '{course_id}' found for enrollment".format(course_id=course_id)
                }
            )
        except CourseEnrollmentExistsError as error:
            log.warning('An enrollment already exists for user [%s] in course run [%s].', username, course_id)
            return Response(data=error.enrollment)
        except CourseEnrollmentError:
            log.exception("An error occurred while creating the new course enrollment for user "
                          "[%s] in course run [%s]", username, course_id)
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message": (
                        u"An error occurred while creating the new course enrollment for user "
                        u"'{username}' in course '{course_id}'"
                    ).format(username=username, course_id=course_id)
                }
            )
        finally:
            # Assumes that the ecommerce service uses an API key to authenticate.
            if has_api_key_permissions:
                current_enrollment = api.get_enrollment(username, unicode(course_id))
                audit_log(
                    'enrollment_change_requested',
                    course_id=unicode(course_id),
                    requested_mode=mode,
                    actual_mode=current_enrollment['mode'] if current_enrollment else None,
                    requested_activation=is_active,
                    actual_activation=current_enrollment['is_active'] if current_enrollment else None,
                    user_id=user.id
                )