Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for Django 5 and Moves to Github Actions for core CI/CD #615

Merged
merged 7 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions .circleci/config.yml

This file was deleted.

5 changes: 5 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[flake8]
per-file-ignores =
dj_rest_auth/tests/test_serializers.py:E501,F401
dj_rest_auth/serializers.py:E501
dj_rest_auth/jwt_auth.py:E501
91 changes: 83 additions & 8 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,89 @@
name: Release to PyPi
on: [push]
name: Lint, Build and Test
on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
lint:
runs-on: ubuntu-latest
name: Lint
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.8
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8
- name: Lint
run: flake8 dj_rest_auth/ --append-config ./.flake8
build:
name: Publish
runs-on: ubuntu-latest
name: Build
needs: [lint]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.8
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- name: Build
run: python3 setup.py sdist
- name: Store artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
test:
runs-on: ubuntu-20.04
name: Test Python ${{ matrix.python-version }} + Django ~= ${{ matrix.django-version }}
needs: [build]
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
django-version: ['3.2', '4.2', '5.0']
exclude:
- python-version: '3.8'
django-version: '5.0'
- python-version: '3.9'
django-version: '5.0'
steps:
- name: Publish package
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@master
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -r dj_rest_auth/tests/requirements.pip
pip install "Django~=${{ matrix.django-version }}.0"
- name: Run Tests
run: |
echo "$(python --version) / Django $(django-admin --version)"
coverage run ./runtests.py
- name: Generate Coverage Report
run: |
mkdir -p test-results/
coverage report
coverage xml
- name: Code Coverage Summary Report
uses: irongut/[email protected]
with:
filename: coverage.xml
- name: Store test results
uses: actions/upload-artifact@v4
with:
user: __token__
password: ${{ secrets.pypi_password }}
name: results-${{ matrix.python-version }}-${{ matrix.django-version }}
path: test-results/
28 changes: 0 additions & 28 deletions .github/workflows/stale.yml

