diff --git a/.env.example b/.env.example index 930af5b..14e0f17 100644 --- a/.env.example +++ b/.env.example @@ -39,7 +39,8 @@ OAUTH_ONLY=False #OAUTH_BUTTON_TEXT=Login with OAuth #OAUTH_BUTTON_IMAGE= # Space-separated OAuth2 scopes -#OAUTH_SCOPE=openid profile email +#OAUTH_SCOPE=openid profile email groups +#OAUTH_ADMIN_GROUP=Admins # Database engine: 'sqlite' or 'postgres' DB_ENGINE=sqlite diff --git a/allauth_oauth/provider.py b/allauth_oauth/provider.py index 6a6430c..2a9035e 100644 --- a/allauth_oauth/provider.py +++ b/allauth_oauth/provider.py @@ -18,14 +18,12 @@ class OAuthProvider(OAuth2Provider): account_class = OAuthAccount def extract_uid(self, data): - return str(data["username"]) + return str(data["preferred_username"]) def extract_common_fields(self, data): return dict( email=data.get("email"), - username=data.get("username"), - last_name=data.get("last_name"), - first_name=data.get("first_name"), + username=data.get("preferred_username"), ) def get_default_scope(self): diff --git a/allauth_oauth/signals.py b/allauth_oauth/signals.py index d7f1cf6..8a7c9a2 100644 --- a/allauth_oauth/signals.py +++ b/allauth_oauth/signals.py @@ -2,7 +2,9 @@ # Copyright (C) 2022 Amicale des élèves de l'ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from allauth.account.models import EmailAddress from allauth.socialaccount.signals import pre_social_login +from django.conf import settings from django.dispatch import receiver @@ -19,11 +21,19 @@ def sync_user_fields(sender, request, sociallogin, **kwargs): if email and user.email != email: user.email = email changed = True + EmailAddress.objects.filter(user=user).update(email=email) - username = data.get("username") + username = data.get("preferred_username") if username and user.username != username: user.username = username changed = True + admin_group = settings.OAUTH_ADMIN_GROUP + if admin_group: + is_staff = admin_group in data.get("groups", []) + if user.is_staff != is_staff: + user.is_staff = is_staff + changed = True + if changed: user.save() diff --git a/allauth_oauth/views.py b/allauth_oauth/views.py index 7a568a5..f247412 100644 --- a/allauth_oauth/views.py +++ b/allauth_oauth/views.py @@ -4,6 +4,7 @@ import requests from allauth.socialaccount import app_settings +from django.core.exceptions import ImproperlyConfigured from allauth.socialaccount.providers.oauth2.views import ( OAuth2Adapter, OAuth2CallbackView, @@ -31,20 +32,27 @@ class OAuthAdapter(OAuth2Adapter): @property def domain(self): - return self.settings.get("DOMAIN", "") + domain = self.settings.get("DOMAIN", "") + if not domain: + raise ImproperlyConfigured( + "OAUTH_SERVER_URL is not configured. Set it in your .env file." + ) + return domain @property def access_token_url(self): - return f"https://{self.domain}/o/token/" + return f"https://{self.domain}/application/o/token/" @property def authorize_url(self): - return f"https://{self.domain}/o/authorize/" + return f"https://{self.domain}/application/o/authorize/" @property def profile_url(self): - return f"https://{self.domain}/api/me/" + return f"https://{self.domain}/application/o/userinfo/" +OAuthProvider.oauth2_adapter_class = OAuthAdapter + oauth2_login = OAuth2LoginView.adapter_view(OAuthAdapter) oauth2_callback = OAuth2CallbackView.adapter_view(OAuthAdapter) diff --git a/photo21/settings.py b/photo21/settings.py index 422f2c7..c41d520 100644 --- a/photo21/settings.py +++ b/photo21/settings.py @@ -64,6 +64,7 @@ OAUTH_SERVER_URL = config("OAUTH_SERVER_URL", default="") OAUTH_BUTTON_TEXT = config("OAUTH_BUTTON_TEXT", default="Login with OAuth") OAUTH_BUTTON_IMAGE = config("OAUTH_BUTTON_IMAGE", default="") OAUTH_SCOPE = config("OAUTH_SCOPE", default="openid profile email", cast=Csv(delimiter=" ")) +OAUTH_ADMIN_GROUP = config("OAUTH_ADMIN_GROUP", default="") INSTALLED_APPS = [ "django.contrib.admin", @@ -118,6 +119,7 @@ TEMPLATES = [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", + "photo21.views.oauth_context", ], }, }, @@ -282,6 +284,9 @@ ACCOUNT_FORMS = {"signup": "photo21.forms.CustomSignupForm"} if OAUTH_ENABLED: SOCIALACCOUNT_ONLY = OAUTH_ONLY + if OAUTH_ONLY: + ACCOUNT_EMAIL_VERIFICATION = 'none' + SOCIALACCOUNT_LOGIN_ON_GET = True SOCIALACCOUNT_PROVIDERS = { "oauth": { "SCOPE": OAUTH_SCOPE, diff --git a/photo21/templates/account/login.html b/photo21/templates/account/login.html index a2bc666..b1c48b3 100644 --- a/photo21/templates/account/login.html +++ b/photo21/templates/account/login.html @@ -15,10 +15,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
+ {% if not SOCIALACCOUNT_ONLY %}

