Exemplo n.º 1
0
    def _get_jwt_builder(self, user, is_client_restricted):
        """ Creates and returns a JWTBuilder object for creating JWTs. """

        # If JWT scope enforcement is enabled, we need to sign tokens
        # given to restricted applications with a key that
        # other IDAs do not have access to. This prevents restricted
        # applications from getting access to API endpoints available
        # on other IDAs which have not yet been protected with the
        # scope-related DRF permission classes. Once all endpoints have
        # been protected, we can enable all IDAs to use the same new
        # (asymmetric) key.
        # TODO: ARCH-162
        use_asymmetric_key = ENFORCE_JWT_SCOPES.is_enabled(
        ) and is_client_restricted
        monitoring_utils.set_custom_metric('oauth_asymmetric_jwt',
                                           use_asymmetric_key)

        log.info("Using Asymmetric JWT: %s", use_asymmetric_key)

        return JwtBuilder(
            user,
            asymmetric=use_asymmetric_key,
            secret=settings.JWT_AUTH['JWT_SECRET_KEY'],
            issuer=settings.JWT_AUTH['JWT_ISSUER'],
        )
Exemplo n.º 2
0
    def dispatch(self, request, *args, **kwargs):
        response = super(AccessTokenView, self).dispatch(request, *args, **kwargs)

        if response.status_code == 200 and request.POST.get('token_type', '').lower() == 'jwt':
            client_id = self._get_client_id(request)
            adapter = self.get_adapter(request)
            expires_in, scopes, user = self._decompose_access_token_response(adapter, response)
            issuer, secret, audience, filters, is_client_restricted = self._get_client_specific_claims(
                client_id,
                adapter
            )

            content = {
                'access_token': JwtBuilder(
                    user,
                    secret=secret,
                    issuer=issuer,
                ).build_token(
                    scopes,
                    expires_in,
                    aud=audience,
                    additional_claims={
                        'filters': filters,
                        'is_restricted': is_client_restricted,
                    },
                ),
                'expires_in': expires_in,
                'token_type': 'JWT',
                'scope': ' '.join(scopes),
            }
            response.content = json.dumps(content)

        return response
Exemplo n.º 3
0
def get_course_run(course_key, user):
    """Get a course run's data from the course catalog service.

    Arguments:
        course_key (CourseKey): Course key object identifying the run whose data we want.
        user (User): The user to authenticate as when making requests to the catalog service.

    Returns:
        dict, empty if no data could be retrieved.
    """
    catalog_integration = CatalogIntegration.current()

    if catalog_integration.enabled:
        scopes = ['email', 'profile']
        expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
        jwt = JwtBuilder(user).build_token(scopes, expires_in)
        api = EdxRestApiClient(catalog_integration.internal_api_url, jwt=jwt)

        data = get_edx_api_data(
            catalog_integration,
            user,
            'course_runs',
            resource_id=unicode(course_key),
            cache_key=catalog_integration.CACHE_KEY
            if catalog_integration.is_cache_enabled else None,
            api=api,
        )

        return data if data else {}
    else:
        return {}
Exemplo n.º 4
0
 def build_jwt_headers(self, user):
     """
     Helper function for creating headers for the JWT authentication.
     """
     token = JwtBuilder(user).build_token([])
     headers = {'HTTP_AUTHORIZATION': 'JWT ' + token}
     return headers
Exemplo n.º 5
0
    def test_tracking_context(self):
        """
        Ensure the tracking context is set up in the api client correctly and
        automatically.
        """

        # fake an E-Commerce API request.
        httpretty.register_uri(
            httpretty.POST,
            '{}/baskets/1/'.format(settings.ECOMMERCE_API_URL.strip('/')),
            status=200, body='{}',
            adding_headers={'Content-Type': JSON}
        )

        mock_tracker = mock.Mock()
        mock_tracker.resolve_context = mock.Mock(return_value={'client_id': self.TEST_CLIENT_ID, 'ip': '127.0.0.1'})
        with mock.patch('openedx.core.djangoapps.commerce.utils.tracker.get_tracker', return_value=mock_tracker):
            ecommerce_api_client(self.user).baskets(1).post()

        # Verify the JWT includes the tracking context for the user
        actual_header = httpretty.last_request().headers['Authorization']

        claims = {
            'tracking_context': {
                'lms_user_id': self.user.id,  # pylint: disable=no-member
                'lms_client_id': self.TEST_CLIENT_ID,
                'lms_ip': '127.0.0.1',
            }
        }
        expected_jwt = JwtBuilder(self.user).build_token(['email', 'profile'], additional_claims=claims)
        expected_header = 'JWT {}'.format(expected_jwt)
        self.assertEqual(actual_header, expected_header)
