initial commit

master
vuko 2021-05-05 21:08:08 +02:00
commit 756f6cbe66
8 changed files with 234 additions and 0 deletions

2
README.rst Normal file
View File

@ -0,0 +1,2 @@
Command line tool for managing user accounts at Warsaw Hackerspace. For now only
password reset is implemented.

3
build.nix Normal file
View File

@ -0,0 +1,3 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.python3Packages.callPackage (import ./default.nix) {}

16
default.nix Normal file
View File

@ -0,0 +1,16 @@
{ buildPythonPackage, setuptools, jinja2, ldap3, apg, callPackage }:
let
python-kadmin = callPackage (import ./python-kadmin.nix) {};
in buildPythonPackage rec {
pname = "hs-admin-${version}";
version = "0.0.1";
propagatedBuildInputs = [
python-kadmin
setuptools
jinja2
ldap3
apg
];
src = ./.;
}

145
hsadmin/cmd.py Normal file
View File

@ -0,0 +1,145 @@
import os
from pkg_resources import resource_filename, cleanup_resources, resource_string
import atexit
from pathlib import Path
atexit.register(cleanup_resources, force=True)
os.environ["KRB5_CONFIG"] = str(
Path(resource_filename(__name__, "krb5.conf")).resolve()
)
import kadmin
import getpass
import argparse
import secrets
import string
import shutil
import logging
from ldap3 import Server, Connection, LEVEL
from ldap3.utils.conv import escape_filter_chars
from ldap3.utils.dn import escape_rdn
import subprocess
import smtplib
from jinja2 import Template
from email.message import EmailMessage
FROM_LDAP = object()
parser = argparse.ArgumentParser()
parser.add_argument("--admin", default=getpass.getuser())
parser.add_argument("--verbose", action="store_true")
subparsers = parser.add_subparsers(dest="cmd", help="command")
reset_password = subparsers.add_parser(
"reset_password",
help="change user password to newly generated one and send it to his email address from LDAP",
)
reset_password.add_argument("user")
reset_password.add_argument(
"--show-password", action="store_true", help="print generated password"
)
reset_password.add_argument("email_address", default=FROM_LDAP, nargs="?")
APG_CMD = shutil.which("apg")
def generage_password(length=15):
if APG_CMD is None:
logging.warning("apg command not found. Using built in password generator")
pool = string.ascii_lowercase + string.ascii_uppercase + string.digits
password = "".join([secrets.choice(pool) for _ in range(length)])
else:
password = (
subprocess.run(
[APG_CMD, "-m", str(length), "-n", "1", "-M", "NCL"],
check=True,
capture_output=True,
)
.stdout.decode()
.strip()
)
if len(password) != length:
raise Exception("Password generation failed")
return password
def main():
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
if args.cmd == "reset_password":
admin_pass = getpass.getpass(f"{args.admin}@HACKERSPACE.PL password: ")
logging.debug("initializing kadmin")
k = kadmin.init_with_password(f"{args.admin}/admin", admin_pass)
logging.debug("kadmin initialized")
user = args.user
if user is None:
user = input("User: ")
p = k.get_principal(user)
password = generage_password()
if args.email_address is not FROM_LDAP:
address = args.email_address
else:
address = get_email_address(args.admin, admin_pass, user)
if args.show_password:
print(f'password: "{password}"')
i = input(
f"Type yes to reset {user}'s password and send email to {address}\n"
).strip()
if i != "yes":
print("Aborted")
return
p.change_password(password)
print("password changed")
send_mail(args.admin, admin_pass, password, user, address)
print("email sent")
else:
parser.print_help()
def get_email_address(admin, admin_pass, uid):
logging.debug("fetching email address from LDAP")
s = Server("ldap.hackerspace.pl", use_ssl=True)
with Connection(
s,
user=f"uid={escape_rdn(admin)},ou=People,dc=hackerspace,dc=pl",
password=admin_pass,
raise_exceptions=True,
) as c:
logging.debug("connected to LDAP server")
c.search(
search_base="ou=People,dc=hackerspace,dc=pl",
search_filter=f"(uid={escape_filter_chars(uid)})",
search_scope=LEVEL,
attributes=["mailRoutingAddress"],
)
if not c.entries:
raise Exception("empty response")
if len(c.entries) > 1:
raise Exception("too many responses")
address = c.entries[0]["mailRoutingAddress"]
logging.debug(f"got mail address from LDAP: {address}")
return address
def send_mail(admin, admin_password, password, user, address):
mail_template = Template(
resource_string(__name__, "password_reset.jinja2").decode()
)
msg = EmailMessage()
config = {"password": password, "user": user, "admin": admin}
msg.set_content(mail_template.render(config))
msg["Subject"] = f"Password reset for {user}@hackerspace.pl"
msg["From"] = f"{admin}@hackerspace.pl"
msg["To"] = address
with smtplib.SMTP_SSL("mail.hackerspace.pl") as s:
s.login(admin, admin_password)
s.send_message(msg)

13
hsadmin/krb5.conf Normal file
View File

@ -0,0 +1,13 @@
[libdefaults]
default_realm = HACKERSPACE.PL
[realms]
HACKERSPACE.PL = {
admin_server = hackerspace.pl
kdc = kerberos.hackerspace.pl
default_domain = hackerspace.pl
sasl-realm = HACKERSPACE.PL
}
[domain_realm]
.hackerspace.pl = HACKERSPACE.PL
hackerspace.pl = HACKERSPACE.PL

View File

@ -0,0 +1,8 @@
Hi,
Password for your Warsaw Hackerspace account has been resetted.
user: {{ user }}
password: {{ password }}
You can change it here: https://profile.hackerspace.pl

24
python-kadmin.nix Normal file
View File

@ -0,0 +1,24 @@
{ buildPythonPackage, bison, krb5, fetchFromGitHub }:
buildPythonPackage rec {
pname = "python-kadmin-${version}";
version = "0.0.2";
nativeBuildInputs = [ bison ];
buildInputs = [ krb5 ];
src = fetchFromGitHub {
owner = "nightfly19";
repo = "python-kadmin";
#rev = "c1acec9d197b79e3f51928aad6df0f99e86283c2";
#sha256 = "0jb0k998624scy204im068kwhnwa2l6vag69qi3hnmlpr1q3wh0z";
rev = "31d25f734b926b71e15d4c2f3a2e68decf8a465b";
sha256 = "1vnmrd9sz08sr3nsg1n1rgwrqai802hba8gqybgabblbza4kg4x1";
};
preConfigure = ''
substituteInPlace setup.py --replace '["/usr/include/", "/usr/include/et/"]' '["${krb5.dev}/include"]'
'';
postInstall = ''
ln -s $src $out
'';
#doCheck=false;
doCheck=true;
}

23
setup.py Normal file
View File

@ -0,0 +1,23 @@
from setuptools import setup
setup(
name="hsadmin",
version="0.1",
description="Warsaw Hackerspace account managment cli",
author="vuko",
author_email="vuko@hackerspace.pl",
classifiers=[
"Development Status :: 3 - Alpha",
"License :: OSI Approved :: zlib/libpng License",
"Programming Language :: Python :: 3.8",
],
packages=["hsadmin"],
python_requires=">=3.8,",
install_requires=["kadmin", "setuptools", "jinja2", "ldap3"],
package_data={"hsadmin": ["krb5.conf", "password_reset.jinja2"]},
entry_points={
"console_scripts": [
"hs-admin=hsadmin.cmd:main",
]
},
)