fix: remove no longer needed htpasswd infrastructure (#7590)
This commit is contained in:
parent
a1902cfeca
commit
704f9967fd
|
@ -1,30 +0,0 @@
|
|||
# Copyright The IETF Trust 2016-2020, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import io
|
||||
import subprocess, hashlib
|
||||
from django.utils.encoding import force_bytes
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
def update_htpasswd_file(username, password):
|
||||
if getattr(settings, 'USE_PYTHON_HTDIGEST', None):
|
||||
pass_file = settings.HTPASSWD_FILE
|
||||
realm = settings.HTDIGEST_REALM
|
||||
prefix = force_bytes('%s:%s:' % (username, realm))
|
||||
key = force_bytes(hashlib.md5(prefix + force_bytes(password)).hexdigest())
|
||||
f = io.open(pass_file, 'r+b')
|
||||
pos = f.tell()
|
||||
line = f.readline()
|
||||
while line:
|
||||
if line.startswith(prefix):
|
||||
break
|
||||
pos=f.tell()
|
||||
line = f.readline()
|
||||
f.seek(pos)
|
||||
f.write(b'%s%s\n' % (prefix, key))
|
||||
f.close()
|
||||
else:
|
||||
p = subprocess.Popen([settings.HTPASSWD_COMMAND, "-b", settings.HTPASSWD_FILE, username, password], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
|
@ -3,13 +3,10 @@
|
|||
|
||||
|
||||
import datetime
|
||||
import io
|
||||
import logging # pyflakes:ignore
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
import requests_mock
|
||||
import shutil
|
||||
import time
|
||||
import urllib
|
||||
|
||||
|
@ -21,7 +18,6 @@ from oic.oic.message import RegistrationResponse, AuthorizationResponse
|
|||
from oic.utils.authn.client import CLIENT_AUTHN_METHOD
|
||||
from oidc_provider.models import RSAKey
|
||||
from pyquery import PyQuery
|
||||
from unittest import skipIf
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
import django.core.signing
|
||||
|
@ -35,7 +31,6 @@ import debug # pyflakes:ignore
|
|||
|
||||
from ietf.group.factories import GroupFactory, RoleFactory
|
||||
from ietf.group.models import Group, Role, RoleName
|
||||
from ietf.ietfauth.htpasswd import update_htpasswd_file
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.meeting.factories import MeetingFactory
|
||||
from ietf.nomcom.factories import NomComFactory
|
||||
|
@ -45,41 +40,12 @@ from ietf.person.tasks import send_apikey_usage_emails_task
|
|||
from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory
|
||||
from ietf.review.models import ReviewWish, UnavailablePeriod
|
||||
from ietf.stats.models import MeetingRegistration
|
||||
from ietf.utils.decorators import skip_coverage
|
||||
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
|
||||
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
|
||||
from ietf.utils.timezone import date_today
|
||||
|
||||
|
||||
if os.path.exists(settings.HTPASSWD_COMMAND):
|
||||
skip_htpasswd_command = False
|
||||
skip_message = ""
|
||||
else:
|
||||
skip_htpasswd_command = True
|
||||
skip_message = ("Skipping htpasswd test: The binary for htpasswd wasn't found in the\n "
|
||||
"location indicated in settings.py.")
|
||||
print(" "+skip_message)
|
||||
|
||||
class IetfAuthTests(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.saved_use_python_htdigest = getattr(settings, "USE_PYTHON_HTDIGEST", None)
|
||||
settings.USE_PYTHON_HTDIGEST = True
|
||||
|
||||
self.saved_htpasswd_file = settings.HTPASSWD_FILE
|
||||
self.htpasswd_dir = self.tempdir('htpasswd')
|
||||
settings.HTPASSWD_FILE = os.path.join(self.htpasswd_dir, "htpasswd")
|
||||
io.open(settings.HTPASSWD_FILE, 'a').close() # create empty file
|
||||
|
||||
self.saved_htdigest_realm = getattr(settings, "HTDIGEST_REALM", None)
|
||||
settings.HTDIGEST_REALM = "test-realm"
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.htpasswd_dir)
|
||||
settings.USE_PYTHON_HTDIGEST = self.saved_use_python_htdigest
|
||||
settings.HTPASSWD_FILE = self.saved_htpasswd_file
|
||||
settings.HTDIGEST_REALM = self.saved_htdigest_realm
|
||||
super().tearDown()
|
||||
|
||||
def test_index(self):
|
||||
self.assertEqual(self.client.get(urlreverse("ietf.ietfauth.views.index")).status_code, 200)
|
||||
|
@ -162,15 +128,6 @@ class IetfAuthTests(TestCase):
|
|||
|
||||
return confirm_url
|
||||
|
||||
def username_in_htpasswd_file(self, username):
|
||||
with io.open(settings.HTPASSWD_FILE) as f:
|
||||
for l in f:
|
||||
if l.startswith(username + ":"):
|
||||
return True
|
||||
with io.open(settings.HTPASSWD_FILE) as f:
|
||||
print(f.read())
|
||||
|
||||
return False
|
||||
|
||||
# For the lowered barrier to account creation period, we are disabling this kind of failure
|
||||
# def test_create_account_failure(self):
|
||||
|
@ -223,8 +180,6 @@ class IetfAuthTests(TestCase):
|
|||
self.assertEqual(Person.objects.filter(user__username=email).count(), 1)
|
||||
self.assertEqual(Email.objects.filter(person__user__username=email).count(), 1)
|
||||
|
||||
self.assertTrue(self.username_in_htpasswd_file(email))
|
||||
|
||||
|
||||
# This also tests new account creation.
|
||||
def test_create_existing_account(self):
|
||||
|
@ -490,7 +445,6 @@ class IetfAuthTests(TestCase):
|
|||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q("form .is-invalid")), 0)
|
||||
self.assertTrue(self.username_in_htpasswd_file(user.username))
|
||||
|
||||
# reuse reset url
|
||||
r = self.client.get(confirm_url)
|
||||
|
@ -614,23 +568,6 @@ class IetfAuthTests(TestCase):
|
|||
self.assertEqual(r.status_code, 302)
|
||||
self.assertEqual(ReviewWish.objects.filter(doc=doc, team=review_req.team).count(), 0)
|
||||
|
||||
def test_htpasswd_file_with_python(self):
|
||||
# make sure we test both Python and call-out to binary
|
||||
settings.USE_PYTHON_HTDIGEST = True
|
||||
|
||||
update_htpasswd_file("foo", "passwd")
|
||||
self.assertTrue(self.username_in_htpasswd_file("foo"))
|
||||
|
||||
@skipIf(skip_htpasswd_command, skip_message)
|
||||
@skip_coverage
|
||||
def test_htpasswd_file_with_htpasswd_binary(self):
|
||||
# make sure we test both Python and call-out to binary
|
||||
settings.USE_PYTHON_HTDIGEST = False
|
||||
|
||||
update_htpasswd_file("foo", "passwd")
|
||||
self.assertTrue(self.username_in_htpasswd_file("foo"))
|
||||
|
||||
|
||||
def test_change_password(self):
|
||||
chpw_url = urlreverse("ietf.ietfauth.views.change_password")
|
||||
prof_url = urlreverse("ietf.ietfauth.views.profile")
|
||||
|
|
|
@ -65,7 +65,6 @@ from ietf.group.models import Role, Group
|
|||
from ietf.ietfauth.forms import ( RegistrationForm, PasswordForm, ResetPasswordForm, TestEmailForm,
|
||||
ChangePasswordForm, get_person_form, RoleEmailForm,
|
||||
NewEmailForm, ChangeUsernameForm, PersonPasswordForm)
|
||||
from ietf.ietfauth.htpasswd import update_htpasswd_file
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.name.models import ExtResourceName
|
||||
from ietf.nomcom.models import NomCom
|
||||
|
@ -222,8 +221,6 @@ def confirm_account(request, auth):
|
|||
user = User.objects.create(username=email, email=email)
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
# password is also stored in htpasswd file
|
||||
update_htpasswd_file(email, password)
|
||||
|
||||
# make sure the rest of the person infrastructure is
|
||||
# well-connected
|
||||
|
@ -552,8 +549,6 @@ def confirm_password_reset(request, auth):
|
|||
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
# password is also stored in htpasswd file
|
||||
update_htpasswd_file(user.username, password)
|
||||
|
||||
success = True
|
||||
else:
|
||||
|
@ -693,8 +688,6 @@ def change_password(request):
|
|||
|
||||
user.set_password(new_password)
|
||||
user.save()
|
||||
# password is also stored in htpasswd file
|
||||
update_htpasswd_file(user.username, new_password)
|
||||
# keep the session
|
||||
update_session_auth_hash(request, user)
|
||||
|
||||
|
@ -731,13 +724,10 @@ def change_username(request):
|
|||
form = ChangeUsernameForm(user, request.POST)
|
||||
if form.is_valid():
|
||||
new_username = form.cleaned_data["username"]
|
||||
password = form.cleaned_data["password"]
|
||||
assert new_username in emails
|
||||
|
||||
user.username = new_username.lower()
|
||||
user.save()
|
||||
# password is also stored in htpasswd file
|
||||
update_htpasswd_file(user.username, password)
|
||||
# keep the session
|
||||
update_session_auth_hash(request, user)
|
||||
|
||||
|
|
|
@ -979,8 +979,6 @@ DE_GFM_BINARY = '/usr/bin/de-gfm.ruby2.5'
|
|||
# Account settings
|
||||
DAYS_TO_EXPIRE_REGISTRATION_LINK = 3
|
||||
MINUTES_TO_EXPIRE_RESET_PASSWORD_LINK = 60
|
||||
HTPASSWD_COMMAND = "/usr/bin/htpasswd"
|
||||
HTPASSWD_FILE = "/a/www/htpasswd"
|
||||
|
||||
# Generation of pdf files
|
||||
GHOSTSCRIPT_COMMAND = "/usr/bin/gs"
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
# Copyright The IETF Trust 2014-2020, All Rights Reserved
|
||||
import io
|
||||
import sys
|
||||
|
||||
from textwrap import dedent
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
def import_htpasswd_file(filename, verbosity=1, overwrite=False):
|
||||
with io.open(filename) as file:
|
||||
for line in file:
|
||||
if not ':' in line:
|
||||
raise ValueError('Found a line without colon separator in the htpassword file %s:'
|
||||
' "%s"' % (file.name, line))
|
||||
username, password = line.strip().split(':', 1)
|
||||
try:
|
||||
user = User.objects.get(username__iexact=username)
|
||||
if overwrite == True or not user.password:
|
||||
if password.startswith('{SHA}'):
|
||||
user.password = "sha1$$%s" % password[len('{SHA}'):]
|
||||
elif password.startswith('$apr1$'):
|
||||
user.password = "md5$%s" % password[len('$apr1$'):]
|
||||
else: # Assume crypt
|
||||
user.password = "crypt$$%s" % password
|
||||
user.save()
|
||||
if verbosity > 0:
|
||||
sys.stderr.write('.')
|
||||
if verbosity > 1:
|
||||
sys.stderr.write(' %s\n' % username)
|
||||
except User.DoesNotExist:
|
||||
if verbosity > 1:
|
||||
sys.stderr.write('\nNo such user: %s\n' % username)
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
Import passwords from one or more htpasswd files to Django's auth_user table.
|
||||
|
||||
This command only imports passwords; it does not import usernames, as that
|
||||
would leave usernames without associated Person records in the database,
|
||||
something which is undesirable.
|
||||
|
||||
By default the command won't overwrite existing password entries, but
|
||||
given the --force switch, it will overwrite existing entries too. Without
|
||||
the --force switch, the command is safe to run repeatedly.
|
||||
"""
|
||||
|
||||
help = dedent(__doc__).strip()
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--force',
|
||||
action='store_true', dest='overwrite', default=False,
|
||||
help='Overwrite existing passwords in the auth_user table.')
|
||||
|
||||
|
||||
args = '[path [path [...]]]'
|
||||
|
||||
def handle(self, *filenames, **options):
|
||||
overwrite = options.get('overwrite', False)
|
||||
verbosity = int(options.get('verbosity'))
|
||||
for fn in filenames:
|
||||
import_htpasswd_file(fn, verbosity=verbosity, overwrite=overwrite)
|
||||
|
Loading…
Reference in a new issue