source: main/waeup.kofa/trunk/src/waeup/kofa/kpasswd.py @ 17863

Last change on this file since 17863 was 17820, checked in by uli, 6 months ago

Add kpasswd for generating/setting kofa passwords.

File size: 3.3 KB
Line 
1#!/usr/bin/env python
2#
3# kpasswd.py
4#
5# Set password for kofa instances.
6#
7# (c) 2024 WAeUP Germany
8# Licensed under AGPL 3.0 or newer
9#
10# This script sets the username and password for a principal of a `kofa`
11# instance.
12#
13#    $ python kpasswd.py -l foo -c parts/etc/site.zcml not-secret
14#
15# sets the credentials for the superuser principal (`zope.manager`) to `foo`
16# (username) and `not-scret` (password). The given site.zcml will be updated
17# accordingly.
18#
19# Not giving a site.zcml path will print the hashed form of the given password:
20#
21#    $ python kpasswd.py also-not-secret
22#    {SSHA}EkqqJb8opEe1QxhETB57Ps2O62HS63Vu
23#
24from __future__ import print_function
25import argparse
26import os
27import sys
28import xml.etree.ElementTree as ET
29from zope.password.password import managers as ZOPE_PW_MANAGERS
30
31
32def parse_args(argv):
33    p = argparse.ArgumentParser(description=(
34        "Set kofa password. If path to local `site.zcml` is given, also "
35        "updates this file. If not, the hashed password is displayed and "
36        "can be set manually in `site.zcml`"))
37    p.add_argument("password", nargs=1, help="Password to set")
38    p.add_argument(
39        "-c",
40        "--config",
41        help=(
42            "path to the site.zcml configuration file (optional). If "
43            "given, the respective file will be modified. Otherwise "
44            "the hashed password is displayed on stdout."
45        ),
46    )
47    p.add_argument(
48        "--id",
49        help=(
50            "Principal id found in site.zcml. `zope.manager? by default. "
51            "Only considered if a config file was given."
52        ),
53        default="zope.manager",
54    )
55    p.add_argument(
56        "-l",
57        "--login",
58        help=(
59            "Principal login name. `grok` by default. Only considered if a "
60            "config file was given."
61        ),
62        default="grok",
63    )
64    options = p.parse_args(argv[1:])
65    return options
66
67
68def main(argv=None):
69    if argv is None:
70        argv = sys.argv
71    try:
72        options = parse_args(argv)
73        app = Application(options)
74        app.run()
75    except SystemExit as e:
76        if e.code:
77            return 2
78    return 0
79
80
81class Application(object):
82    def __init__(self, options):
83        self.options = options
84
85    def run(self):
86        hashed = self.get_hashed_password(self.options.password[0]).decode("utf-8")
87        if self.options.config is None:
88            print(hashed)
89            return
90        path = os.path.abspath(self.options.config)
91        xmltree = ET.parse(path).getroot()
92        doc = open(path).read()
93        for entry in xmltree.iter("{http://namespaces.zope.org/zope}principal"):
94            if entry.get("id") != self.options.id:
95                continue
96            # Replace hashed password with new value
97            doc = doc.replace(entry.get("password"), hashed)
98            # Replace old login (username) with new one
99            doc = doc.replace(
100                'login="%s"' % entry.get("login"), 'login="%s"' % self.options.login
101            )
102        # Create a backup of the file we are going to modify
103        os.rename(path, path + ".bak")
104        with open(path, "w") as fd:
105            fd.write(doc)
106        print("Updated: %s" % path)
107
108    def get_hashed_password(self, password, salt=None):
109        manager = dict(ZOPE_PW_MANAGERS)["SSHA"]
110        return manager.encodePassword(password, salt)
Note: See TracBrowser for help on using the repository browser.