forked from GithubBackups/healthchecks
Store the one time login token in profile so user.password can be used for regular passwords.
This commit is contained in:
parent
8e8d9abe3b
commit
dd188064fa
24
hc/accounts/backends.py
Normal file
24
hc/accounts/backends.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from django.contrib.auth.hashers import check_password
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from hc.accounts.models import Profile
|
||||||
|
|
||||||
|
|
||||||
|
# Authenticate against the token in user's profile.
|
||||||
|
class ProfileBackend(object):
|
||||||
|
|
||||||
|
def authenticate(self, username=None, token=None):
|
||||||
|
try:
|
||||||
|
profile = Profile.objects.get(user__username=username)
|
||||||
|
except Profile.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not check_password(token, profile.token):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return profile.user
|
||||||
|
|
||||||
|
def get_user(self, user_id):
|
||||||
|
try:
|
||||||
|
return User.objects.get(pk=user_id)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return None
|
20
hc/accounts/migrations/0003_profile_token.py
Normal file
20
hc/accounts/migrations/0003_profile_token.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9 on 2016-01-04 20:26
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0002_profile_ping_log_limit'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='profile',
|
||||||
|
name='token',
|
||||||
|
field=models.CharField(blank=True, max_length=128),
|
||||||
|
),
|
||||||
|
]
|
@ -1,5 +1,6 @@
|
|||||||
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.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
@ -26,9 +27,19 @@ class Profile(models.Model):
|
|||||||
next_report_date = models.DateTimeField(null=True, blank=True)
|
next_report_date = models.DateTimeField(null=True, blank=True)
|
||||||
reports_allowed = models.BooleanField(default=True)
|
reports_allowed = models.BooleanField(default=True)
|
||||||
ping_log_limit = models.IntegerField(default=100)
|
ping_log_limit = models.IntegerField(default=100)
|
||||||
|
token = models.CharField(max_length=128, blank=True)
|
||||||
|
|
||||||
objects = ProfileManager()
|
objects = ProfileManager()
|
||||||
|
|
||||||
|
def send_instant_login_link(self):
|
||||||
|
token = str(uuid.uuid4())
|
||||||
|
self.token = make_password(token)
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
path = reverse("hc-check-token", args=[self.user.username, token])
|
||||||
|
ctx = {"login_link": settings.SITE_ROOT + path}
|
||||||
|
emails.login(self.user.email, ctx)
|
||||||
|
|
||||||
def send_report(self):
|
def send_report(self):
|
||||||
# reset next report date first:
|
# reset next report date first:
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import login as auth_login
|
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
|
||||||
@ -8,18 +7,17 @@ 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.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.http import HttpResponseBadRequest
|
from django.http import HttpResponseBadRequest
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from hc.accounts.forms import EmailForm, ReportSettingsForm
|
from hc.accounts.forms import EmailForm, ReportSettingsForm
|
||||||
from hc.accounts.models import Profile
|
from hc.accounts.models import Profile
|
||||||
from hc.api.models import Channel, Check
|
from hc.api.models import Channel, Check
|
||||||
from hc.lib import emails
|
|
||||||
|
|
||||||
|
|
||||||
def _make_user(email):
|
def _make_user(email):
|
||||||
username = str(uuid.uuid4())[:30]
|
username = str(uuid.uuid4())[:30]
|
||||||
user = User(username=username, email=email)
|
user = User(username=username, email=email)
|
||||||
|
user.set_unusable_password()
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
channel = Channel()
|
channel = Channel()
|
||||||
@ -46,18 +44,6 @@ def _associate_demo_check(request, user):
|
|||||||
del request.session["welcome_code"]
|
del request.session["welcome_code"]
|
||||||
|
|
||||||
|
|
||||||
def _send_login_link(user):
|
|
||||||
token = str(uuid.uuid4())
|
|
||||||
user.set_password(token)
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
login_link = reverse("hc-check-token", args=[user.username, token])
|
|
||||||
login_link = settings.SITE_ROOT + login_link
|
|
||||||
ctx = {"login_link": login_link}
|
|
||||||
|
|
||||||
emails.login(user.email, ctx)
|
|
||||||
|
|
||||||
|
|
||||||
def login(request):
|
def login(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = EmailForm(request.POST)
|
form = EmailForm(request.POST)
|
||||||
@ -69,12 +55,8 @@ def login(request):
|
|||||||
user = _make_user(email)
|
user = _make_user(email)
|
||||||
_associate_demo_check(request, user)
|
_associate_demo_check(request, user)
|
||||||
|
|
||||||
# We don't want to reset passwords of staff users :-)
|
profile = Profile.objects.for_user(user)
|
||||||
if user.is_staff:
|
profile.send_instant_login_link()
|
||||||
return HttpResponseBadRequest()
|
|
||||||
|
|
||||||
_send_login_link(user)
|
|
||||||
|
|
||||||
return redirect("hc-login-link-sent")
|
return redirect("hc-login-link-sent")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -99,14 +81,14 @@ def check_token(request, username, token):
|
|||||||
# User is already logged in
|
# User is already logged in
|
||||||
return redirect("hc-checks")
|
return redirect("hc-checks")
|
||||||
|
|
||||||
user = authenticate(username=username, password=token)
|
user = authenticate(username=username, token=token)
|
||||||
if user is not None:
|
if user is not None and user.is_active:
|
||||||
if user.is_active:
|
|
||||||
# This should get rid of "welcome_code" in session
|
# This should get rid of "welcome_code" in session
|
||||||
request.session.flush()
|
request.session.flush()
|
||||||
|
|
||||||
user.set_unusable_password()
|
profile = Profile.objects.for_user(user)
|
||||||
user.save()
|
profile.token = ""
|
||||||
|
profile.save()
|
||||||
auth_login(request, user)
|
auth_login(request, user)
|
||||||
|
|
||||||
return redirect("hc-checks")
|
return redirect("hc-checks")
|
||||||
|
@ -51,6 +51,11 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
|
'hc.accounts.backends.ProfileBackend'
|
||||||
|
)
|
||||||
|
|
||||||
ROOT_URLCONF = 'hc.urls'
|
ROOT_URLCONF = 'hc.urls'
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user