Exemple #1
0
    def setUp(self):
        super().setUp()
        self.dot_adapter = adapters.DOTAdapter()
        self.csrf_client = APIClient(enforce_csrf_checks=True)
        self.username = '******'
        self.email = '*****@*****.**'
        self.password = '******'
        self.user = UserFactory.create(username=self.username,
                                       email=self.email,
                                       password=self.password)

        self.dot_oauth2_client = self.dot_adapter.create_public_client(
            name='example',
            user=self.user,
            client_id='dot-client-id',
            redirect_uri='https://example.edx/redirect',
        )
        self.dot_access_token = dot_models.AccessToken.objects.create(
            user=self.user,
            token='dot-access-token',
            application=self.dot_oauth2_client,
            expires=now() + timedelta(days=30),
        )
        self.dot_refresh_token = dot_models.RefreshToken.objects.create(
            user=self.user,
            token='dot-refresh-token',
            application=self.dot_oauth2_client,
        )

        # This is the a change we've made from the django-rest-framework-oauth version
        # of these tests.
        self.user.is_active = False
        self.user.save()
Exemple #2
0
class DOTAccessTokenExchangeView(AccessTokenExchangeBase, DOTAccessTokenView):
    """
    View for token exchange from 3rd party OAuth access token to 1st party
    OAuth access token.  Uses django-oauth-toolkit (DOT) to manage access
    tokens.
    """

    oauth2_adapter = adapters.DOTAdapter()

    def create_access_token(self, request, user, scopes, client):
        """
        Create and return a new access token.
        """
        return create_dot_access_token(request, user, client, scopes=scopes)

    def access_token_response(self, token):
        """
        Wrap an access token in an appropriate response
        """
        return Response(data=token)

    def error_response(self, form_errors, **kwargs):  # pylint: disable=arguments-differ
        """
        Return an error response consisting of the errors in the form
        """
        error_code = form_errors.get('error_code', 400)
        return Response(status=error_code, data=form_errors, **kwargs)
Exemple #3
0
class DOTAccessTokenExchangeView(AccessTokenExchangeBase, DOTAccessTokenView):
    """
    View for token exchange from 3rd party OAuth access token to 1st party
    OAuth access token.  Uses django-oauth-toolkit (DOT) to manage access
    tokens.
    """

    oauth2_adapter = adapters.DOTAdapter()

    def get(self, request, _backend):
        return Response(status=400, data={
            'error': 'invalid_request',
            'error_description': 'Only POST requests allowed.',
        })

    def create_access_token(self, request, user, scopes, client):
        """
        Create and return a new access token.
        """
        return create_dot_access_token(request, user, client, scopes=scopes)

    def access_token_response(self, token):
        """
        Wrap an access token in an appropriate response
        """
        return Response(data=token)

    def error_response(self, form_errors, **kwargs):  # pylint: disable=arguments-differ
        """
        Return an error response consisting of the errors in the form
        """
        return Response(status=400, data=form_errors, **kwargs)
Exemple #4
0
class DOTAccessTokenExchangeView(AccessTokenExchangeBase, DOTAccessTokenView):
    """
    View for token exchange from 3rd party OAuth access token to 1st party
    OAuth access token.  Uses django-oauth-toolkit (DOT) to manage access
    tokens.
    """

    oauth2_adapter = adapters.DOTAdapter()

    def get(self, request, _backend):
        return Response(status=400, data={
            'error': 'invalid_request',
            'error_description': 'Only POST requests allowed.',
        })

    def get_access_token(self, request, user, scope, client):
        """
        TODO: MA-2122: Reusing access tokens is not yet supported for DOT.
        Just return a new access token.
        """
        return self.create_access_token(request, user, scope, client)

    def create_access_token(self, request, user, scope, client):
        """
        Create and return a new access token.
        """
        _days = 24 * 60 * 60
        token_generator = BearerToken(
            expires_in=settings.OAUTH_EXPIRE_PUBLIC_CLIENT_DAYS * _days,
            request_validator=oauth2_settings.OAUTH2_VALIDATOR_CLASS(),
        )
        self._populate_create_access_token_request(request, user, scope, client)
        return token_generator.create_token(request, refresh_token=True)

    def access_token_response(self, token):
        """
        Wrap an access token in an appropriate response
        """
        return Response(data=token)

    def _populate_create_access_token_request(self, request, user, scope, client):
        """
        django-oauth-toolkit expects certain non-standard attributes to
        be present on the request object.  This function modifies the
        request object to match these expectations
        """
        request.user = user
        request.scopes = [SCOPE_VALUE_DICT[scope]]
        request.client = client
        request.state = None
        request.refresh_token = None
        request.extra_credentials = None
        request.grant_type = client.authorization_grant_type

    def error_response(self, form_errors, **kwargs):
        """
        Return an error response consisting of the errors in the form
        """
        return Response(status=400, data=form_errors, **kwargs)
