rewrite index.py to work with ldap

This commit is contained in:
Christoph Loesch 2021-04-11 05:16:42 +02:00 committed by GitHub
parent 34a5b48314
commit 42279bbcfa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -2,12 +2,15 @@
import cgi, cgitb import cgi, cgitb
import re import re
import sys, os import sys, os
from subprocess import check_output, Popen, PIPE, STDOUT, CalledProcessError import ldap
from os.path import expanduser
ldap_proto = 'ldap://'
ldap_server = 'localhost'
ldap_basedn = 'dc=ldap,dc=freiesnetz,dc=at'
ldap_userdn = 'ou=Users' +','+ ldap_basedn
cgitb.enable(display=0, logdir='logs/')
cgitb.enable()
home_dir = expanduser("~")
os.environ['HOME'] = home_dir
def check_form(formvars, form): def check_form(formvars, form):
for varname in formvars: for varname in formvars:
@ -18,6 +21,7 @@ def check_form(formvars, form):
return None return None
return True return True
def read_template_file(filename, **vars): def read_template_file(filename, **vars):
with open('tpl/' + filename, mode='r', encoding='utf-8') as f: with open('tpl/' + filename, mode='r', encoding='utf-8') as f:
template = f.read() template = f.read()
@ -25,38 +29,30 @@ def read_template_file(filename, **vars):
template = template.replace('{$' + key + '}', vars[key]) template = template.replace('{$' + key + '}', vars[key])
return template return template
def check_oldpw(accountname, oldpass): def check_oldpw(accountname, oldpass):
try: try:
dumpvuserargs = ['dumpvuser', accountname] conn = ldap.initialize(ldap_proto+ldap_server)
userdump = check_output(dumpvuserargs).strip().decode('utf-8') conn.set_option(ldap.OPT_REFERRALS, 0)
m = re.search('Encrypted-Password: (\$([^\$]+)\$([^\$]+)\$([^\$\n]+))', userdump) conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
if None == m: if conn.simple_bind("uid="+accountname+","+ldap_userdn, oldpass) == True:
return False
oldhash = m.group(1)
hashtype = m.group(2)
salt = m.group(3)
except CalledProcessError:
return False
opensslargs = ['openssl', 'passwd', '-' + hashtype, '-salt', salt, '-stdin']
p = Popen(opensslargs, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
p.stdin.write(oldpass.encode('utf-8') + b'\n')
p.stdin.close()
if p.wait() == 0:
newhash = p.stdout.readline().strip().decode('utf-8');
if newhash == oldhash:
return True return True
except ldap.INVALID_CREDENTIALS:
conn.unbind()
return False
return False return False
def generate_headers(): def generate_headers():
return "Content-Type: text/html; charset=utf-8\n" return "Content-Type: text/html; charset=utf-8\n"
def main(): def main():
main_content = '' main_content = ''
form = cgi.FieldStorage() form = cgi.FieldStorage()
debug_content = str(form)
if 'submit' in form.keys(): if 'submit' in form.keys():
formvars = ['accountname', 'oldpass', 'newpass', 'newpass2'] formvars = ['accountname', 'oldpass', 'newpass', 'newpass2']
form_ok = check_form(formvars, form) form_ok = check_form(formvars, form)
@ -68,16 +64,30 @@ def main():
newpass2 = form['newpass2'].value newpass2 = form['newpass2'].value
if newpass == newpass2: if newpass == newpass2:
if check_oldpw(accountname, oldpass): if check_oldpw(accountname, oldpass):
vpasswdargs = ['vpasswd', accountname] conn = ldap.initialize(ldap_proto+ldap_server)
p = Popen(vpasswdargs, stdin=PIPE, stdout=PIPE, stderr=STDOUT) conn.set_option(ldap.OPT_REFERRALS, 0)
p.stdin.write(newpass.encode('utf-8') + b'\n') conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
p.stdin.write(newpass2.encode('utf-8') + b'\n') conn.simple_bind(accountname, oldpass)
p.stdin.close() results = conn.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, "(uid="+accountname+")", ["dn"])
if p.wait() == 0: conn.unbind()
for dn in results:
conn = ldap.initialize(ldap_proto+ldap_server)
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
# do a synchronous ldap bind
conn.simple_bind_s(dn[0], oldpass)
conn.passwd_s(dn[0], oldpass, newpass)
conn.unbind_s()
conn = ldap.initialize(ldap_proto+ldap_server)
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
if conn.simple_bind(accountname, newpass) == True:
# We did it # We did it
conn.unbind()
main_content = read_template_file('success.tpl') main_content = read_template_file('success.tpl')
else: else:
main_content = read_template_file('fail.tpl', message=cgi.escape(p.stdout.read())) conn.unbind()
main_content = read_template_file('fail.tpl', message=cgi.escape(ldap.LDAPError))
else: else:
main_content = read_template_file('fail.tpl', message='User not found or wrong password entered.') main_content = read_template_file('fail.tpl', message='User not found or wrong password entered.')
else: else:
@ -87,15 +97,17 @@ def main():
else: else:
main_content = read_template_file('fail.tpl', message='Invalid data type supplied.') main_content = read_template_file('fail.tpl', message='Invalid data type supplied.')
else: else:
# Submit button not pressed, show form
formaction = cgi.escape("https://" + os.environ["HTTP_HOST"] + os.environ["REQUEST_URI"]) formaction = cgi.escape("https://" + os.environ["HTTP_HOST"] + os.environ["REQUEST_URI"])
form = read_template_file('form.tpl', formaction=formaction) #accountname = os.environ.get('REMOTE_USER')
accountname = os.environ.get('AUTHENTICATE_UID')
http_host = os.environ.get('HTTP_HOST')
form = read_template_file('form.tpl', formaction=formaction, accountname=accountname, http_host=http_host)
main_content = form main_content = form
response = generate_headers() + "\n" response = generate_headers() + "\n"
response += read_template_file('main.tpl', main_content=main_content) response += read_template_file('main.tpl', main_content=main_content, debug_content=debug_content)
sys.stdout.buffer.write(response.encode('utf-8')) sys.stdout.buffer.write(response.encode('utf-8'))
if __name__ == "__main__": if __name__ == "__main__":
main() main()