Browse Source

login, set-password, and change-email tokens use different salts.

pull/133/head
Pēteris Caune 7 years ago
parent
commit
de7160a0e6
5 changed files with 18 additions and 20 deletions
  1. +1
    -2
      hc/accounts/backends.py
  2. +11
    -11
      hc/accounts/models.py
  3. +3
    -3
      hc/accounts/tests/test_change_email.py
  4. +1
    -1
      hc/accounts/tests/test_check_token.py
  5. +2
    -3
      hc/accounts/views.py

+ 1
- 2
hc/accounts/backends.py View File

@ -1,4 +1,3 @@
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User from django.contrib.auth.models import User
from hc.accounts.models import Profile from hc.accounts.models import Profile
@ -22,7 +21,7 @@ class ProfileBackend(BasicBackend):
except Profile.DoesNotExist: except Profile.DoesNotExist:
return None return None
if not check_password(token, profile.token):
if not profile.check_token(token, "login"):
return None return None
return profile.user return profile.user


+ 11
- 11
hc/accounts/models.py View File

@ -4,7 +4,7 @@ import uuid
from datetime import timedelta from datetime import timedelta
from django.conf import settings from django.conf import settings
from django.contrib.auth.hashers import make_password
from django.contrib.auth.hashers import check_password, make_password
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import signing from django.core import signing
from django.db import models from django.db import models
@ -54,11 +54,17 @@ class Profile(models.Model):
def __str__(self): def __str__(self):
return self.team_name or self.user.email return self.team_name or self.user.email
def send_instant_login_link(self, inviting_profile=None):
def prepare_token(self, salt):
token = str(uuid.uuid4()) token = str(uuid.uuid4())
self.token = make_password(token)
self.token = make_password(token, salt)
self.save() self.save()
return token
def check_token(self, token, salt):
return salt in self.token and check_password(token, self.token)
def send_instant_login_link(self, inviting_profile=None):
token = self.prepare_token("login")
path = reverse("hc-check-token", args=[self.user.username, token]) path = reverse("hc-check-token", args=[self.user.username, token])
ctx = { ctx = {
"button_text": "Log In", "button_text": "Log In",
@ -68,10 +74,7 @@ class Profile(models.Model):
emails.login(self.user.email, ctx) emails.login(self.user.email, ctx)
def send_set_password_link(self): def send_set_password_link(self):
token = str(uuid.uuid4())
self.token = make_password(token)
self.save()
token = self.prepare_token("set-password")
path = reverse("hc-set-password", args=[token]) path = reverse("hc-set-password", args=[token])
ctx = { ctx = {
"button_text": "Set Password", "button_text": "Set Password",
@ -80,10 +83,7 @@ class Profile(models.Model):
emails.set_password(self.user.email, ctx) emails.set_password(self.user.email, ctx)
def send_change_email_link(self): def send_change_email_link(self):
token = str(uuid.uuid4())
self.token = make_password(token)
self.save()
token = self.prepare_token("change-email")
path = reverse("hc-change-email", args=[token]) path = reverse("hc-change-email", args=[token])
ctx = { ctx = {
"button_text": "Change Email", "button_text": "Change Email",


+ 3
- 3
hc/accounts/tests/test_change_email.py View File

@ -6,7 +6,7 @@ from hc.test import BaseTestCase
class ChangeEmailTestCase(BaseTestCase): class ChangeEmailTestCase(BaseTestCase):
def test_it_shows_form(self): def test_it_shows_form(self):
self.profile.token = make_password("foo")
self.profile.token = make_password("foo", "change-email")
self.profile.save() self.profile.save()
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
@ -15,7 +15,7 @@ class ChangeEmailTestCase(BaseTestCase):
self.assertContains(r, "Change Account's Email Address") self.assertContains(r, "Change Account's Email Address")
def test_it_changes_password(self): def test_it_changes_password(self):
self.profile.token = make_password("foo")
self.profile.token = make_password("foo", "change-email")
self.profile.save() self.profile.save()
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
@ -28,7 +28,7 @@ class ChangeEmailTestCase(BaseTestCase):
self.assertFalse(self.alice.has_usable_password()) self.assertFalse(self.alice.has_usable_password())
def test_it_requires_unique_email(self): def test_it_requires_unique_email(self):
self.profile.token = make_password("foo")
self.profile.token = make_password("foo", "change-email")
self.profile.save() self.profile.save()
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")


+ 1
- 1
hc/accounts/tests/test_check_token.py View File

@ -6,7 +6,7 @@ class CheckTokenTestCase(BaseTestCase):
def setUp(self): def setUp(self):
super(CheckTokenTestCase, self).setUp() super(CheckTokenTestCase, self).setUp()
self.profile.token = make_password("secret-token")
self.profile.token = make_password("secret-token", "login")
self.profile.save() self.profile.save()
def test_it_shows_form(self): def test_it_shows_form(self):


+ 2
- 3
hc/accounts/views.py View File

@ -7,7 +7,6 @@ from django.contrib.auth import login as auth_login
from django.contrib.auth import logout as auth_logout from django.contrib.auth import logout as auth_logout
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import signing from django.core import signing
from django.http import HttpResponseForbidden, HttpResponseBadRequest from django.http import HttpResponseForbidden, HttpResponseBadRequest
@ -288,7 +287,7 @@ def badges(request):
@login_required @login_required
def set_password(request, token): def set_password(request, token):
profile = request.user.profile profile = request.user.profile
if not check_password(token, profile.token):
if not profile.check_token(token, "set-password"):
return HttpResponseBadRequest() return HttpResponseBadRequest()
if request.method == "POST": if request.method == "POST":
@ -315,7 +314,7 @@ def set_password(request, token):
@login_required @login_required
def change_email(request, token): def change_email(request, token):
profile = request.user.profile profile = request.user.profile
if not check_password(token, profile.token):
if not profile.check_token(token, "change-email"):
return HttpResponseBadRequest() return HttpResponseBadRequest()
if request.method == "POST": if request.method == "POST":


Loading…
Cancel
Save