Exemplo n.º 6
0
    def __init__(self):
        """
        Initialize an authenticated Discovery service API client by using the
        provided user.
        """
        catalog_integration = CatalogIntegration.current()

        # Client can't be used if there is no catalog integration
        if not (catalog_integration and catalog_integration.enabled):
            LOGGER.error(
                "Unable to create DiscoveryApiClient because catalog integration not set up or enabled"
            )
            return None

        try:
            user = catalog_integration.get_service_user()
        except ObjectDoesNotExist:
            LOGGER.error("Unable to retrieve catalog integration service user")
            return None

        jwt = JwtBuilder(user).build_token([])
        base_url = configuration_helpers.get_value(
            'COURSE_CATALOG_URL_BASE', settings.COURSE_CATALOG_URL_BASE)
        self.client = EdxRestApiClient('{base_url}{journals_path}'.format(
            base_url=base_url, journals_path=JOURNALS_API_PATH),
                                       jwt=jwt)
Exemplo n.º 7
0
def get_credentials_api_client(user):
    """ Returns an authenticated Credentials API client. """

    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)
    return EdxRestApiClient(CredentialsApiConfig.current().internal_api_url, jwt=jwt)
Exemplo n.º 8
0
def get_api_client(api_config, student):
    """
    Create and configure an API client for authenticated HTTP requests.

    Args:
        api_config: CredentialsApiConfig object
        student: User object as whom to authenticate to the API

    Returns:
        EdxRestApiClient

    """
    # TODO: Use the system's JWT_AUDIENCE and JWT_SECRET_KEY instead of client ID and name.
    client_name = api_config.OAUTH2_CLIENT_NAME

    try:
        client = Client.objects.get(name=client_name)
    except Client.DoesNotExist:
        raise ImproperlyConfigured(
            'OAuth2 Client with name [{}] does not exist.'.format(client_name))

    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(student, secret=client.client_secret).build_token(
        scopes, expires_in, aud=client.client_id)

    return EdxRestApiClient(api_config.internal_api_url, jwt=jwt)
Exemplo n.º 9
0
def course_discovery_api_client(user):
    """ Returns a Course Discovery API client setup with authentication for the specified user. """
    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)

    return EdxRestApiClient(settings.COURSE_CATALOG_API_URL, jwt=jwt)
Exemplo n.º 10
0
 def _build_jwt_response_from_access_token_response(self, request,
                                                    response):
     """ Builds the content of the response, including the JWT token. """
     client_id = self._get_client_id(request)
     adapter = self.get_adapter(request)
     expires_in, scopes, user = self._decompose_access_token_response(
         adapter, response)
     issuer, secret, audience, filters, is_client_restricted = self._get_client_specific_claims(
         client_id, adapter)
     content = {
         'access_token':
         JwtBuilder(
             user,
             secret=secret,
             issuer=issuer,
         ).build_token(
             scopes,
             expires_in,
             aud=audience,
             additional_claims={
                 'filters': filters,
                 'is_restricted': is_client_restricted,
             },
         ),
         'expires_in':
         expires_in,
         'token_type':
         'JWT',
         'scope':
         ' '.join(scopes),
     }
     return json.dumps(content)
Exemplo n.º 11
0
def create_catalog_api_client(user, catalog_integration):
    """Returns an API client which can be used to make catalog API requests."""
    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)

    return EdxRestApiClient(catalog_integration.internal_api_url, jwt=jwt)
Exemplo n.º 12
0
    def test_user_profile_missing(self):
        """
        Verify that token construction succeeds if the UserProfile is missing.
        """
        self.profile.delete()

        token = JwtBuilder(self.user).build_token(expires_in=self.expires_in)
        self.assert_valid_jwt_access_token(token, self.user, self.scopes)
