Beispiel #1
0
    def authenticate(self, request):
        """
        Returns a two-tuple of `User` and token if a valid signature has been
        supplied using JWT-based authentication.  Otherwise returns `None`.
        """
        try:
            token = self.get_token_from_request(request)
            if token is None:
                return None
        except MissingToken:
            return None

        try:
            payload = self.jwt_decode_token(token)
        except ExpiredSignature:
            msg = _('Token has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding token.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            msg = _('Invalid token.')
            raise exceptions.AuthenticationFailed(msg)

        if apps.is_installed('rest_framework_jwt.blacklist'):
            from rest_framework_jwt.blacklist.models import BlacklistedToken
            if BlacklistedToken.is_blocked(token, payload):
                msg = _('Token is blacklisted.')
                raise exceptions.PermissionDenied(msg)

        user = self.authenticate_credentials(payload)

        return user, token
Beispiel #2
0
    def validate(self, data):
        token = data['token']

        payload = check_payload(token=token)
        user = check_user(payload=payload)

        # Get and check 'orig_iat'
        orig_iat = payload.get('orig_iat')

        if orig_iat is None:
            msg = _('orig_iat field not found in token.')
            raise serializers.ValidationError(msg)

        # Verify expiration
        refresh_limit = \
            api_settings.JWT_REFRESH_EXPIRATION_DELTA.total_seconds()

        expiration_timestamp = orig_iat + refresh_limit
        now_timestamp = unix_epoch()

        if now_timestamp > expiration_timestamp:
            msg = _('Refresh has expired.')
            raise serializers.ValidationError(msg)

        new_payload = JSONWebTokenAuthentication.jwt_create_payload(user)
        new_payload['orig_iat'] = orig_iat

        return {
            'token':
            JSONWebTokenAuthentication.jwt_encode_payload(new_payload),
            'user': user,
            'issued_at': new_payload.get('iat', unix_epoch())
        }
    def authenticate(self, request):
        """
        Returns a two-tuple of `User` and token if a valid signature has been
        supplied using JWT-based authentication.  Otherwise returns `None`.
        """
        try:
            token = self.get_token_from_request(request)
        except MissingToken:
            return None

        if apps.is_installed('rest_framework_jwt.blacklist'):
            if BlacklistedToken.objects.filter(
                    token=force_str(token)).exists():
                msg = _('Token is blacklisted.')
                raise exceptions.PermissionDenied(msg)

        try:
            payload = self.jwt_decode_token(token)
        except jwt.ExpiredSignature:
            msg = _('Token has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding token.')
            raise exceptions.AuthenticationFailed(msg)

        user = self.authenticate_credentials(payload)

        return user, token
def check_user(payload):
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication

    username = JSONWebTokenAuthentication. \
        jwt_get_username_from_payload(payload)

    if not username:
        msg = _('Invalid token.')
        raise serializers.ValidationError(msg)

    if api_settings.JWT_TOKEN_ID == 'require' and not payload.get('jti'):
        msg = _('Invalid token.')
        raise serializers.ValidationError(msg)

    # Make sure user exists
    try:
        User = get_user_model()
        user = User.objects.get_by_natural_key(username)
    except User.DoesNotExist:
        msg = _("User doesn't exist.")
        raise serializers.ValidationError(msg)

    if not user.is_active:
        msg = _('User account is disabled.')
        raise serializers.ValidationError(msg)

    return user
Beispiel #5
0
class IsNotBlacklisted(BasePermission):
    message = _('You have been blacklisted.')

    def has_permission(self, request, view):
        return not BlacklistedToken.objects.filter(
            token=JSONWebTokenAuthentication.get_token_from_request(
                request)).exists()
Beispiel #6
0
    def authenticate_credentials(self, payload):
        """
        Returns an active user that matches the payload's user id.
        """
        username = self.jwt_get_username_from_payload(payload)

        if not username:
            msg = _('Invalid payload.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            user = User.objects.get(user_id=username)
        except User.DoesNotExist:
            msg = _('Invalid token.')
            raise exceptions.AuthenticationFailed(msg)

        return user
def check_payload(token):
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication

    if apps.is_installed('rest_framework_jwt.blacklist'):
        if BlacklistedToken.objects.filter(token=force_str(token)).exists():
            msg = _('Token is blacklisted.')
            raise serializers.ValidationError(msg)

    try:
        payload = JSONWebTokenAuthentication.jwt_decode_token(token)
    except jwt.ExpiredSignature:
        msg = _('Token has expired.')
        raise serializers.ValidationError(msg)
    except jwt.DecodeError:
        msg = _('Error decoding token.')
        raise serializers.ValidationError(msg)

    return payload
Beispiel #8
0
def test_view_requires_authentication(api_client):
    url = reverse("test-view")
    response = api_client.get(url)

    expected_output = {
        "detail": _("Authentication credentials were not provided.")
    }

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
Beispiel #9
0
def test_refresh_limit_expired__returns_validation_error(
        call_auth_refresh_endpoint, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload["orig_iat"] = 0  # beginning of time
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("Refresh has expired.")]}

    response = call_auth_refresh_endpoint(auth_token)
    assert response.json() == expected_output
def test_token_with_invalid_username_returns_validation_error(
    user, call_auth_verify_endpoint
):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload["username"] = "******"
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("User doesn't exist.")]}

    verify_response = call_auth_verify_endpoint(auth_token)
    assert verify_response.json() == expected_output