Exemple #5
0
class DOTAdapterMixin(object):
    """
    Mixin to rewire existing tests to use django-oauth-toolkit (DOT) backend

    Overwrites self.client_id, self.access_token, self.oauth2_adapter
    """

    client_id = 'dot_test_client_id'
    access_token = 'dot_test_access_token'
    oauth2_adapter = adapters.DOTAdapter()

    def create_public_client(self, user, client_id=None):
        """
        Create an oauth client application that is public.
        """
        return self.oauth2_adapter.create_public_client(
            name='Test Public Application',
            user=user,
            client_id=client_id,
            redirect_uri=DUMMY_REDIRECT_URL,
        )

    def create_confidential_client(self, user, client_id=None):
        """
        Create an oauth client application that is confidential.
        """
        return self.oauth2_adapter.create_confidential_client(
            name='Test Confidential Application',
            user=user,
            client_id=client_id,
            redirect_uri=DUMMY_REDIRECT_URL,
        )

    def get_token_response_keys(self):
        """
        Return the set of keys provided when requesting an access token
        """
        return {
            'access_token', 'refresh_token', 'token_type', 'expires_in',
            'scope'
        }

    def test_get_method(self):
        # Dispatch routes all get methods to DOP, so we test this on the view
        request_factory = RequestFactory()
        request = request_factory.get('/oauth2/exchange_access_token/')
        request.session = {}
        view = DOTAccessTokenExchangeView.as_view()
        response = view(request, backend='facebook')
        self.assertEqual(response.status_code, 400)

    @expectedFailure
    def test_single_access_token(self):
        # TODO: Single access tokens not supported yet for DOT (See MA-2122)
        super(DOTAdapterMixin, self).test_single_access_token()

    @skip("Not supported yet (See MA-2123)")
    def test_scopes(self):
        super(DOTAdapterMixin, self).test_scopes()
Exemple #6
0
    def setUp(self):
        super(OAuth2Tests, self).setUp()
        self.dop_adapter = adapters.DOPAdapter()
        self.dot_adapter = adapters.DOTAdapter()
        self.csrf_client = APIClient(enforce_csrf_checks=True)
        self.username = '******'
        self.email = '*****@*****.**'
        self.password = '******'
        self.user = User.objects.create_user(self.username, self.email, self.password)

        self.CLIENT_ID = 'client_key'  # pylint: disable=invalid-name
        self.CLIENT_SECRET = 'client_secret'  # pylint: disable=invalid-name
        self.ACCESS_TOKEN = 'access_token'  # pylint: disable=invalid-name
        self.REFRESH_TOKEN = 'refresh_token'  # pylint: disable=invalid-name

        self.dop_oauth2_client = self.dop_adapter.create_public_client(
            name='example',
            user=self.user,
            client_id=self.CLIENT_ID,
            redirect_uri='https://example.edx/redirect',
        )

        self.access_token = oauth2_provider.oauth2.models.AccessToken.objects.create(
            token=self.ACCESS_TOKEN,
            client=self.dop_oauth2_client,
            user=self.user,
        )
        self.refresh_token = oauth2_provider.oauth2.models.RefreshToken.objects.create(
            user=self.user,
            access_token=self.access_token,
            client=self.dop_oauth2_client,
        )

        self.dot_oauth2_client = self.dot_adapter.create_public_client(
            name='example',
            user=self.user,
            client_id='dot-client-id',
            redirect_uri='https://example.edx/redirect',
        )
        self.dot_access_token = dot_models.AccessToken.objects.create(
            user=self.user,
            token='dot-access-token',
            application=self.dot_oauth2_client,
            expires=datetime.now() + timedelta(days=30),
        )

        # This is the a change we've made from the django-rest-framework-oauth version
        # of these tests.
        self.user.is_active = False
        self.user.save()

        # This is the a change we've made from the django-rest-framework-oauth version
        # of these tests.
        # Override the SCOPE_NAME_DICT setting for tests for oauth2-with-scope-test.  This is
        # needed to support READ and WRITE scopes as they currently aren't supported by the
        # edx-auth2-provider, and their scope values collide with other scopes defined in the
        # edx-auth2-provider.
        scope.SCOPE_NAME_DICT = {'read': constants.READ, 'write': constants.WRITE}
