Enforce lowercase email addresses in more places

We don't want two different accounts to exist with the same email
address only differing in case. This had already happened for a few
which have been manually fixed, since it turns out we only enforced the
rule on new account creation, not when accounts changed email address or
when they were created using oauth. Also add database level constraints to
make sure this cannot happen again if some codepath is missed.
This commit is contained in:
Magnus Hagander
2017-10-13 14:08:21 +02:00
parent b8c353ac28
commit 022dd26283
5 changed files with 30 additions and 9 deletions

View File

@ -94,6 +94,9 @@ class SignupOauthForm(forms.Form):
def clean_username(self):
return _clean_username(self.cleaned_data['username'])
def clean_email(self):
return self.cleaned_data['email'].lower()
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
@ -122,7 +125,7 @@ class ChangeEmailForm(forms.Form):
self.user = user
def clean_email(self):
email = self.cleaned_data['email']
email = self.cleaned_data['email'].lower()
if email == self.user.email:
raise forms.ValidationError("This is your existing email address!")
@ -136,7 +139,7 @@ class ChangeEmailForm(forms.Form):
# If the primary email checker had an exception, the data will be gone
# from the cleaned_data structure
if not self.cleaned_data.has_key('email'):
return self.cleaned_data['email2']
return self.cleaned_data['email2'].lower()
email1 = self.cleaned_data['email'].lower()
email2 = self.cleaned_data['email2'].lower()

View File

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.RunSQL("UPDATE auth_user SET email=lower(email) WHERE email!=lower(email)"),
migrations.RunSQL("ALTER TABLE auth_user ADD CONSTRAINT email_must_be_lowercase CHECK (email=lower(email))"),
migrations.RunSQL("CREATE UNIQUE INDEX auth_user_email_lower_key ON auth_user USING btree(lower(email))"),
]

View File

@ -39,6 +39,7 @@ def _login_oauth(request, provider, authurl, tokenurl, scope, authdatafunc):
code=request.GET['code'])
try:
(email, firstname, lastname) = authdatafunc(oa)
email = email.lower()
except KeyError, e:
log.warning("Oauth signing using {0} was missing data: {1}".format(provider, e))
return HttpResponse('OAuth login was missing critical data. To log in, you need to allow access to email, first name and last name!')

View File

@ -153,7 +153,7 @@ def change_email(request):
# Create a new token
token = EmailChangeToken(user=request.user,
email=form.cleaned_data['email'],
email=form.cleaned_data['email'].lower(),
token=generate_random_token())
token.save()
@ -185,7 +185,7 @@ def confirm_change_email(request, tokenhash):
if token:
# Valid token find, so change the email address
request.user.email = token.email
request.user.email = token.email.lower()
request.user.save()
token.delete()
@ -334,7 +334,7 @@ def signup_oauth(request):
# Second stage, so create the account. But verify that the
# nonce matches.
data = request.POST.copy()
data['email'] = request.session['oauth_email']
data['email'] = request.session['oauth_email'].lower()
data['first_name'] = request.session['oauth_firstname']
data['last_name'] = request.session['oauth_lastname']
form = SignupOauthForm(data=data)
@ -342,7 +342,7 @@ def signup_oauth(request):
log.info("Creating user for {0} from {1} from oauth signin of email {2}".format(form.cleaned_data['username'], get_client_ip(request), request.session['oauth_email']))
user = User.objects.create_user(form.cleaned_data['username'].lower(),
request.session['oauth_email'],
request.session['oauth_email'].lower(),
last_login=datetime.now())
user.first_name = request.session['oauth_firstname']
user.last_name = request.session['oauth_lastname']
@ -387,7 +387,7 @@ def signup_oauth(request):
form = SignupOauthForm(initial={
'username': suggested_username,
'email': request.session['oauth_email'],
'email': request.session['oauth_email'].lower(),
'first_name': request.session['oauth_firstname'][:30],
'last_name': request.session['oauth_lastname'][:30],
})

View File

@ -24,7 +24,7 @@ class OrganisationForm(forms.ModelForm):
if self.cleaned_data['add_manager']:
# Something was added as manager - let's make sure the user exists
try:
User.objects.get(email=self.cleaned_data['add_manager'])
User.objects.get(email=self.cleaned_data['add_manager'].lower())
except User.DoesNotExist:
raise ValidationError("User with email %s not found" % self.cleaned_data['add_manager'])
@ -44,7 +44,7 @@ class OrganisationForm(forms.ModelForm):
def save(self, commit=True):
model = super(OrganisationForm, self).save(commit=False)
if self.cleaned_data.has_key('add_manager') and self.cleaned_data['add_manager']:
model.managers.add(User.objects.get(email=self.cleaned_data['add_manager']))
model.managers.add(User.objects.get(email=self.cleaned_data['add_manager'].lower()))
if self.cleaned_data.has_key('remove_manager') and self.cleaned_data['remove_manager']:
for toremove in self.cleaned_data['remove_manager']:
model.managers.remove(toremove)