Merge branch 'devel' into 'master'

Pull latest fixed from devel

See merge request oliver/ivatar!266
This commit is contained in:
Oliver Falk
2025-10-17 12:56:16 +02:00

View File

@@ -575,14 +575,12 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
# rb => Read binary # rb => Read binary
with open(TEST_IMAGE_FILE, "rb") as photo_file: with open(TEST_IMAGE_FILE, "rb") as photo_file:
photo_data = photo_file.read() photo_data = photo_file.read()
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
uploaded_file = SimpleUploadedFile( uploaded_file = SimpleUploadedFile(
"deadbeef.png", "deadbeef.png", photo_data, content_type="image/png"
photo_data,
content_type="image/png"
) )
response = self.client.post( response = self.client.post(
url, url,
{ {
@@ -2028,3 +2026,319 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
"This mail address has been taken already and cannot be confirmed", "This mail address has been taken already and cannot be confirmed",
"This should return an error message!", "This should return an error message!",
) )
class OpenIDErrorHandlingTestCase(TestCase):
"""
Test cases for OpenID error handling and error.html template coverage
"""
def setUp(self):
"""Set up test user and client"""
self.username = random_string()
self.password = random_string()
self.user = User.objects.create_user(
username=self.username,
password=self.password,
)
self.client = Client()
def login(self):
"""Login as test user"""
self.client.login(username=self.username, password=self.password)
def test_openid_discovery_failure_renders_error_template(self):
"""
Test that OpenID discovery failure renders error.html template
"""
from unittest.mock import patch, MagicMock
from openid.consumer import consumer
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://invalid-openid-provider.example.com/",
)
# Mock the OpenID consumer to raise DiscoveryFailure
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a proper DiscoveryFailure with required http_response parameter
mock_response = MagicMock()
mock_response.status_code = 404
discovery_failure = consumer.DiscoveryFailure(
"Invalid provider", mock_response
)
mock_consumer.begin.side_effect = discovery_failure
# Make request to openid_redirection view
response = self.client.get(
reverse("openid_redirection", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(
any("OpenID discovery failed" in str(msg) for msg in messages)
)
def test_openid_confirmation_failure_renders_error_template(self):
"""
Test that OpenID confirmation failure renders error.html template
"""
from unittest.mock import patch, MagicMock
from openid.consumer import consumer
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://test-provider.example.com/",
)
# Mock the OpenID consumer to return FAILURE status
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a mock response with FAILURE status
mock_response = MagicMock()
mock_response.status = consumer.FAILURE
mock_response.message = "Authentication failed"
mock_consumer.complete.return_value = mock_response
# Make request to confirm_openid view
response = self.client.get(
reverse("confirm_openid", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(any("Confirmation failed" in str(msg) for msg in messages))
def test_openid_cancellation_renders_error_template(self):
"""
Test that OpenID cancellation renders error.html template
"""
from unittest.mock import patch, MagicMock
from openid.consumer import consumer
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://test-provider.example.com/",
)
# Mock the OpenID consumer to return CANCEL status
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a mock response with CANCEL status
mock_response = MagicMock()
mock_response.status = consumer.CANCEL
mock_consumer.complete.return_value = mock_response
# Make request to confirm_openid view
response = self.client.get(
reverse("confirm_openid", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(any("Cancelled by user" in str(msg) for msg in messages))
def test_openid_unknown_error_renders_error_template(self):
"""
Test that unknown OpenID verification error renders error.html template
"""
from unittest.mock import patch, MagicMock
from ivatar.ivataraccount.models import UnconfirmedOpenId
self.login()
# Create an unconfirmed OpenID
unconfirmed = UnconfirmedOpenId.objects.create(
user=self.user,
openid="http://test-provider.example.com/",
)
# Mock the OpenID consumer to return unknown status
with patch(
"ivatar.ivataraccount.views.consumer.Consumer"
) as mock_consumer_class:
mock_consumer = MagicMock()
mock_consumer_class.return_value = mock_consumer
# Create a mock response with unknown status
mock_response = MagicMock()
mock_response.status = "UNKNOWN_STATUS"
mock_consumer.complete.return_value = mock_response
# Make request to confirm_openid view
response = self.client.get(
reverse("confirm_openid", args=[unconfirmed.id]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(
any("Unknown verification error" in str(msg) for msg in messages)
)
def test_openid_nonexistent_id_error(self):
"""
Test that accessing non-existent OpenID ID shows error message
"""
self.login()
# Try to access a non-existent OpenID ID
response = self.client.get(
reverse("openid_redirection", args=[99999]), follow=True
)
# Verify we get redirected to profile with error message
self.assertEqual(response.status_code, 200)
self.assertRedirects(response, reverse("profile"))
# Check that error message is in the response
messages = list(response.context[0]["messages"])
self.assertTrue(any("ID does not exist" in str(msg) for msg in messages))
def test_django_openid_auth_failure_template_coverage(self):
"""
Test that django-openid-auth failure template uses error.html
This test verifies the OpenID login page renders correctly
"""
# Try to access the OpenID login page
response = self.client.get(reverse("openid-login"))
self.assertEqual(response.status_code, 200)
# The login page should render successfully
self.assertContains(response, "OpenID Login")
def test_error_template_direct_rendering(self):
"""
Test error.html template directly to ensure it renders correctly
"""
from django.test import RequestFactory
from django.template import Context, Template
from django.contrib.auth.models import AnonymousUser
# Test with authenticated user
factory = RequestFactory()
request = factory.get("/")
request.user = self.user
# Test template with error message
template_content = """
{% extends 'error.html' %}
{% load i18n %}
{% block errormessage %}
{% trans 'Test error message:' %} {{ errormessage }}
{% endblock errormessage %}
"""
template = Template(template_content)
context = Context(
{
"request": request,
"errormessage": "This is a test error",
"user": self.user,
}
)
rendered = template.render(context)
# Verify the template renders without errors
self.assertIn("Error!", rendered)
self.assertIn("This is a test error", rendered)
# Check for the profile link in the navbar (not in the backlink block)
self.assertIn("/accounts/profile/", rendered)
# Test with anonymous user
request.user = AnonymousUser()
context = Context(
{
"request": request,
"errormessage": "This is a test error",
"user": AnonymousUser(),
}
)
rendered = template.render(context)
# Verify the template renders without errors for anonymous users
self.assertIn("Error!", rendered)
self.assertIn("This is a test error", rendered)
# Should not contain profile link for anonymous users
self.assertNotIn("/accounts/profile/", rendered)
def test_openid_failure_template_inheritance(self):
"""
Test that openid/failure.html properly extends error.html
"""
from django.test import RequestFactory
from django.template import Context, Template
factory = RequestFactory()
request = factory.get("/")
request.user = self.user
# Test the openid/failure.html template
template_content = """
{% extends 'error.html' %}
{% load i18n %}
{% block errormessage %}
{% trans 'OpenID error:' %} {{ message }}
{% endblock errormessage %}
"""
template = Template(template_content)
context = Context(
{
"request": request,
"message": "Authentication failed",
"user": self.user,
}
)
rendered = template.render(context)
# Verify the template renders correctly
self.assertIn("Error!", rendered)
self.assertIn("OpenID error:", rendered)
self.assertIn("Authentication failed", rendered)
# Check for the profile link in the navbar (not in the backlink block)
self.assertIn("/accounts/profile/", rendered)