{% blocktrans trimmed with site.name as site_name %}Please sign in with one of your existing third party accounts. Or, sign up for a {{ site_name }} account and sign in below:{% endblocktrans %}

+ {% endif %} {% include "socialaccount/snippets/login_extra.html" %} @@ -27,6 +29,7 @@ SPDX-License-Identifier: GPL-3.0-or-later sign up first.{% endblocktrans %}

{% endif %} + {% if not SOCIALACCOUNT_ONLY %}
{% csrf_token %} {{ form|crispy }} {% if redirect_field_value %} @@ -36,7 +39,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
- {% trans "Forgot Password?" %} + {% url 'account_reset_password' as reset_url %}{% if reset_url %}{% trans "Forgot Password?" %}{% endif %} + {% endif %} diff --git a/photo21/templates/base.html b/photo21/templates/base.html index ccd17c2..ce771a1 100644 --- a/photo21/templates/base.html +++ b/photo21/templates/base.html @@ -100,15 +100,16 @@ SPDX-License-Identifier: GPL-3.0-or-later {% trans "Log in" %} - + {% endif %} {% endif %} diff --git a/photo21/templates/socialaccount/snippets/provider_list.html b/photo21/templates/socialaccount/snippets/provider_list.html index 71a8ec0..dc6aad7 100644 --- a/photo21/templates/socialaccount/snippets/provider_list.html +++ b/photo21/templates/socialaccount/snippets/provider_list.html @@ -17,5 +17,5 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endfor %} {% endif %} {% trans "Sign in with" %} {{provider.name}} + href="{% provider_login_url provider.id process=process scope=scope auth_params=auth_params %}">{{ OAUTH_BUTTON_TEXT|default:provider.name }} {% endfor %} diff --git a/photo21/urls.py b/photo21/urls.py index 2884442..5b4df26 100644 --- a/photo21/urls.py +++ b/photo21/urls.py @@ -24,6 +24,8 @@ urlpatterns = [ path("", IndexView.as_view(), name="index"), path("", include("photologue.urls", namespace="photologue")), path("accounts/", include("allauth.urls")), + path("accounts/", include("allauth_oauth.urls")), + path("i18n/", include("django.conf.urls.i18n")), path("jsi18n/", JavaScriptCatalog.as_view(), name="javascript-catalog"), path("admin/doc/", include("django.contrib.admindocs.urls")), diff --git a/photo21/views.py b/photo21/views.py index 65f0b11..075f249 100644 --- a/photo21/views.py +++ b/photo21/views.py @@ -69,3 +69,10 @@ class IndexView(LoginRequiredMixin, ListView): context["superusers"] = superusers return context + + +def oauth_context(request): + return { + "OAUTH_BUTTON_TEXT": getattr(settings, "OAUTH_BUTTON_TEXT", ""), + "OAUTH_BUTTON_IMAGE": getattr(settings, "OAUTH_BUTTON_IMAGE", ""), + }