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.
This commit is contained in:
Magnus Hagander
2025-06-11 12:29:24 +02:00
parent e48157dac3
commit e001690d4d
4 changed files with 34 additions and 4 deletions

View File

@ -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)*/

View File

@ -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()

View File

@ -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),

View File

@ -46,9 +46,12 @@ password, you can use the <a href="/account/reset/">password reset</a> form.
{%if oauth_providers%}
<h2>Third party sign in</h2>
<form method="post" action="/account/login/oauth/">
<input type="hidden" name="next" value="{{next}}" />
{%for p,d in oauth_providers%}
<p><a href="/account/login/{{p}}/?next={{next}}"><img src="/media/img/misc/btn_login_{{p}}.png" alt="Sign in with {{p|capfirst}}" /></a></p>
<p><button type="submit" name="submit" value="{{p}}" class="imagebutton"><img src="/media/img/misc/btn_login_{{p}}.png" alt="Sign in with {{p|capfirst}}"></button></p>
{%endfor%}
</form>
{%endif%}
{%endblock%}