Beispiel #11
0
def test_refresh_with_invalid_algorithm__returns_validation_error(
        call_auth_refresh_endpoint, user):
    header = '{"alg": "bad", "typ": "JWT"}'
    token_bytes = base64.b64encode(
        header.encode('ascii')) + "..".encode('ascii')
    token = token_bytes.decode()

    expected_output = {"non_field_errors": [_("Invalid token.")]}

    refresh_response = call_auth_refresh_endpoint(token)
    assert refresh_response.json() == expected_output
Beispiel #12
0
def test_expired_token__returns_validation_error(call_auth_refresh_endpoint,
                                                 user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload["iat"] = 0
    payload["exp"] = 1
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("Token has expired.")]}

    refresh_response = call_auth_refresh_endpoint(auth_token)
    assert refresh_response.json() == expected_output
Beispiel #13
0
def test_view_returns_401_for_invalid_token(api_client):
    token = "invalid"
    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token)

    expected_output = {"detail": _("Error decoding token.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
Beispiel #14
0
def test_view_returns_401_for_corrupt_signature(api_client, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    token = JSONWebTokenAuthentication.jwt_encode_payload(payload) + "x"
    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token)

    expected_output = {"detail": _("Error decoding token.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
def test_expired_token_returns_validation_error(
    user, call_auth_verify_endpoint
):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload["iat"] = 0  # beginning of time
    payload["exp"] = 1  # one second after beginning of time
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("Token has expired.")]}

    verify_response = call_auth_verify_endpoint(auth_token)
    assert verify_response.json() == expected_output
Beispiel #16
0
def test_view_returns_401_to_authorization_header_without_token(api_client):
    api_client.credentials(HTTP_AUTHORIZATION="Bearer ")

    expected_output = {
        "detail": _("Authentication credentials were not provided.")
    }

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
def test_token_without_username_returns_validation_error(
    user, call_auth_verify_endpoint
):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload.pop("username")
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("Invalid token.")]}

    verify_response = call_auth_verify_endpoint(auth_token)

    assert verify_response.json() == expected_output
Beispiel #18
0
def test_view_returns_401_for_invalid_algorithm(api_client, user):
    header = '{"alg": "bad", "typ": "JWT"}'
    token = base64.b64encode(header.encode('ascii')) + "..".encode('ascii')

    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token.decode())

    expected_output = {"detail": _("Invalid token.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
def test_token_without_required_token_id_returns_validation_error(
    monkeypatch, user, call_auth_verify_endpoint
):
    monkeypatch.setattr(api_settings, "JWT_TOKEN_ID", "require")
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload.pop("jti")
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("Invalid token.")]}

    verify_response = call_auth_verify_endpoint(auth_token)

    assert verify_response.json() == expected_output
def check_payload(token):
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication

    try:
        payload = JSONWebTokenAuthentication.jwt_decode_token(token)
    except jwt.ExpiredSignature:
        msg = _('Token has expired.')
        raise serializers.ValidationError(msg)
    except jwt.DecodeError:
        msg = _('Error decoding token.')
        raise serializers.ValidationError(msg)
    except jwt.InvalidTokenError:
        msg = _('Invalid token.')
        raise serializers.ValidationError(msg)

    if apps.is_installed('rest_framework_jwt.blacklist'):
        from rest_framework_jwt.blacklist.models import BlacklistedToken
        if BlacklistedToken.is_blocked(token, payload):
            msg = _('Token is blacklisted.')
            raise serializers.ValidationError(msg)

    return payload
