Add htpasswd management functionality.

- Legacy-Id: 3386
This commit is contained in:
Henrik Levkowetz 2011-08-26 18:06:12 +00:00
parent f47ca8710c
commit 6c93e2553b
5 changed files with 237 additions and 3 deletions

125
ietf/ietfauth/forms.py Normal file
View file

@ -0,0 +1,125 @@
import datetime
import hashlib
import subprocess
from django import forms
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.sites.models import Site
from django.utils.translation import ugettext, ugettext_lazy as _
from ietf.utils.mail import send_mail
from ietf.utils import debug
#from redesign.person.models import Person, Email
class RegistrationForm(forms.Form):
email = forms.EmailField(label="Your email")
realm = 'IETF'
expire = 3
def save(self, *args, **kwargs):
self.send_email()
return True
def send_email(self):
domain = Site.objects.get_current().domain
subject = 'Confirm registration at %s' % domain
from_email = settings.DEFAULT_FROM_EMAIL
to_email = self.cleaned_data['email']
today = datetime.date.today().strftime('%Y%m%d')
auth = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, today, to_email, self.realm)).hexdigest()
context = {
'domain': domain,
'today': today,
'realm': self.realm,
'auth': auth,
'username': to_email,
'expire': settings.DAYS_TO_EXPIRE_REGISTRATION_LINK,
}
send_mail(None, to_email, from_email, subject, 'registration/creation_email.txt', context)
def clean_email(self):
email = self.cleaned_data.get('email', '')
if not email:
return email
# if User.objects.filter(username=email).count():
# raise forms.ValidationError(_('Email already in use'))
return email
class RecoverPasswordForm(RegistrationForm):
realm = 'IETF'
def send_email(self):
domain = Site.objects.get_current().domain
subject = 'Password reset at %s' % domain
from_email = settings.DEFAULT_FROM_EMAIL
today = datetime.date.today().strftime('%Y%m%d')
to_email = self.cleaned_data['email']
today = datetime.date.today().strftime('%Y%m%d')
auth = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, today, to_email, self.realm)).hexdigest()
context = {
'domain': domain,
'today': today,
'realm': self.realm,
'auth': auth,
'username': to_email,
'expire': settings.DAYS_TO_EXPIRE_REGISTRATION_LINK,
}
send_mail(None, to_email, from_email, subject, 'registration/password_reset_email.txt', context)
class PasswordForm(forms.Form):
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
def __init__(self, *args, **kwargs):
self.username = kwargs.pop('username')
self.update_user = kwargs.pop('update_user', False)
super(PasswordForm, self).__init__(*args, **kwargs)
def clean_password2(self):
password1 = self.cleaned_data.get("password1", "")
password2 = self.cleaned_data["password2"]
if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match."))
return password2
def get_password(self):
return self.cleaned_data.get('password1')
def create_user(self):
# user = User.objects.create(username=self.username,
# email=self.username)
# person = Person.objects.create(user=user,
# name=self.username,
# ascii=self.username)
# Email.objects.create(person=person,
# address=self.username)
# return user
return None
def get_user(self):
return User.objects.get(username=self.username)
@debug.trace
def save(self):
# if self.update_user:
# user = self.get_user()
# else:
# user = self.create_user()
# user.set_password(self.get_password())
# user.save()
# return user
debug.show("[settings.HTPASSWD_COMMAND, settings.HTPASSWD_FILE, self.username, self.get_password()]")
p = subprocess.Popen([settings.HTPASSWD_COMMAND, "-b", settings.HTPASSWD_FILE, self.username, self.get_password()], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
debug.show('stdout')
debug.show('stderr')
return p.returncode

View file

@ -1,11 +1,21 @@
# Copyright The IETF Trust 2007, 2009, All Rights Reserved
from django.conf.urls.defaults import patterns
from django.conf.urls.defaults import patterns, url
from ietf.ietfauth import views
urlpatterns = patterns('',
(r'^$', views.index, None, 'account_index'),
(r'^login/$', views.ietf_login),
(r'^loggedin/$', views.ietf_loggedin),
(r'^profile/$', views.profile),
# (r'^login/(?P<user>[a-z0-9.@]+)/(?P<passwd>.+)$', views.url_login),
)
urlpatterns += patterns('ietf.ietfauth.views',
url(r'^create/$', 'create_account', name='create_account'),
url(r'^confirm/(?P<username>[\w.@+-]+)/(?P<date>[\d]+)/(?P<realm>[\w]+)/(?P<registration_hash>[a-f0-9]+)/$', 'confirm_account', name='confirm_account'),
url(r'^reset/$', 'password_reset_view', name='password_reset'),
url(r'^reset/confirm/(?P<username>[\w.@+-]+)/(?P<date>[\d]+)/(?P<realm>[\w]+)/(?P<reset_hash>[a-f0-9]+)/$', 'confirm_password_reset', name='confirm_password_reset'),
url(r'^ajax/check_username/$', 'ajax_check_username', name='ajax_check_username'),
)

View file

@ -32,15 +32,28 @@
# Copyright The IETF Trust 2007, All Rights Reserved
import datetime
import hashlib
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render_to_response
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, HttpResponse
from django.contrib.auth import REDIRECT_FIELD_NAME, authenticate, login
from django.contrib.auth.models import User
from django.conf import settings
from django.utils.http import urlquote
from django.contrib.auth.models import User
from django.utils import simplejson as json
from django.utils.translation import ugettext as _
from forms import (RegistrationForm, PasswordForm, RecoverPasswordForm)
def index(request):
return render_to_response('registration/index.html', context_instance=RequestContext(request))
def url_login(request, user, passwd):
user = authenticate(username=user, password=passwd)
redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
@ -70,3 +83,82 @@ def ietf_loggedin(request):
@login_required
def profile(request):
return render_to_response('registration/profile.html', context_instance=RequestContext(request))
def create_account(request):
success = False
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
success = True
else:
form = RegistrationForm()
return render_to_response('registration/create.html',
{'form': form,
'success': success},
context_instance=RequestContext(request))
def confirm_account(request, username, date, realm, registration_hash):
valid = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, date, username, realm)).hexdigest() == registration_hash
if not valid:
raise Http404
request_date = datetime.date(int(date[:4]), int(date[4:6]), int(date[6:]))
if datetime.date.today() > (request_date + datetime.timedelta(days=settings.DAYS_TO_EXPIRE_REGISTRATION_LINK)):
raise Http404
success = False
if request.method == 'POST':
form = PasswordForm(request.POST, username=username)
if form.is_valid():
form.save()
# TODO: Add the user in the htdigest file
success = True
else:
form = PasswordForm(username=username)
return render_to_response('registration/confirm.html',
{'form': form, 'email': username, 'success': success},
context_instance=RequestContext(request))
def password_reset_view(request):
success = False
if request.method == 'POST':
form = RecoverPasswordForm(request.POST)
if form.is_valid():
form.save()
success = True
else:
form = RecoverPasswordForm()
return render_to_response('registration/password_reset.html',
{'form': form,
'success': success},
context_instance=RequestContext(request))
def confirm_password_reset(request, username, date, realm, reset_hash):
valid = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, date, username, realm)).hexdigest() == reset_hash
if not valid:
raise Http404
success = False
if request.method == 'POST':
form = PasswordForm(request.POST, update_user=True, username=username)
if form.is_valid():
form.save()
# TODO: Update the user in the htdigest file
success = True
else:
form = PasswordForm(username=username)
return render_to_response('registration/change_password.html',
{'form': form,
'success': success,
'username': username},
context_instance=RequestContext(request))
def ajax_check_username(request):
username = request.GET.get('username', '')
error = False
if User.objects.filter(username=username).count():
error = _('This email is already in use')
return HttpResponse(simplejson.dumps({'error': error}), mimetype='text/plain')

View file

@ -229,6 +229,11 @@ MAX_DAILY_SUBMISSION = 1000
MAX_DAILY_SUBMISSION_SIZE = 2000
# End of ID Submission Tool settings
# Account settings
DAYS_TO_EXPIRE_REGISTRATION_LINK = 3
HTPASSWD_COMMAND = "/usr/bin/htpasswd2"
HTPASSWD_FILE = "/www/htpasswd"
# Put SECRET_KEY in here, or any other sensitive or site-specific
# changes. DO NOT commit settings_local.py to svn.
from settings_local import *

View file

@ -35,6 +35,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% load wg_menu %}
{% load ietf_filters %}
<ul>
<li class="sect first">Accounts</li>
<li><a href="{% url account_index %}">New Account</a></li>
{% if user|in_group:"Area_Director" %}
<li class="sect first">AD Dashboard</li>
<li><a href="{% url doc_search_by_ad name=user.get_profile.person.full_name_as_key %}">My Documents</a></li>