Exemplo n.º 13
0
 def __init__(self, user):
     """
     Initialize an authenticated Enterprise service API client by using the
     provided user.
     """
     jwt = JwtBuilder(user).build_token([])
     self.client = EdxRestApiClient(configuration_helpers.get_value(
         'ENTERPRISE_API_URL', settings.ENTERPRISE_API_URL),
                                    jwt=jwt)
Exemplo n.º 14
0
    def test_user_profile_missing(self):
        """
        Verify that token construction succeeds if the UserProfile is missing.
        """
        self.profile.delete()  # pylint: disable=no-member

        scopes = ['profile']
        token = JwtBuilder(self.user).build_token(scopes, self.expires_in)
        self.assert_valid_jwt_access_token(token, self.user, scopes)
Exemplo n.º 15
0
 def test_jwt_auth(self):
     """ verify the endpoints JWT authentication. """
     scopes = ['email', 'profile']
     expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
     token = JwtBuilder(self.user).build_token(scopes, expires_in)
     headers = {'HTTP_AUTHORIZATION': 'JWT ' + token}
     self.client.logout()
     response = self.client.get(self.path, **headers)
     self.assertEqual(response.status_code, 200)
def ecommerce_api_client(user, session=None, token_expiration=None):
    """ Returns an E-Commerce API client setup with authentication for the specified user. """
    claims = {'tracking_context': create_tracking_context(user)}
    jwt = JwtBuilder(user).build_token(['email', 'profile'], expires_in=token_expiration, additional_claims=claims)

    return EdxRestApiClient(
        configuration_helpers.get_value('ECOMMERCE_API_URL', settings.ECOMMERCE_API_URL),
        jwt=jwt,
        session=session
    )
Exemplo n.º 17
0
 def __init__(self):
     """
     Initialize an Enterprise service API client, authenticated using the Enterprise worker username.
     """
     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)
Exemplo n.º 18
0
    def test_override_secret_and_audience(self):
        """
        Verify that the signing key and audience can be overridden.
        """
        secret = 'avoid-this'
        audience = 'avoid-this-too'
        scopes = []

        token = JwtBuilder(self.user, secret=secret).build_token(scopes, self.expires_in, aud=audience)

        jwt.decode(token, secret, audience=audience)
Exemplo n.º 19
0
def create_video_pipeline_api_client(user, api_url):
    """
    Returns an API client which can be used to make Video Pipeline API requests.

    Arguments:
        user(User): A requesting user.
        api_url(unicode): It is video pipeline's API URL.
    """
    jwt_token = JwtBuilder(user).build_token(
        scopes=[], expires_in=settings.OAUTH_ID_TOKEN_EXPIRATION)
    return EdxRestApiClient(api_url, jwt=jwt_token)
Exemplo n.º 20
0
def create_catalog_api_client(user, site=None):
    """Returns an API client which can be used to make Catalog API requests."""
    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)

    if site:
        url = site.configuration.get_value('COURSE_CATALOG_API_URL')
    else:
        url = CatalogIntegration.current().get_internal_api_url()

    return EdxRestApiClient(url, jwt=jwt)
Exemplo n.º 21
0
 def __init__(self, user):
     """
     Initialize an authenticated Consent service API client by using the
     provided user.
     """
     jwt = JwtBuilder(user).build_token([])
     url = configuration_helpers.get_value('ENTERPRISE_CONSENT_API_URL', settings.ENTERPRISE_CONSENT_API_URL)
     self.client = EdxRestApiClient(
         url,
         jwt=jwt,
         append_slash=False,
     )
     self.consent_endpoint = self.client.data_sharing_consent
Exemplo n.º 22
0
 def __init__(self):
     """
     Initialize a consent service API client, authenticated using the Enterprise worker username.
     """
     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,
         jwt=jwt,
         append_slash=False,
     )
     self.consent_endpoint = self.client.data_sharing_consent
Exemplo n.º 23
0
def course_discovery_api_client(user):
    """
    Return a Course Discovery API client setup with authentication for the specified user.
    """
    if JwtBuilder is None:
        raise NotConnectedToOpenEdX(
            _("To get a Catalog API client, this package must be "
              "installed in an Open edX environment."))

    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)
    return EdxRestApiClient(settings.COURSE_CATALOG_API_URL, jwt=jwt)
