From 170262915bd627dfd821488d3fbffb2444ad44bc Mon Sep 17 00:00:00 2001 From: Robert George Date: Sat, 11 Feb 2023 17:41:16 -0800 Subject: [PATCH 1/2] Added support for oauth 2 login and registration --- .env.example | 8 ++ bookwyrm/context_processors.py | 2 + bookwyrm/forms/landing.py | 14 ++++ bookwyrm/oauth.py | 38 ++++++++++ bookwyrm/settings.py | 11 +++ bookwyrm/templates/landing/login.html | 8 +- .../templates/landing/oauth_register.html | 75 +++++++++++++++++++ bookwyrm/templates/layout.html | 6 ++ bookwyrm/urls.py | 5 +- bookwyrm/views/__init__.py | 1 + bookwyrm/views/landing/register.py | 16 ++-- bookwyrm/views/oauth.py | 35 +++++++++ requirements.txt | 1 + 13 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 bookwyrm/oauth.py create mode 100644 bookwyrm/templates/landing/oauth_register.html create mode 100644 bookwyrm/views/oauth.py diff --git a/.env.example b/.env.example index 4c1c2eefea..3983e23c7e 100644 --- a/.env.example +++ b/.env.example @@ -120,3 +120,11 @@ OTEL_SERVICE_NAME= # for your instance: # https://docs.djangoproject.com/en/3.2/ref/settings/#secure-proxy-ssl-header HTTP_X_FORWARDED_PROTO=false + +# Enable logging in and registration with OAuth 2 +OAUTH_ACTIVE=false +#OAUTH_NAME="OAuth Provider" # Displayed on Login Button as "Login with OAUTH_NAME" +#OAUTH_CLIENT_ID="" +#OAUTH_CLIENT_SECRET="" +#OAUTH_AUTHORIZE_URL="" # For mastodon use "https:///oauth/authorize" +#OAUTH_ACCESS_TOKEN_URL="" # For mastodon use "https:///oauth/token" diff --git a/bookwyrm/context_processors.py b/bookwyrm/context_processors.py index 0047bfce11..df0a1ce775 100644 --- a/bookwyrm/context_processors.py +++ b/bookwyrm/context_processors.py @@ -28,4 +28,6 @@ def site_settings(request): # pylint: disable=unused-argument "preview_images_enabled": settings.ENABLE_PREVIEW_IMAGES, "request_protocol": request_protocol, "js_cache": settings.JS_CACHE, + "oauth_active": settings.OAUTH_ACTIVE, + "oauth_name": settings.OAUTH_NAME, } diff --git a/bookwyrm/forms/landing.py b/bookwyrm/forms/landing.py index bd9884bc35..1b20146bfb 100644 --- a/bookwyrm/forms/landing.py +++ b/bookwyrm/forms/landing.py @@ -56,6 +56,20 @@ def clean(self): self.add_error("localname", _("User with this username already exists")) +class OAuthRegisterForm(CustomForm): + class Meta: + model = models.User + fields = ["localname", "email"] + help_texts = {f: None for f in fields} + + def clean(self): + """Check if the username is taken""" + cleaned_data = super().clean() + localname = cleaned_data.get("localname").strip() + if models.User.objects.filter(localname=localname).first(): + self.add_error("localname", _("User with this username already exists")) + + class InviteRequestForm(CustomForm): def clean(self): """make sure the email isn't in use by a registered user""" diff --git a/bookwyrm/oauth.py b/bookwyrm/oauth.py new file mode 100644 index 0000000000..f297877897 --- /dev/null +++ b/bookwyrm/oauth.py @@ -0,0 +1,38 @@ +""" responds to various requests to oauth """ +from django.contrib.auth import login +from django.core.exceptions import ObjectDoesNotExist +from django.dispatch import receiver +from django.urls import reverse +from django.shortcuts import render, redirect +from django.template.response import TemplateResponse +from authlib.integrations.django_client import OAuth, OAuthError + +from bookwyrm import models +from bookwyrm.settings import DOMAIN + +oauth = OAuth() +oauth.register('oauth') +oauth = oauth.oauth + +def auth(request): + try: + token = oauth.authorize_access_token(request) + except OAuthError: + data = {} + return TemplateResponse(request, "landing/login.html", data) + acct = oauth.get("https://raphus.social/api/v1/accounts/verify_credentials",token=token) + if (acct.status_code==200): + localname = dict(acct.json())['acct'] + username = "{}@{}".format(localname,DOMAIN) + try: + user = models.User.objects.get(username=username) + except ObjectDoesNotExist: + request.session['oauth-newuser'] = localname + request.session["oauth-newuser-pfp"] = dict(acct.json())['avatar'] + return redirect('oauth-register') + login(request,user) + return redirect('/') + +def request_login(request): + redirect_uri = request.build_absolute_uri(reverse('oauth')) + return oauth.authorize_redirect(request, redirect_uri, force_login=True ) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index c66bd636b1..64cd9c7fd7 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -388,3 +388,14 @@ # Do not change this setting unless you already have an existing # user with the same username - in which case you should change it! INSTANCE_ACTOR_USERNAME = "bookwyrm.instance.actor" +OAUTH_ACTIVE = env("OAUTH_ACTIVE",False) +if OAUTH_ACTIVE: + OAUTH_NAME=env("OAUTH_NAME","OAuth2") + AUTHLIB_OAUTH_CLIENTS = { + 'oauth': { + 'client_id': env("OAUTH_CLIENT_ID"), + 'client_secret': env("OAUTH_CLIENT_SECRET"), + 'authorize_url': env("OAUTH_AUTHORIZE_URL"), + 'access_token_url': env("OAUTH_ACCESS_TOKEN_URL"), + } + } diff --git a/bookwyrm/templates/landing/login.html b/bookwyrm/templates/landing/login.html index 369a72bd28..ed20d06006 100644 --- a/bookwyrm/templates/landing/login.html +++ b/bookwyrm/templates/landing/login.html @@ -10,10 +10,15 @@

{% trans "Log in" %}

{% if login_form.non_field_errors %}

{{ login_form.non_field_errors }}

{% endif %} - + {% if show_confirmed_email %}

{% trans "Success! Email address confirmed." %}

{% endif %} + {% if oauth_active %} + + + + {% else %}
{% csrf_token %} {% if show_confirmed_email %}{% endif %} @@ -40,6 +45,7 @@

{% trans "Log in" %}

+ {% endif %} {% if site.allow_registration %} diff --git a/bookwyrm/templates/landing/oauth_register.html b/bookwyrm/templates/landing/oauth_register.html new file mode 100644 index 0000000000..215140baf2 --- /dev/null +++ b/bookwyrm/templates/landing/oauth_register.html @@ -0,0 +1,75 @@ +{% extends 'layout.html' %} +{% load i18n %} + +{% block title %}{% trans "Create an Account" %}{% endblock %} + +{% block content %} + +

{% trans "Create an Account" %}

+
+
+
+ {% if valid %} +
+
+{% csrf_token %} +
+ +
+ {{ username }} +
+

+ {% trans "Your username cannot be changed." %} +

+
+
+
+
+ +
+ + + {% include 'snippets/form_errors.html' with errors_list=register_form.email.errors id="desc_email_register" %} +
+
+ + + +
+
+ +
+
+
+
+ {% else %} +
+

{% trans "Permission Denied" %}

+

{% trans "Sorry!" %}

+
+ {% endif %} +
+
+
+
+ {% include 'snippets/about.html' %} +
+
+
+ +{% endblock %} diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index c3408f44e1..78c53b9ce7 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -115,6 +115,12 @@ + {% elif oauth_active %} + {% else %}