def _set_request_auth_type_guess_attribute(self, request): """ Add custom attribute 'request_auth_type_guess' for the authentication type used. NOTE: This is a best guess at this point. Possible values include: no-user unauthenticated jwt/bearer/other-token-type jwt-cookie session-or-other (catch all) """ if not hasattr(request, 'user') or not request.user: auth_type = 'no-user' elif not request.user.is_authenticated: auth_type = 'unauthenticated' elif 'HTTP_AUTHORIZATION' in request.META and request.META[ 'HTTP_AUTHORIZATION']: token_parts = request.META['HTTP_AUTHORIZATION'].split() # Example: "JWT eyJhbGciO..." if len(token_parts) == 2: auth_type = token_parts[0].lower( ) # 'jwt' or 'bearer' (for example) else: auth_type = 'other-token-type' elif USE_JWT_COOKIE_HEADER in request.META and jwt_cookie_name( ) in request.COOKIES: auth_type = 'jwt-cookie' else: auth_type = 'session-or-other' monitoring.set_custom_attribute('request_auth_type_guess', auth_type)
def test_success(self, mock_set_custom_metric): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.request.COOKIES[jwt_cookie_header_payload_name()] = 'header.payload' self.request.COOKIES[jwt_cookie_signature_name()] = 'signature' self.middleware.process_request(self.request) self.assertEqual(self.request.COOKIES[jwt_cookie_name()], 'header.payload.signature') mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'success')
def set_jwt_cookie(client, user, role_context_pairs=None): """ Set jwt token in cookies """ jwt_token = _jwt_token_from_role_context_pairs(user, role_context_pairs or []) client.cookies[jwt_cookie_name()] = jwt_token
def process_request(self, request): """ Reconstitute the full JWT and add a new cookie on the request object. """ use_jwt_cookie_requested = request.META.get(USE_JWT_COOKIE_HEADER) header_payload_cookie = request.COOKIES.get(jwt_cookie_header_payload_name()) signature_cookie = request.COOKIES.get(jwt_cookie_signature_name()) if not use_jwt_cookie_requested: metric_value = 'not-requested' elif header_payload_cookie and signature_cookie: # Reconstitute JWT auth cookie if split cookies are available and jwt cookie # authentication was requested by the client. request.COOKIES[jwt_cookie_name()] = '{}{}{}'.format( header_payload_cookie, JWT_DELIMITER, signature_cookie, ) metric_value = 'success' elif header_payload_cookie or signature_cookie: # Log unexpected case of only finding one cookie. if not header_payload_cookie: log_message, metric_value = self._get_missing_cookie_message_and_metric( jwt_cookie_header_payload_name() ) if not signature_cookie: log_message, metric_value = self._get_missing_cookie_message_and_metric( jwt_cookie_signature_name() ) log.warning(log_message) else: metric_value = 'missing-both' monitoring.set_custom_metric('request_jwt_cookie', metric_value)
def test_success(self, mock_set_custom_attribute): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.request.COOKIES[jwt_cookie_header_payload_name()] = 'header.payload' self.request.COOKIES[jwt_cookie_signature_name()] = 'signature' self.middleware.process_view(self.request, None, None, None) self.assertEqual(self.request.COOKIES[jwt_cookie_name()], 'header.payload.signature') mock_set_custom_attribute.assert_called_once_with('request_jwt_cookie', 'success')
def process_request(self, request): """ Reconstitute the full JWT and add a new cookie on the request object. """ use_jwt_cookie_requested = request.META.get(USE_JWT_COOKIE_HEADER) header_payload_cookie = request.COOKIES.get(jwt_cookie_header_payload_name()) signature_cookie = request.COOKIES.get(jwt_cookie_signature_name()) if not use_jwt_cookie_requested: metric_value = 'not-requested' elif header_payload_cookie and signature_cookie: # Reconstitute JWT auth cookie if split cookies are available and jwt cookie # authentication was requested by the client. request.COOKIES[jwt_cookie_name()] = '{}{}{}'.format( header_payload_cookie, JWT_DELIMITER, signature_cookie, ) metric_value = 'success' elif header_payload_cookie or signature_cookie: # Log unexpected case of only finding one cookie. if not header_payload_cookie: log_message, metric_value = self._get_missing_cookie_message_and_metric( jwt_cookie_header_payload_name() ) if not signature_cookie: log_message, metric_value = self._get_missing_cookie_message_and_metric( jwt_cookie_signature_name() ) log.warning(log_message) else: metric_value = 'missing-both' monitoring.set_custom_metric('request_jwt_cookie', metric_value)
def test_request_auth_type_guess_jwt_cookie_attribute( self, mock_set_custom_attribute): self.request.user = UserFactory() self.request.META[USE_JWT_COOKIE_HEADER] = True self.request.COOKIES[jwt_cookie_name()] = 'reconstituted-jwt-cookie' self.middleware.process_response(self.request, None) mock_set_custom_attribute.assert_any_call('request_auth_type_guess', 'jwt-cookie')
def test_missing_cookies(self, set_cookie_name, missing_cookie_name, mock_set_custom_metric, mock_log): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.request.COOKIES[set_cookie_name] = 'test' self.middleware.process_request(self.request) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_log.warning.assert_called_once_with( '%s cookie is missing. JWT auth cookies will not be reconstituted.' % missing_cookie_name) mock_set_custom_metric.assert_called_once_with( 'request_jwt_cookie', 'missing-{}'.format(missing_cookie_name))
def test_missing_cookies( self, set_cookie_name, missing_cookie_name, mock_set_custom_metric, mock_log ): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.request.COOKIES[set_cookie_name] = 'test' self.middleware.process_request(self.request) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_log.warning.assert_called_once_with( '%s cookie is missing. JWT auth cookies will not be reconstituted.' % missing_cookie_name ) mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'missing-{}'.format(missing_cookie_name))
def authenticate(self, request): if request.COOKIES.get(jwt_cookie_name(), None) != 'header.payload.signature': return None # authenticate was failing on POST calls because it previously wasn't passing the # supported parsers into the new Request object. This retrieval of POST data # simulates the CSRF POST data checks in the non-test authenticate method. This # line lets us verify that the parsers are being correctly passed to the request request.POST.get('csrfmiddlewaretoken', '') user = UserFactory() return (user, None)
def get_decoded_jwt_from_request(request): """ Grab jwt from request if possible. Returns a decoded jwt dict if it finds it. Returns a None if it does not. """ jwt_cookie = request.COOKIES.get(jwt_cookie_name(), None) or getattr( request, 'auth', None) if not jwt_cookie: return None return jwt_decode_handler(jwt_cookie)
def set_jwt_cookie(self, system_wide_role='admin', context='some_context'): """ Set jwt token in cookies """ role_data = '{system_wide_role}'.format( system_wide_role=system_wide_role) if context is not None: role_data += ':{context}'.format(context=context) payload = generate_unversioned_payload(self.user) payload.update({'roles': [role_data]}) jwt_token = generate_jwt_token(payload) self.client.cookies[jwt_cookie_name()] = jwt_token
def process_view(self, request, view_func, view_args, view_kwargs): # pylint: disable=unused-argument """ Reconstitute the full JWT and add a new cookie on the request object. """ assert hasattr( request, 'session' ), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'." # noqa E501 line too long use_jwt_cookie_requested = request.META.get(USE_JWT_COOKIE_HEADER) header_payload_cookie = request.COOKIES.get( jwt_cookie_header_payload_name()) signature_cookie = request.COOKIES.get(jwt_cookie_signature_name()) is_set_request_user_for_jwt_cookie_enabled = get_setting( ENABLE_SET_REQUEST_USER_FOR_JWT_COOKIE) if use_jwt_cookie_requested and is_set_request_user_for_jwt_cookie_enabled: # DRF does not set request.user until process_response. This makes it available in process_view. # For more info, see https://github.com/jpadilla/django-rest-framework-jwt/issues/45#issuecomment-74996698 request.user = SimpleLazyObject( lambda: _get_user_from_jwt(request, view_func)) if not use_jwt_cookie_requested: metric_value = 'not-requested' elif header_payload_cookie and signature_cookie: # Reconstitute JWT auth cookie if split cookies are available and jwt cookie # authentication was requested by the client. request.COOKIES[jwt_cookie_name()] = '{}{}{}'.format( header_payload_cookie, JWT_DELIMITER, signature_cookie, ) metric_value = 'success' elif header_payload_cookie or signature_cookie: # Log unexpected case of only finding one cookie. if not header_payload_cookie: log_message, metric_value = self._get_missing_cookie_message_and_metric( jwt_cookie_header_payload_name()) if not signature_cookie: log_message, metric_value = self._get_missing_cookie_message_and_metric( jwt_cookie_signature_name()) log.warning(log_message) else: metric_value = 'missing-both' log.warning( 'Both JWT auth cookies missing. JWT auth cookies will not be reconstituted.' ) monitoring.set_custom_metric('request_jwt_cookie', metric_value)
def get_request_with_jwt_cookie(self, system_wide_role=None, context=None): """ Set jwt token in cookies. """ payload = generate_unversioned_payload(self.user) if system_wide_role: payload.update({ 'roles': [ '{system_wide_role}:{context}'.format(system_wide_role=system_wide_role, context=context) ] }) jwt_token = generate_jwt_token(payload) request = RequestFactory().get('/') request.COOKIES[jwt_cookie_name()] = jwt_token return request
def test_get_decoded_jwt_from_request(self, mock_decoder): """ A decoded jwt should be returned from request if it exists """ payload = generate_unversioned_payload(self.request.user) payload.update({ "roles": [ "some_new_role_name:some_context" ] }) jwt_token = generate_jwt_token(payload) self.request.COOKIES[jwt_cookie_name()] = jwt_token get_decoded_jwt_from_request(self.request) mock_decoder.assert_called_once()
def test_jwt_authentication(self): """Test that requests made without a valid JWT fail.""" # Remove jwt cookie self.client.cookies[jwt_cookie_name()] = {} # Verify that the basket creation endpoint requires JWT authentication response = self.create_basket(skus=[self.PAID_SKU], auth=False) self.assertEqual(response.status_code, 401) # Verify that the basket creation endpoint requires valid user data in the JWT payload token = self.generate_token({}) response = self.create_basket(skus=[self.PAID_SKU], token=token) self.assertEqual(response.status_code, 401) # Verify that the basket creation endpoint requires user data to be signed with a valid secret; # guarantee an invalid secret by truncating the valid secret invalid_secret = self.JWT_SECRET_KEY[:-1] payload = { 'username': self.user.username, 'email': self.user.email, } token = self.generate_token(payload, secret=invalid_secret) response = self.create_basket(skus=[self.PAID_SKU], token=token) self.assertEqual(response.status_code, 401)
def _set_encoded_jwt_in_cookies(client, payload): """ JWT-encodes the given payload and sets it in the client's cookies. """ client.cookies[jwt_cookie_name()] = generate_jwt_token(payload)
def test_do_not_use_jwt_cookies(self, mock_set_custom_attribute): self.middleware.process_view(self.request, None, None, None) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_set_custom_attribute.assert_called_once_with('request_jwt_cookie', 'not-requested')
def authenticate(self, request): if request.COOKIES.get(jwt_cookie_name(), None) != 'header.payload.signature': return None user = UserFactory() return (user, None)
def test_no_cookies(self, mock_set_custom_metric): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.middleware.process_request(self.request) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'missing-both')
def test_do_not_use_jwt_cookies(self, mock_set_custom_metric): self.middleware.process_request(self.request) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'not-requested')
def test_no_cookies(self, mock_set_custom_metric): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.middleware.process_request(self.request) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'missing-both')
def test_do_not_use_jwt_cookies(self, mock_set_custom_metric): self.middleware.process_request(self.request) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'not-requested')