Exemplo n.º 24
0
    def dispatch(self, request, *args, **kwargs):
        response = super(AccessTokenView, self).dispatch(request, *args, **kwargs)

        if response.status_code == 200 and request.POST.get('token_type', '').lower() == 'jwt':
            expires_in, scopes, user = self._decompose_access_token_response(request, response)

            content = {
                'access_token': JwtBuilder(user).build_token(scopes, expires_in),
                'expires_in': expires_in,
                'token_type': 'JWT',
                'scope': ' '.join(scopes),
            }
            response.content = json.dumps(content)

        return response
Exemplo n.º 25
0
def get_api_client(api_config, user):
    """
    Create and configure an API client for authenticated HTTP requests.

    Args:
        api_config: CredentialsApiConfig object
        user: User object as whom to authenticate to the API

    Returns:
        EdxRestApiClient

    """
    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)
    return EdxRestApiClient(api_config.internal_api_url, jwt=jwt)
Exemplo n.º 26
0
    def __init__(self):
        """
        Initialize an authenticated Journals service API client by using the
        provided user.
        """
        try:
            self.user = self.get_journals_worker()
        except ObjectDoesNotExist:
            error = 'Unable to retrieve {} service user'.format(
                JOURNAL_WORKER_USERNAME)
            LOGGER.error(error)
            raise ValueError(error)

        jwt = JwtBuilder(self.user).build_token(['email', 'profile'], 16000)
        self.client = EdxRestApiClient(configuration_helpers.get_value(
            'JOURNALS_API_URL', settings.JOURNALS_API_URL),
                                       jwt=jwt)
Exemplo n.º 27
0
def get_edxnotes_id_token(user):
    """
    Returns generated ID Token for edxnotes.
    """
    # TODO: Use the system's JWT_AUDIENCE and JWT_SECRET_KEY instead of client ID and name.
    try:
        client = Client.objects.get(name=CLIENT_NAME)
    except Client.DoesNotExist:
        raise ImproperlyConfigured(
            'OAuth2 Client with name [{}] does not exist.'.format(CLIENT_NAME))

    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user, secret=client.client_secret).build_token(
        scopes, expires_in, aud=client.client_id)

    return jwt
Exemplo n.º 28
0
    def connect(self):
        """
        Connect to the REST API, authenticating with a JWT for the current user.
        """
        if JwtBuilder is None:
            raise NotConnectedToOpenEdX(
                "This package must be installed in an OpenEdX environment.")

        now = int(time())
        scopes = ['profile', 'email']
        jwt = JwtBuilder(self.user).build_token(scopes, self.expires_in)
        self.client = EdxRestApiClient(
            self.API_BASE_URL,
            append_slash=self.APPEND_SLASH,
            jwt=jwt,
        )
        self.expires_at = now + self.expires_in
Exemplo n.º 29
0
    def _get_jwt_builder(self, user, is_client_restricted):
        """ Creates and returns a JWTBuilder object for creating JWTs. """

        # If JWT scope enforcement is enabled, we need to sign tokens
        # given to restricted applications with a key that
        # other IDAs do not have access to. This prevents restricted
        # applications from getting access to API endpoints available
        # on other IDAs which have not yet been protected with the
        # scope-related DRF permission classes. Once all endpoints have
        # been protected, we can enable all IDAs to use the same new
        # (asymmetric) key.
        # TODO: ARCH-162
        use_asymmetric_key = ENFORCE_JWT_SCOPES.is_enabled(
        ) and is_client_restricted
        return JwtBuilder(
            user,
            asymmetric=use_asymmetric_key,
        )
Exemplo n.º 30
0
def get_credentials_api_client(user, org=None):
    """
    Returns an authenticated Credentials API client.

    Arguments:
        user (User): The user to authenticate as when requesting credentials.
        org (str): Optional organization to look up the site config for, rather than the current request

    """

    scopes = ['email', 'profile']
    expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
    jwt = JwtBuilder(user).build_token(scopes, expires_in)

    if org is None:
        url = CredentialsApiConfig.current().internal_api_url  # by current request
    else:
        url = CredentialsApiConfig.get_internal_api_url_for_org(org)  # by org
    return EdxRestApiClient(url, jwt=jwt)