def test_token_for_inactive_user_returns_validation_error(
    create_user, call_auth_verify_endpoint
):
    inactive_user = create_user(
        username="******", password="******", is_active=False
    )
    payload = JSONWebTokenAuthentication.jwt_create_payload(inactive_user)
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {"non_field_errors": [_("User account is disabled.")]}

    verify_response = call_auth_verify_endpoint(auth_token)
    assert verify_response.json() == expected_output
Beispiel #22
0
def test_without_orig_iat_in_payload__returns_validation_error(
        call_auth_refresh_endpoint, user):
    # create token without orig_iat in payload
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    del payload["orig_iat"]
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    expected_output = {
        "non_field_errors": [_("orig_iat field not found in token.")]
    }

    response = call_auth_refresh_endpoint(auth_token)
    assert response.json() == expected_output
class IsNotBlacklisted(BasePermission):
    message = _('You have been blacklisted.')

    def has_permission(self, request, view):
        token = JSONWebTokenAuthentication.get_token_from_request(request)

        # Don't check the blacklist for requests with no token.
        if token is None:
            return True

        # The token should already be validated before we call this.
        payload = jwt_decode(token, None, verify=False)
        return not BlacklistedToken.is_blocked(token, payload)
Beispiel #24
0
    def authenticate_credentials(self, payload):
        """
        Returns an active user that matches the payload's user id and email.
        """

        username = self.jwt_get_username_from_payload(payload)

        if not username:
            msg = _('Invalid payload.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            User = get_user_model()
            user = User.objects.get_by_natural_key(username)
        except User.DoesNotExist:
            msg = _('Invalid token.')
            raise exceptions.AuthenticationFailed(msg)

        if not user.is_active:
            msg = _('User account is disabled.')
            raise exceptions.AuthenticationFailed(msg)

        return user
Beispiel #25
0
def test_view_returns_401_when_username_does_not_exist(api_client, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload["username"] = "******"
    token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token)

    expected_output = {"detail": _("Invalid token.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
Beispiel #26
0
def test_view_returns_401_for_bogus_issued_at(api_client, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    payload["iat"] = 'banana'
    token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token)

    expected_output = {"detail": _("Invalid token.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
Beispiel #27
0
def test_blacklisted_token__returns_validation_error(
        call_auth_refresh_endpoint, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    auth_token = JSONWebTokenAuthentication.jwt_encode_payload(payload)
    BlacklistedToken.objects.create(
        token=auth_token,
        user=user,
        expires_at=timezone.now() - timedelta(days=7),
    )

    expected_output = {"non_field_errors": [_("Token is blacklisted.")]}

    refresh_response = call_auth_refresh_endpoint(auth_token)
    assert refresh_response.json() == expected_output
Beispiel #28
0
def test_view_returns_401_to_deactivated_user(api_client, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    token = JSONWebTokenAuthentication.jwt_encode_payload(payload)
    user.is_active = False
    user.save()

    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token)

    expected_output = {"detail": _("User account is disabled.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
Beispiel #29
0
def test_view_returns_401_to_invalid_token_prefix(api_client, user):
    payload = JSONWebTokenAuthentication.jwt_create_payload(user)
    token = JSONWebTokenAuthentication.jwt_encode_payload(payload)

    api_client.credentials(HTTP_AUTHORIZATION="INVALID_PREFIX " + token)

    expected_output = {
        "detail": _("Authentication credentials were not provided.")
    }

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output
Beispiel #30
0
def test_view_returns_401_for_unknown_required_key_id(monkeypatch, api_client,
                                                      user):
    monkeypatch.setattr(api_settings, "JWT_INSIST_ON_KID", True)
    header = '{"alg": "HS256", "kid": "unknown-key-id", "typ": "JWT"}'
    token = base64.b64encode(header.encode('ascii')) + "..".encode('ascii')

    api_client.credentials(HTTP_AUTHORIZATION="Bearer " + token.decode())

    expected_output = {"detail": _("Error decoding token.")}

    url = reverse("test-view")
    response = api_client.get(url)

    assert response.status_code == status.HTTP_401_UNAUTHORIZED
    assert response.json() == expected_output