This file was deleted.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Dj-Rest-Auth
[![<iMerica>](https://circleci.com/gh/iMerica/dj-rest-auth.svg?style=svg)](https://app.circleci.com/pipelines/github/iMerica/dj-rest-auth)
[![<iMerica>](https://github.com/iMerica/dj-rest-auth/actions/workflows/main.yml/badge.svg)](https://github.com/iMerica/dj-rest-auth/actions/workflows/main.yml/)


Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well
with SPAs (e.g., React, Vue, Angular), and Mobile applications.

## Requirements
- Django 2, 3, or 4 (See Unit Test Coverage in CI)
- Python 3
- Django 3, 4 and 5 (See Unit Test Coverage in CI)
- Python >= 3.8

## Quick Setup

Expand Down
2 changes: 1 addition & 1 deletion dj_rest_auth/__version__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__title__ = 'dj-rest-auth'
__description__ = 'Authentication and Registration in Django Rest Framework.'
__url__ = 'http://github.com/iMerica/dj-rest-auth'
__version__ = '5.1.0'
__version__ = '6.0.0'
__author__ = '@iMerica https://github.com/iMerica'
__author_email__ = '[email protected]'
__license__ = 'MIT'
Expand Down
4 changes: 2 additions & 2 deletions dj_rest_auth/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
'JWT_AUTH_SECURE': False,
'JWT_AUTH_HTTPONLY': True,
'JWT_AUTH_SAMESITE': 'Lax',
'JWT_AUTH_COOKIE_DOMAIN' : None,
'JWT_AUTH_COOKIE_DOMAIN': None,
'JWT_AUTH_RETURN_EXPIRATION': False,
'JWT_AUTH_COOKIE_USE_CSRF': False,
'JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED': False,
Expand All @@ -59,7 +59,7 @@
)

# List of settings that have been removed
REMOVED_SETTINGS = ( )
REMOVED_SETTINGS = []


class APISettings(_APISettings): # pragma: no cover
Expand Down
3 changes: 1 addition & 2 deletions dj_rest_auth/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ def save(self, request, **kwargs):
'uid': uid,
}
if (
allauth_account_settings.AUTHENTICATION_METHOD
!= allauth_account_settings.AuthenticationMethod.EMAIL
allauth_account_settings.AUTHENTICATION_METHOD != allauth_account_settings.AuthenticationMethod.EMAIL
):
context['username'] = user_username(user)
get_adapter(request).send_mail(
Expand Down
3 changes: 1 addition & 2 deletions dj_rest_auth/jwt_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def set_jwt_access_cookie(response, access_token):
cookie_samesite = api_settings.JWT_AUTH_SAMESITE
cookie_domain = api_settings.JWT_AUTH_COOKIE_DOMAIN


if cookie_name:
response.set_cookie(
cookie_name,
Expand Down Expand Up @@ -139,7 +138,7 @@ def authenticate(self, request):
if header is None:
if cookie_name:
raw_token = request.COOKIES.get(cookie_name)
if api_settings.JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED: #True at your own risk
if api_settings.JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED: # True at your own risk
self.enforce_csrf(request)
elif raw_token is not None and api_settings.JWT_AUTH_COOKIE_USE_CSRF:
self.enforce_csrf(request)
Expand Down
5 changes: 3 additions & 2 deletions dj_rest_auth/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from .app_settings import api_settings


def get_token_model():
token_model = api_settings.TOKEN_MODEL
session_login = api_settings.SESSION_LOGIN
Expand All @@ -15,13 +16,13 @@ def get_token_model():
'more of `TOKEN_MODEL`, `USE_JWT` or `SESSION_LOGIN`'
)
if (
token_model == DefaultTokenModel
and 'rest_framework.authtoken' not in settings.INSTALLED_APPS
token_model == DefaultTokenModel and 'rest_framework.authtoken' not in settings.INSTALLED_APPS
):
raise ImproperlyConfigured(
'You must include `rest_framework.authtoken` in INSTALLED_APPS '
'or set TOKEN_MODEL to None'
)
return token_model


TokenModel = get_token_model()
3 changes: 1 addition & 2 deletions dj_rest_auth/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ def validate_auth_user_status(user):
def validate_email_verification_status(user, email=None):
from allauth.account import app_settings as allauth_account_settings
if (
allauth_account_settings.EMAIL_VERIFICATION == allauth_account_settings.EmailVerificationMethod.MANDATORY
and not user.emailaddress_set.filter(email=user.email, verified=True).exists()
allauth_account_settings.EMAIL_VERIFICATION == allauth_account_settings.EmailVerificationMethod.MANDATORY and not user.emailaddress_set.filter(email=user.email, verified=True).exists()
):
raise serializers.ValidationError(_('E-mail is not verified.'))

Expand Down
3 changes: 1 addition & 2 deletions dj_rest_auth/tests/requirements.pip
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
coveralls==1.11.1
django-allauth==0.61.1
django>=2.2,<5.0
djangorestframework-simplejwt==4.6.0
djangorestframework-simplejwt>=5.3.1
flake8==3.8.4
responses==0.12.1
unittest-xml-reporting==3.0.4
19 changes: 9 additions & 10 deletions dj_rest_auth/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ def test_registration_allowed_with_custom_no_password_serializer(self):
self.assertEqual(new_user.username, payload['username'])
self.assertFalse(new_user.has_usable_password())

## Also check that regular registration also works
# Also check that regular registration also works
user_count = get_user_model().objects.all().count()

# test empty payload
Expand All @@ -514,7 +514,6 @@ def test_registration_allowed_with_custom_no_password_serializer(self):
new_user = get_user_model().objects.latest('id')
self.assertEqual(new_user.username, self.REGISTRATION_DATA['username'])


@override_api_settings(USE_JWT=True)
def test_registration_with_jwt(self):
user_count = get_user_model().objects.all().count()
Expand Down Expand Up @@ -837,15 +836,15 @@ def test_wo_csrf_enforcement(self):
self.assertTrue('jwt-auth' in list(client.cookies.keys()))
self.assertEquals(resp.status_code, 200)

## TEST WITH JWT AUTH HEADER
# TEST WITH JWT AUTH HEADER
jwtclient = APIClient(enforce_csrf_checks=True)
token = resp.data['access']
resp = jwtclient.get('/protected-view/', HTTP_AUTHORIZATION='Bearer ' + token)
self.assertEquals(resp.status_code, 200)
resp = jwtclient.post('/protected-view/', {}, HTTP_AUTHORIZATION='Bearer ' + token)
self.assertEquals(resp.status_code, 200)

## TEST WITH COOKIES
# TEST WITH COOKIES
resp = client.get('/protected-view/')
self.assertEquals(resp.status_code, 200)

Expand Down Expand Up @@ -883,7 +882,7 @@ def test_csrf_wo_login_csrf_enforcement(self):
self.assertTrue('csrftoken' in list(client.cookies.keys()))
self.assertEquals(resp.status_code, 200)

## TEST WITH JWT AUTH HEADER
# TEST WITH JWT AUTH HEADER
jwtclient = APIClient(enforce_csrf_checks=True)
token = resp.data['access']
resp = jwtclient.get('/protected-view/')
Expand All @@ -909,7 +908,7 @@ def test_csrf_wo_login_csrf_enforcement(self):
@override_api_settings(USE_JWT=True)
@override_api_settings(JWT_AUTH_COOKIE='jwt-auth')
@override_api_settings(JWT_AUTH_COOKIE_USE_CSRF=True)
@override_api_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=True) # True at your own risk
@override_api_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=True) # True at your own risk
@override_settings(
REST_FRAMEWORK=dict(
DEFAULT_AUTHENTICATION_CLASSES=[
Expand Down Expand Up @@ -942,9 +941,9 @@ def test_csrf_w_login_csrf_enforcement(self):
self.assertTrue('csrftoken' in list(client.cookies.keys()))
self.assertEquals(resp.status_code, 200)

## TEST WITH JWT AUTH HEADER does not make sense
# TEST WITH JWT AUTH HEADER does not make sense

## TEST WITH COOKIES
# TEST WITH COOKIES
resp = client.get('/protected-view/')
self.assertEquals(resp.status_code, 200)
# fail w/o csrftoken in payload
Expand All @@ -958,7 +957,7 @@ def test_csrf_w_login_csrf_enforcement(self):
@override_api_settings(USE_JWT=True)
@override_api_settings(JWT_AUTH_COOKIE='jwt-auth')
@override_api_settings(JWT_AUTH_COOKIE_USE_CSRF=False)
@override_api_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=True) # True at your own risk
@override_api_settings(JWT_AUTH_COOKIE_ENFORCE_CSRF_ON_UNAUTHENTICATED=True) # True at your own risk
@override_settings(
REST_FRAMEWORK=dict(
DEFAULT_AUTHENTICATION_CLASSES=[
Expand Down Expand Up @@ -1064,7 +1063,7 @@ def test_custom_token_refresh_view(self):
# Ensure access keys are provided in response
self.assertIn('access', refresh_resp.data)
self.assertIn('access_expiration', refresh_resp.data)

@override_api_settings(JWT_AUTH_RETURN_EXPIRATION=True)
@override_api_settings(USE_JWT=True)
@override_api_settings(JWT_AUTH_COOKIE='xxx')
Expand Down
2 changes: 1 addition & 1 deletion dj_rest_auth/tests/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from allauth.socialaccount.providers.facebook.views import FacebookProvider
from allauth.socialaccount.models import SocialApp
from allauth.exceptions import ImmediateHttpResponse
from allauth.core.exceptions import ImmediateHttpResponse
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.core.exceptions import ValidationError
Expand Down
1 change: 0 additions & 1 deletion dj_rest_auth/tests/test_social.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import responses
from allauth.socialaccount.models import SocialApp
from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.test import TestCase
Expand Down
Loading