Exemple #7
0
class _DispatchingView(View):
    """
    Base class that route views to the appropriate provider view.  The default
    behavior routes based on client_id, but this can be overridden by redefining
    `select_backend()` if particular views need different behavior.
    """

    dot_adapter = adapters.DOTAdapter()

    def get_adapter(self, request):
        """
        Returns the appropriate adapter based on the OAuth client linked to the request.
        """
        client_id = self._get_client_id(request)
        monitoring_utils.set_custom_attribute('oauth_client_id', client_id)

        return self.dot_adapter

    def dispatch(self, request, *args, **kwargs):
        """
        Dispatch the request to the selected backend's view.
        """
        backend = self.select_backend(request)
        view = self.get_view_for_backend(backend)
        return view(request, *args, **kwargs)

    def select_backend(self, request):
        """
        Given a request that specifies an oauth `client_id`, return the adapter
        for the appropriate OAuth handling library.  If the client_id is found
        in a django-oauth-toolkit (DOT) Application, use the DOT adapter,
        otherwise use the django-oauth2-provider (DOP) adapter, and allow the
        calls to fail normally if the client does not exist.
        """
        return self.get_adapter(request).backend

    def get_view_for_backend(self, backend):
        """
        Return the appropriate view from the requested backend.
        """
        if backend == self.dot_adapter.backend:
            return self.dot_view.as_view()  # lint-amnesty, pylint: disable=no-member
        else:
            raise KeyError(
                'Failed to dispatch view. Invalid backend {}'.format(backend))

    def _get_client_id(self, request):
        """
        Return the client_id from the provided request
        """
        if request.method == u'GET':
            return request.GET.get('client_id')
        else:
            return request.POST.get('client_id')
Exemple #8
0
class DOTAccessTokenExchangeView(AccessTokenExchangeBase, DOTAccessTokenView):
    """
    View for token exchange from 3rd party OAuth access token to 1st party
    OAuth access token.  Uses django-oauth-toolkit (DOT) to manage access
    tokens.
    """

    oauth2_adapter = adapters.DOTAdapter()

    def get(self, request, _backend):
        return Response(status=400,
                        data={
                            'error': 'invalid_request',
                            'error_description': 'Only POST requests allowed.',
                        })

    def get_access_token(self, request, user, scope, client):
        """
        TODO: MA-2122: Reusing access tokens is not yet supported for DOT.
        Just return a new access token.
        """
        return self.create_access_token(request, user, scope, client)

    def create_access_token(self, request, user, scope, client):
        """
        Create and return a new access token.
        """
        scopes = dop_scope.to_names(scope)
        return create_dot_access_token(request, user, client, scopes=scopes)

    def access_token_response(self, token):
        """
        Wrap an access token in an appropriate response
        """
        return Response(data=token)

    def error_response(self, form_errors, **kwargs):
        """
        Return an error response consisting of the errors in the form
        """
        return Response(status=400, data=form_errors, **kwargs)
Exemple #9
0
class DOTAdapterMixin(object):
    """
    Mixin to rewire existing tests to use django-oauth-toolkit (DOT) backend

    Overwrites self.client_id, self.access_token, self.oauth2_adapter
    """

    client_id = 'dot_test_client_id'
    access_token = 'dot_test_access_token'
    oauth2_adapter = adapters.DOTAdapter()

    def create_public_client(self, user, client_id=None):
        """
        Create an oauth client application that is public.
        """
        return self.oauth2_adapter.create_public_client(
            name='Test Public Application',
            user=user,
            client_id=client_id,
            redirect_uri=DUMMY_REDIRECT_URL,
        )

    def create_confidential_client(self, user, client_id=None):
        """
        Create an oauth client application that is confidential.
        """
        return self.oauth2_adapter.create_confidential_client(
            name='Test Confidential Application',
            user=user,
            client_id=client_id,
            redirect_uri=DUMMY_REDIRECT_URL,
        )

    def get_token_response_keys(self):
        """
        Return the set of keys provided when requesting an access token
        """
        return {
            'access_token', 'refresh_token', 'token_type', 'expires_in',
            'scope'
        }