From e001690d4d966ab539f4bf5dd0b077371ba27c01 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Wed, 11 Jun 2025 12:29:24 +0200 Subject: [PATCH] Use POST when sending to third party oauth Instead of prepopulating a GET request that could generate a session, createa a form with different submit buttons and use that. In the brave new world of AI bots, nobody cares about robots.txt anymore, so we'd get hit by a lot of requests specifically for these logins that were then thrown away because they couldn't log in on the third party site. --- media/css/main.css | 6 ++++++ pgweb/account/oauthclient.py | 26 +++++++++++++++++++++++--- pgweb/account/urls.py | 1 + templates/account/login.html | 5 ++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/media/css/main.css b/media/css/main.css index 71364f19..4c5c0fab 100644 --- a/media/css/main.css +++ b/media/css/main.css @@ -1834,6 +1834,12 @@ th.organisation-logo { max-width: 650px; } +/* Buttons that are images */ +button.imagebutton { + border: 0; + padding: 0; +} + /** ALL RESPONSIVE QUERIES HERE */ /* Small devices (landscape phones, 576px and up)*/ diff --git a/pgweb/account/oauthclient.py b/pgweb/account/oauthclient.py index bd57243e..255233b1 100644 --- a/pgweb/account/oauthclient.py +++ b/pgweb/account/oauthclient.py @@ -1,6 +1,8 @@ from django.conf import settings from django.contrib.auth import login as django_login -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.views.decorators.http import require_POST, require_GET +from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.models import User import os @@ -66,7 +68,10 @@ def _login_oauth(request, provider, authurl, tokenurl, scope, authdatafunc): redir = '{0}/account/login/{1}/'.format(settings.SITE_ROOT, provider) oa = OAuth2Session(client_id, scope=scope, redirect_uri=redir) - if 'code' in request.GET: + if request.method == 'GET': + if 'code' not in request.GET: + raise OAuthException("No code provided") + log.info("Completing {0} oauth2 step from {1}".format(provider, get_client_ip(request))) # Receiving a login request from the provider, so validate data @@ -284,8 +289,21 @@ def oauth_login_twitter(request): _twitter_auth_data) +@require_POST +@csrf_exempt +def initiate_oauth_login(request): + if 'submit' not in request.POST: + return HttpResponse("Invalid post", status=400) + return _oauth_login_dispatch(request.POST['submit'], request) + + +@require_GET @queryparams('code', 'state', 'next', 'oauth_verifier') def login_oauth(request, provider): + return _oauth_login_dispatch(provider, request) + + +def _oauth_login_dispatch(provider, request): fn = 'oauth_login_{0}'.format(provider) m = sys.modules[__name__] if hasattr(m, fn): @@ -294,5 +312,7 @@ def login_oauth(request, provider): except OAuthException as e: return HttpResponse(e) except Exception as e: - log.error('Exception during OAuth: %s' % e) + log.error('Exception during OAuth: {}'.format(e)) return HttpResponse('An unhandled exception occurred during the authentication process') + else: + raise Http404() diff --git a/pgweb/account/urls.py b/pgweb/account/urls.py index 80d0871f..12ad5955 100644 --- a/pgweb/account/urls.py +++ b/pgweb/account/urls.py @@ -41,6 +41,7 @@ urlpatterns = [ # Log in, logout, change password etc re_path(r'^login/$', pgweb.account.views.login), + re_path(r'^login/oauth/$', pgweb.account.oauthclient.initiate_oauth_login), re_path(r'^logout/$', pgweb.account.views.logout), re_path(r'^changepwd/$', pgweb.account.views.changepwd), re_path(r'^changepwd/done/$', pgweb.account.views.change_done), diff --git a/templates/account/login.html b/templates/account/login.html index a48279ae..7eaa2d55 100644 --- a/templates/account/login.html +++ b/templates/account/login.html @@ -46,9 +46,12 @@ password, you can use the password reset form. {%if oauth_providers%}

Third party sign in

+
+ {%for p,d in oauth_providers%} -

Sign in with {{p|capfirst}}

+

{%endfor%} +
{%endif%} {%endblock%} -- 2.39.5