-
Notifications
You must be signed in to change notification settings - Fork 51
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
Ensure SSO works on admin level #237
Changes from all commits
aaad154
fcf1397
1ee5747
3521bf0
5ce41e5
c1439ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{% extends "orga/base.html" %} | ||
{% load i18n %} | ||
{% load rules %} | ||
{% block extra_title %}{% translate "SSO settings" %} :: {% endblock extra_title %} | ||
{% block content %} | ||
<h2>{% translate "SSO client settings" %}</h2> | ||
<form method="post"> | ||
{% csrf_token %} | ||
{{ form }} | ||
<div class="submit-group panel"> | ||
<span> | ||
{% if sso_provider %} | ||
<a class="btn-outline-danger btn-lg" role="button" href='{% url "orga:admin.sso.delete" %}'> | ||
{% translate "Delete key" %} | ||
</a> | ||
{% endif %} | ||
</span> | ||
<span> | ||
<button type="submit" class="btn-success btn-lg"> | ||
<i class="fa fa-check"></i> | ||
{{ phrases.base.save }} | ||
</button> | ||
</span> | ||
</div> | ||
</form> | ||
{% endblock content %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
import logging | ||
import os | ||
|
||
from allauth.socialaccount.models import SocialApp | ||
from django.conf import settings | ||
from django.contrib import messages | ||
from django.contrib.auth import login | ||
from django.shortcuts import redirect | ||
from django.urls import reverse | ||
|
@@ -19,9 +21,16 @@ | |
|
||
|
||
def oauth2_login_view(request, *args, **kwargs): | ||
sso_provider = SocialApp.objects.filter( | ||
provider=settings.EVENTYAY_SSO_PROVIDER | ||
).first() | ||
if not sso_provider: | ||
messages.error(request, "SSO not configured yet, please contact the " | ||
"administrator or come back later.") | ||
return redirect(reverse("orga:login")) | ||
# Create an OAuth2 session using the client ID and redirect URI | ||
oauth2_session = OAuth2Session( | ||
client_id=settings.OAUTH2_PROVIDER["CLIENT_ID"], | ||
client_id=sso_provider.client_id, | ||
redirect_uri=settings.OAUTH2_PROVIDER["REDIRECT_URI"], | ||
scope=settings.OAUTH2_PROVIDER["SCOPE"], | ||
) | ||
|
@@ -39,8 +48,15 @@ | |
|
||
|
||
def oauth2_callback(request): | ||
sso_provider = SocialApp.objects.filter( | ||
provider=settings.EVENTYAY_SSO_PROVIDER | ||
).first() | ||
if not sso_provider: | ||
messages.error(request, "SSO not configured yet, please contact the " | ||
"administrator or come back later.") | ||
return redirect(reverse("orga:login")) | ||
oauth2_session = OAuth2Session( | ||
settings.OAUTH2_PROVIDER["CLIENT_ID"], | ||
sso_provider.client_id, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
redirect_uri=settings.OAUTH2_PROVIDER["REDIRECT_URI"], | ||
state=request.session.get("oauth2_state"), | ||
) | ||
|
@@ -49,7 +65,7 @@ | |
# Fetch the token using the authorization code | ||
oauth2_session.fetch_token( | ||
settings.OAUTH2_PROVIDER["ACCESS_TOKEN_URL"], | ||
client_secret=settings.OAUTH2_PROVIDER["CLIENT_SECRET"], | ||
client_secret=sso_provider.secret, | ||
authorization_response=request.build_absolute_uri(), | ||
scope=settings.OAUTH2_PROVIDER["SCOPE"], | ||
) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from allauth.socialaccount.models import SocialApp | ||
from django.conf import settings | ||
from django.contrib import messages | ||
from django.contrib.sites.models import Site | ||
from django.db import transaction | ||
from django.http import HttpResponseRedirect | ||
from django.shortcuts import redirect | ||
from django.urls import reverse | ||
from django.utils.translation import gettext_lazy as _ | ||
from django.views.generic import DetailView | ||
|
||
from pretalx.common.text.phrases import phrases | ||
from pretalx.common.views import CreateOrUpdateView | ||
from pretalx.common.views.mixins import ActionConfirmMixin, PermissionRequired | ||
from pretalx.orga.forms.sso_client_form import SSOClientForm | ||
|
||
|
||
class SSOConfigureView(PermissionRequired, CreateOrUpdateView): | ||
template_name = "eventyay_common/sso/detail.html" | ||
permission_required = "person.is_administrator" | ||
form_class = SSOClientForm | ||
model = SocialApp | ||
|
||
def get_object(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (complexity): Consider caching the get_object result and simplifying form handling to reduce code complexity. The current implementation has unnecessary complexity that can be simplified while maintaining Django patterns:
@property
def sso_provider(self):
if not hasattr(self, '_sso_provider'):
self._sso_provider = SocialApp.objects.filter(
provider=settings.EVENTYAY_SSO_PROVIDER
).first()
return self._sso_provider
def form_valid(self, form):
instance = form.save(commit=False)
instance.provider = settings.EVENTYAY_SSO_PROVIDER
instance.name = "Eventyay Ticket Provider"
instance.save()
instance.sites.add(Site.objects.get(pk=settings.SITE_ID))
messages.success(self.request, phrases.base.saved)
return super().form_valid(form)
def get_success_url(self):
return self.request.path This removes the need for a separate form_invalid method since the parent class already handles it appropriately. The property caching pattern reduces database queries and improves code organization while maintaining Django conventions. |
||
""" | ||
Get the SocialApp instance for the 'eventyay' provider if it exists. | ||
If not, return None to create a new instance. | ||
Note: "eventyay" is the provider name for the Eventyay Ticket Provider. | ||
""" | ||
return SocialApp.objects.filter(provider=settings.EVENTYAY_SSO_PROVIDER).first() | ||
|
||
def get_success_url(self): | ||
messages.success(self.request, phrases.base.saved) | ||
return self.request.path | ||
|
||
def form_valid(self, form): | ||
""" | ||
Handle the form submission and save the instance. | ||
""" | ||
instance = form.save(commit=False) | ||
instance.provider = settings.EVENTYAY_SSO_PROVIDER | ||
instance.name = "Eventyay Ticket Provider" | ||
with transaction.atomic(): | ||
instance.save() | ||
site = Site.objects.get(pk=settings.SITE_ID) | ||
instance.sites.add(site) | ||
return redirect(self.get_success_url()) | ||
|
||
def form_invalid(self, form): | ||
""" | ||
Handle invalid form submissions. | ||
""" | ||
messages.error( | ||
self.request, | ||
"There was an error updating the Eventyay Ticket " | ||
"Provider configuration.", | ||
) | ||
return self.render_to_response(self.get_context_data(form=form)) | ||
|
||
def get_context_data(self, **kwargs): | ||
""" | ||
Add additional context to the template if necessary. | ||
""" | ||
context = super().get_context_data(**kwargs) | ||
context["sso_provider"] = self.get_object() | ||
return context | ||
|
||
|
||
class SSODeleteView(PermissionRequired, ActionConfirmMixin, DetailView): | ||
permission_required = "person.is_administrator" | ||
model = SocialApp | ||
action_text = ( | ||
_("You will not able to login with eventyay-tickets account.") | ||
+ " " | ||
+ phrases.base.delete_warning | ||
) | ||
|
||
def get_object(self, queryset=None): | ||
return SocialApp.objects.filter(provider=settings.EVENTYAY_SSO_PROVIDER).first() | ||
|
||
def action_object_name(self): | ||
return _("SSO Provider") + f": {self.get_object().name}" | ||
|
||
@property | ||
def action_back_url(self): | ||
return reverse("orga:admin.sso.settings") | ||
|
||
def post(self, *args, **kwargs): | ||
sso_provider = self.get_object() | ||
sso_provider.delete() | ||
return HttpResponseRedirect(reverse("orga:admin.sso.settings")) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,12 @@ | ||
from allauth.socialaccount.models import SocialApp | ||
from django import forms | ||
from django.conf import settings | ||
from django.contrib.sites.models import Site | ||
|
||
|
||
class SSOClientForm(forms.ModelForm): | ||
def __init__(self, provider_id, *args, **kwargs): | ||
social_app = SocialApp.objects.filter(provider=provider_id).first() | ||
kwargs["instance"] = social_app | ||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.fields["secret"].required = True # Secret is required | ||
self.fields["secret"].required = True | ||
|
||
class Meta: | ||
model = SocialApp | ||
fields = ["client_id", "secret"] | ||
|
||
def save(self, organiser=None): | ||
self.instance.name = organiser | ||
self.instance.provider = organiser | ||
super().save() | ||
self.instance.sites.add(Site.objects.get(pk=settings.SITE_ID)) |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Add error handling for missing SSO provider
The function should handle the case where no SSO provider exists, possibly redirecting to a configuration page with an appropriate message.