From 84fca9ad2177516032e08b998818607ce38beabb Mon Sep 17 00:00:00 2001 From: Dave Disser Date: Sun, 26 Nov 2023 13:15:33 -0800 Subject: [PATCH] Add `password` option to `server.user` (#1040) Co-authored-by: Nick Mills-Barrett --- pyinfra/facts/server.py | 7 +++-- pyinfra/operations/server.py | 13 ++++++++- tests/facts/server.Users/mixed.json | 37 +++++++++++++++----------- tests/operations/server.user/add.json | 5 ++-- tests/operations/server.user/edit.json | 3 ++- 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/pyinfra/facts/server.py b/pyinfra/facts/server.py index 0de3a5f1a..fc91a8e59 100644 --- a/pyinfra/facts/server.py +++ b/pyinfra/facts/server.py @@ -417,6 +417,7 @@ class Users(FactBase): "uid": user_id, "gid": main_user_group_id, "lastlog": last_login_time, + "password": encrypted_password, }, } """ @@ -426,7 +427,8 @@ class Users(FactBase): ENTRY=`grep ^$i: /etc/passwd`; LASTLOG_RAW=`(lastlog -u $i 2> /dev/null || lastlogin $i 2> /dev/null)`; LASTLOG=`echo $LASTLOG_RAW | grep ^$i | tr -s ' '`; - echo "$ENTRY|`id -gn $i`|`id -Gn $i`|$LASTLOG"; + PASSWORD=`grep ^$i: /etc/shadow | cut -d: -f2`; + echo "$ENTRY|`id -gn $i`|`id -Gn $i`|$LASTLOG|$PASSWORD"; done """.strip() @@ -437,7 +439,7 @@ def process(self, output): rex = r"[A-Z][a-z]{2} [A-Z][a-z]{2} {1,2}\d+ .+$" for line in output: - entry, group, user_groups, lastlog = line.split("|") + entry, group, user_groups, lastlog, password = line.split("|") if entry: # Parse out the comment/home/shell @@ -470,6 +472,7 @@ def process(self, output): "gid": int(entries[3]), "lastlog": raw_login_time, "login_time": login_time, + "password": password, } return users diff --git a/pyinfra/operations/server.py b/pyinfra/operations/server.py index 5a903c335..9264dd8b6 100644 --- a/pyinfra/operations/server.py +++ b/pyinfra/operations/server.py @@ -947,6 +947,7 @@ def user( comment=None, add_deploy_dir=True, unique=True, + password=None, ): """ Add/remove/update system users & their ssh `authorized_keys`. @@ -966,6 +967,7 @@ def user( + comment: the user GECOS comment + add_deploy_dir: any public_key filenames are relative to the deploy directory + unique: prevent creating users with duplicate UID + + password: set the encrypted password for the user Home directory: When ``ensure_home`` or ``public_keys`` are provided, ``home`` defaults to @@ -1064,6 +1066,9 @@ def user( if create_home: args.append("-m") + if password: + args.append("-p '{0}'".format(password)) + # Users are often added by other operations (package installs), so check # for the user at runtime before adding. @@ -1087,9 +1092,10 @@ def user( "shell": shell, "group": group, "groups": groups, + "password": password, } - # User exists and we want them, check home/shell/keys + # User exists and we want them, check home/shell/keys/password else: args = [] @@ -1112,6 +1118,9 @@ def user( if comment and existing_user["comment"] != comment: args.append("-c '{0}'".format(comment)) + if password and existing_user["password"] != password: + args.append("-p '{0}'".format(password)) + # Need to mod the user? if args: if os_type == "FreeBSD": @@ -1128,6 +1137,8 @@ def user( existing_user["group"] = group if groups: existing_user["groups"] = groups + if password: + existing_user["password"] = password # Ensure home directory ownership if ensure_home: diff --git a/tests/facts/server.Users/mixed.json b/tests/facts/server.Users/mixed.json index 5dce7da4f..a156cc82b 100644 --- a/tests/facts/server.Users/mixed.json +++ b/tests/facts/server.Users/mixed.json @@ -1,14 +1,14 @@ { "output": [ - "root:x:0:0:root:/root:/bin/ks|wheel|wheel kmem sys tty operator staff guest|root pts/0 Sat Jun 5 12:03:23 -0600 2021", - "_tesTy.test:x:1004:1004::/home/_tesTy.test:/bin/ksh|_tesTy.test|_tesTy.test pyinfra|_tesTy.test pts/0 host-ip Sat Jun 12 13:43:42 -0600 2021", - "test.testy:x:1003:1003:Testy,,,:/home/test.testy:/bin/ksh|test.testy||test.testy Fri Jun 11 22:26:04 -0600 2021", - "noshell:x:1002:1002:noshell comment with spaces:/home/noshell:|noshell||noshell **Never logged in**", - "nohome:x:1002:1002:nohome comment::/bin/bash|nohome||**Never logged in**", - "freebsd:*:1001:1001:FreeBSD:/home/freebsd:/bin/sh|freebsd|freebsd|freebsd pts/0 10.1.10.10 Thu Aug 31 05:37:58 2023", - "freebsdnologin:*:1001:1001:FreeBSD NoLogin:/home/freebsdnologin:/bin/sh|freebsdnologin|freebsdnologin|" + "root:x:0:0:root:/root:/bin/ks|wheel|wheel kmem sys tty operator staff guest|root pts/0 Sat Jun 5 12:03:23 -0600 2021|$rootpw$", + "_tesTy.test:x:1004:1004::/home/_tesTy.test:/bin/ksh|_tesTy.test|_tesTy.test pyinfra|_tesTy.test pts/0 host-ip Sat Jun 12 13:43:42 -0600 2021|$testpw$", + "test.testy:x:1003:1003:Testy,,,:/home/test.testy:/bin/ksh|test.testy||test.testy Fri Jun 11 22:26:04 -0600 2021|$testpw$", + "noshell:x:1002:1002:noshell comment with spaces:/home/noshell:|noshell||noshell **Never logged in**|", + "nohome:x:1002:1002:nohome comment::/bin/bash|nohome||**Never logged in**|", + "freebsd:*:1001:1001:FreeBSD:/home/freebsd:/bin/sh|freebsd|freebsd|freebsd pts/0 10.1.10.10 Thu Aug 31 05:37:58 2023|$bsdpw$", + "freebsdnologin:*:1001:1001:FreeBSD NoLogin:/home/freebsdnologin:/bin/sh|freebsdnologin|freebsdnologin||" ], - "command": "for i in `cat /etc/passwd | cut -d: -f1`; do\n ENTRY=`grep ^$i: /etc/passwd`;\n LASTLOG_RAW=`(lastlog -u $i 2> /dev/null || lastlogin $i 2> /dev/null)`;\n LASTLOG=`echo $LASTLOG_RAW | grep ^$i | tr -s ' '`;\n echo \"$ENTRY|`id -gn $i`|`id -Gn $i`|$LASTLOG\";\n done", + "command": "for i in `cat /etc/passwd | cut -d: -f1`; do\n ENTRY=`grep ^$i: /etc/passwd`;\n LASTLOG_RAW=`(lastlog -u $i 2> /dev/null || lastlogin $i 2> /dev/null)`;\n LASTLOG=`echo $LASTLOG_RAW | grep ^$i | tr -s ' '`;\n PASSWORD=`grep ^$i: /etc/shadow | cut -d: -f2`;\n echo \"$ENTRY|`id -gn $i`|`id -Gn $i`|$LASTLOG|$PASSWORD\";\n done", "fact": { "root": { "home": "/root", @@ -26,7 +26,8 @@ "uid": 0, "gid": 0, "lastlog": "Sat Jun 5 12:03:23 -0600 2021", - "login_time": "2021-06-05T12:03:23-06:00" + "login_time": "2021-06-05T12:03:23-06:00", + "password": "$rootpw$" }, "_tesTy.test": { "home": "/home/_tesTy.test", @@ -39,7 +40,8 @@ "uid": 1004, "gid": 1004, "lastlog": "Sat Jun 12 13:43:42 -0600 2021", - "login_time": "2021-06-12T13:43:42-06:00" + "login_time": "2021-06-12T13:43:42-06:00", + "password": "$testpw$" }, "test.testy": { "home": "/home/test.testy", @@ -50,7 +52,8 @@ "uid": 1003, "gid": 1003, "lastlog": "Fri Jun 11 22:26:04 -0600 2021", - "login_time": "2021-06-11T22:26:04-06:00" + "login_time": "2021-06-11T22:26:04-06:00", + "password": "$testpw$" }, "noshell": { "home": "/home/noshell", @@ -61,7 +64,8 @@ "uid": 1002, "gid": 1002, "lastlog": null, - "login_time": null + "login_time": null, + "password": "" }, "nohome": { "home": null, @@ -72,7 +76,8 @@ "uid": 1002, "gid": 1002, "lastlog": null, - "login_time": null + "login_time": null, + "password": "" }, "freebsd": { "home": "/home/freebsd", @@ -83,7 +88,8 @@ "uid": 1001, "gid": 1001, "lastlog": "Thu Aug 31 05:37:58 2023", - "login_time": "2023-08-31T05:37:58" + "login_time": "2023-08-31T05:37:58", + "password": "$bsdpw$" }, "freebsdnologin": { "home": "/home/freebsdnologin", @@ -94,7 +100,8 @@ "uid": 1001, "gid": 1001, "lastlog": null, - "login_time": null + "login_time": null, + "password": "" } } } \ No newline at end of file diff --git a/tests/operations/server.user/add.json b/tests/operations/server.user/add.json index f6e00c767..efae20195 100644 --- a/tests/operations/server.user/add.json +++ b/tests/operations/server.user/add.json @@ -8,7 +8,8 @@ "uid" : 1000, "system": true, "comment": "Full Name", - "create_home": true + "create_home": true, + "password": "$somecryptedpassword$" }, "facts": { "server.Os": "Linux", @@ -20,7 +21,7 @@ "server.Os": "Linux" }, "commands": [ - "grep '^someuser:' /etc/passwd || useradd -d homedir -s shellbin -g mygroup -G secondary_group,another -r --uid 1000 -c 'Full Name' -m someuser", + "grep '^someuser:' /etc/passwd || useradd -d homedir -s shellbin -g mygroup -G secondary_group,another -r --uid 1000 -c 'Full Name' -m -p '$somecryptedpassword$' someuser", "mkdir -p homedir", "chown someuser:mygroup homedir" ] diff --git a/tests/operations/server.user/edit.json b/tests/operations/server.user/edit.json index c4d21270e..7641d6f78 100644 --- a/tests/operations/server.user/edit.json +++ b/tests/operations/server.user/edit.json @@ -17,7 +17,8 @@ "group": "nowt", "groups": [ "group1", "group2" - ] + ], + "password": "$somepw$" } }, "files.Directory": {