Skip to content

Commit

Permalink
feat(testing): add test example with test user
Browse files Browse the repository at this point in the history
  • Loading branch information
omercnet committed Dec 13, 2023
1 parent 4e92012 commit c0506ca
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 21 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ jobs:
tox -v
env:
DJANGO: ${{ matrix.django-version }}
DESCOPE_PROJECT_ID: P2ZRsmAQw8MKG78knGZ9GXWRqxM5
DESCOPE_MANAGEMENT_KEY: ${{ secrets.DESCOPE_MANAGEMENT_KEY }}
23 changes: 15 additions & 8 deletions django_descope/authentication.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from typing import Any, Union

from descope import REFRESH_SESSION_COOKIE_NAME, SESSION_COOKIE_NAME, SESSION_TOKEN_NAME
from descope.exceptions import AuthException
Expand All @@ -13,13 +14,21 @@
logger = logging.getLogger(__name__)


def add_tokens_to_request(session: Any, session_token: str, refresh_token: str):
session[SESSION_COOKIE_NAME] = session_token
session[REFRESH_SESSION_COOKIE_NAME] = refresh_token
session.save()


class DescopeAuthentication(BaseBackend):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def authenticate(self, request: HttpRequest):
session_token = request.session.get(SESSION_COOKIE_NAME)
refresh_token = request.session.get(REFRESH_SESSION_COOKIE_NAME)
def authenticate(self, request: Union[HttpRequest, None], **kwargs):
if request is None:
return None
session_token = request.session.get(SESSION_COOKIE_NAME, "")
refresh_token = request.session.get(REFRESH_SESSION_COOKIE_NAME, "")

logger.debug("Validating (and refreshing) Descope session")
try:
Expand All @@ -42,13 +51,11 @@ def authenticate(self, request: HttpRequest):
if settings.DEBUG:
# Contains sensitive information, so only log in DEBUG mode
logger.debug(validated_session)
return self.get_user(request, validated_session, refresh_token)

def get_user(self, request: HttpRequest, validated_session, refresh_token):
if validated_session:
username = validated_session[SESSION_TOKEN_NAME]["sub"]
user, created = DescopeUser.objects.get_or_create(username=username)
user, _ = DescopeUser.objects.get_or_create(username=username)
user.sync(validated_session, refresh_token)
request.session[SESSION_COOKIE_NAME] = user.session_token["jwt"]
return user
return None
else:
return None
7 changes: 4 additions & 3 deletions django_descope/middleware.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import logging

from django.contrib.auth import login
from django.http import HttpRequest, HttpResponse
from django.http import HttpRequest
from django.utils.deprecation import MiddlewareMixin

from .authentication import DescopeAuthentication

logger = logging.getLogger(__name__)


class DescopeMiddleware:
class DescopeMiddleware(MiddlewareMixin):
_auth = DescopeAuthentication()

def __init__(self, get_response: HttpResponse = None):
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request: HttpRequest):
Expand Down
6 changes: 3 additions & 3 deletions django_descope/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from django.views import View
from django.views.decorators.cache import never_cache

# User = get_user_model()
from .authentication import add_tokens_to_request

logger = logging.getLogger(__name__)


Expand All @@ -19,8 +20,7 @@ def post(self, request: HttpRequest):
refresh = request.POST.get(REFRESH_SESSION_COOKIE_NAME)

if session and refresh:
request.session[SESSION_COOKIE_NAME] = session
request.session[REFRESH_SESSION_COOKIE_NAME] = refresh
add_tokens_to_request(request, session, refresh)
return JsonResponse({"success": True})

return HttpResponseBadRequest()
Empty file added example_app/__init__.py
Empty file.
61 changes: 61 additions & 0 deletions example_app/test_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import json
import logging
import random
import string

import descope
from descope import REFRESH_SESSION_TOKEN_NAME, SESSION_TOKEN_NAME
from django.test import TestCase

from django_descope import descope_client
from django_descope.authentication import add_tokens_to_request

logger = logging.getLogger(__name__)


def random_string(N: int) -> str:
return "".join(random.choices(string.ascii_lowercase + string.digits, k=N))


class AdminLoginTestCase(TestCase):
delivery_method = descope.DeliveryMethod.EMAIL
login_id = f"test+{random_string(8)}@test.internal"
token: dict

def setUp(self) -> None:
descope_client.mgmt.user.create_test_user(
self.login_id, role_names=["is_staff", "is_superuser"], verified_email=True
)
resp = descope_client.mgmt.user.generate_otp_for_test_user(
self.delivery_method,
self.login_id,
)
self.token = descope_client.otp.verify_code(
self.delivery_method, self.login_id, resp.get("code")
)

session = self.client.session
add_tokens_to_request(
session,
self.token[SESSION_TOKEN_NAME]["jwt"],
self.token[REFRESH_SESSION_TOKEN_NAME]["jwt"],
)

def test_test_user_can_login_to_admin(self):
"""Test that if user has the right roles they can login to admin"""

res = self.client.get("/debug")
self.assertEqual(res.status_code, 200)

debug = json.loads(res.content)
self.assertEqual(debug["user"], self.token["userId"])
self.assertEqual(debug["email"], self.login_id)
self.assertTrue(debug["is_authenticated"])
self.assertTrue(debug["is_staff"])
self.assertTrue(debug["is_superuser"])

res = self.client.get("/admin/")
self.assertEqual(res.status_code, 200, res.headers)

def tearDown(self) -> None:
descope_client.mgmt.user.delete(self.login_id)
4 changes: 0 additions & 4 deletions example_app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@

from django_descope import descope_client
from django_descope.models import DescopeUser
from django.shortcuts import render

from django.urls import path


logger = logging.getLogger(__name__)

Expand Down
4 changes: 2 additions & 2 deletions settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import os
from pathlib import Path
from typing import List

from dotenv import load_dotenv

Expand Down Expand Up @@ -103,8 +104,7 @@
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [] # With descope, there's no need for passwords!

AUTH_PASSWORD_VALIDATORS: List[str] = [] # With descope, there's no need for passwords!

# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
Expand Down
4 changes: 3 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ commands =
python manage.py test
extras=
test
passenv=
DESCOPE_PROJECT_ID
DESCOPE_MANAGEMENT_KEY
setenv=
PYTHONDONTWRITEBYTECODE=1
DESCOPE_PROJECT_ID=test
deps=
dj32: Django>=3.2,<3.3
dj40: Django>=4.0,<4.1
Expand Down

0 comments on commit c0506ca

Please sign in to comment.