Update for automated response around poorly behaving archlinux-keyring weekly timer; rename Sora role to Password

This commit is contained in:
2024-03-07 12:27:21 -06:00
parent 930441ae9a
commit e75d03a313
29 changed files with 360 additions and 64 deletions

134
roles/Password/README.md Normal file
View File

@@ -0,0 +1,134 @@
Sora is the [https://en.wikipedia.org/wiki/LDAP LDAP]-enabled central crendential store of the AniNIX -- end users will have accounts here.
# Etymology=Sora was the name of a pivotal character in the Kingdom of Hearts series. As Sora holds the "keys to the kingdom", the name fit.<!-- I've considered renaming this, but I'm kind of happy with it, even though I didn't follow the Kingdom of Hearts series. -->
# Relevant Files and Software
Most of the configuration initially is handled by the [https://aninix.net/foundation/ConfigPackages ConfigPackages'] Sora Makefile.
We use [file:///etc/openldap/users.d a users.d] folder to hold the default user definitions. uidNumber should generally start from 10000 and the .ldif files should never be deleted to track the maximum uidNumber.
# Available Clients
See [[:Category:LDAP]] for more information on the services that are clients of Sora.
# Equivalents or Competition
Both [[:Category:Google|Google]] and Facebook offer distributed authentication systems. Google in particular is a good equivalent, as some of the services used by this network rely on its authentication for various products it provides internally.
The AniNIX is not presently set up or planning to do distributed authentication.
}}
# Authorizing Other Services by Sora
## [[ShadowArch]] OS Authentication
You will need nss-pam-ldap as package installed. You will need to edit /etc/pam.d/su, /etc/pam.d/su-l, /etc/pam.d/system-auth, and /etc/nslcd.conf to match [https://eng.ucmerced.edu/soe/computing/services/ssh-based-service/ldap-ssh-access this link] and [https://wiki.archlinux.org/index.php/LDAP_authentication the Arch Wiki].
## [[Windows]] OS Authentication
We recommend the [https://pgina.org/ pGina] package -- this is a very smooth client.
## [[SSH]]
Edit /etc/ssh/sshd_config to allow PasswordAuthentication and PAM. This assumes the OS authentication is set up.
We recommend adding a passwdchange OS group on the external-facing SSH host and set up a ForceCommand around /usr/bin/passwd for users in that group. This allows you to enable centralized password changes from outside the command line for subscribing clients and then disable password changes in individual services.
## [[IRC|IRCServices]]
You will need to enable m_ldap and m_ldap_authentication in [file:///etc/anope/modules.aninix.conf the modules conf file]. The modules conf has the necessary parameters waiting to be filled in. We recommend updating the search_filter to "(&(!(shadowLastChange=0))(&(uid=%account)(objectClass=%object_class)))". This will prevent users from using a password reset by an administrator.
When you enable LDAP for IRCServices, we would recommend disabling email changes in m_ldap_authentication and disabling account creation in the NickServ configuration. Do not disable registration in m_ldap_authentication. This ensures that account provisioning is done by LDAP and users can group as necessary. Moreover, disable password changes by removing the NickServ set/*pass directives.
## [[Singularity]]
You'll need to update your plugins line in [file:///usr/share/webapps/tt-rss/config.php the config file] and add some parameters. Note: you'll be removing the auth_internal module, but you'll have to add it at least once to promote an LDAP user to admin.
<pre>
define('PLUGINS', 'auth_remote, note, updater, auth_ldap');
define('LDAP_AUTH_SERVER_URI', 'ldap://localhost:389/');
define('LDAP_AUTH_USETLS', FALSE); // Enable TLS Support for ldaps://
define('LDAP_AUTH_ALLOW_UNTRUSTED_CERT', TRUE); // Allows untrusted certificate
define('LDAP_AUTH_BINDDN', 'uid=binduser,ou=People,dc=aninix,dc=net');
define('LDAP_AUTH_BINDPW', 'secret');
define('LDAP_AUTH_BASEDN', 'ou=People,dc=aninix,dc=net');
define('LDAP_AUTH_ANONYMOUSBEFOREBIND', FALSE);
define('LDAP_AUTH_SEARCHFILTER', 'uid=???');
</pre>
## [[Wiki]]
Wiki is the most complicated to add with its multiple domain support, but the following snippet can be modified for a single domain. You'll need to comment out the fourth line at least once after logging in an LDAP user to promote that user to administrator.
<pre>
1. LDAP Modules
require_once( "extensions/LdapAuthentication/LdapAuthentication.php" );
require_once( "includes/AuthPlugin.php");
$wgAuth = new LdapAuthenticationPlugin();
1. LDAP Debugging
$wgLDAPDebug = 0;
$wgDebugLogGroups["ldap"] = "$IP/debug.log" ;
1. LDAP Connection info
$wgLDAPUseLocal = false;
$wgLDAPDomainNames = array( 'aninix.net', );
$wgLDAPServerNames = array( 'aninix.net' => 'localhost', );
$wgLDAPEncryptionType = array( 'aninix.net' => 'clear',
#'aninix.net' => 'tls',
);
1. $wgLDAPOptions = array( 'aninix.net' => array( LDAP_OPT_DEREF, 0 ), );
$wgLDAPPort = array( 'aninix.net' => 389, );
$wgLDAPProxyAgent = array( 'aninix.net' => 'uid=binduser,ou=People,dc=aninix,dc=net', );
$wgLDAPProxyAgentPassword = array( 'aninix.net' => 'secret', );
$wgLDAPSearchAttributes = array( 'aninix.net' => 'uid', );
$wgLDAPBaseDNs = array( 'aninix.net' => 'dc=aninix,dc=net', );
$wgLDAPGroupBaseDNs = array( 'aninix.net' => 'ou=Group,dc=aninix,dc=net', );
$wgLDAPUserBaseDNs = array( 'aninix.net' => 'ou=People,dc=aninix,dc=net', );
$wgLDAPAddLDAPUsers = array( 'aninix.net' => false, );
$wgLDAPUpdateLDAP = array( 'aninix.net' => false, );
$wgLDAPPreferences = array( 'aninix.net' => array( 'email' => 'mail','realname' => 'cn','nickname' => 'uid'), );
1. LDAP Access Only by Group Membership -- requires the memberOf overlay in Sora
1. $wgLDAPGroupUseFullDN = array( "aninix.net"=>false );
1. $wgLDAPGroupObjectclass = array( "aninix.net"=>"posixgroup" );
1. $wgLDAPGroupAttribute = array( "aninix.net"=>"memberuid" );
1. $wgLDAPGroupSearchNestedGroups = array( "aninix.net"=>false );
1. $wgLDAPGroupNameAttribute = array( "aninix.net"=>"cn" );
1. $wgLDAPRequiredGroups = array( "aninix.net"=>array("cn=wiki,ou=Group,dc=aninix,dc=net"));
1. Disable password changes.
$wgHooks['UserLoginForm'][] = 'lfChangeLoginPage';
function lfChangeLoginPage( &$template ) {
$template->set('canreset',false); // removes default reset password link
$template->set('resetlink',false);
// Use the following line to show your own 'reset password' link above the login fields
$template->set('link',"<a href='http://www.somedomain.org/lostpassword'>Forgot your password?</a>");
return true;
}
// Disallow password reset on password reset page
$wgHooks['UserLoginMailPassword'][] = 'MailPasswordIsAllowed';
function MailPasswordIsAllowed ( $username, $error ) {
$error = wfMsg( 'resetpass_forbidden' );
return false;
}
$wgHooks['PrefsPasswordAudit'][] = 'ChangePasswordIsAllowed';
function ChangePasswordIsAllowed ( $user ) {
throw new PasswordError( wfMsg( 'resetpass_forbidden' ));
return true;
}
$wgHooks['GetPreferences'][] = 'RemovePasswordChangeLink';
function RemovePasswordChangeLink ( $user, &$preferences ) {
unset($preferences['password']);
return true;
}
</pre>
# Making Changes
Ldapmodify will allow admins to change parts of Sora. Most user attributes can be updated like below.
<pre>
dn: uid=testuser,ou=People,dc=aninix,dc=net
changetype: modify
replace: mail
mail: blar@test.local
</pre>
Some properties are more intrinsic to the user object and require special handling.
<pre>
dn: uid=testuser1,ou=People,dc=aninix,dc=net
changetype: modrdn
newrdn: uid=testuser2
deleteoldrdn: 1
modifying rdn of entry "uid=testuser2,ou=People,dc=aninix,dc=net"
</pre>
[[Category:Security]]
[[Category:LDAP]]

View File

@@ -0,0 +1,3 @@
#!/bin/bash
slapcat -a "(!(entryDN:dnSubtreeMatch:=ou=People,dc=aninix,dc=net))"

View File

@@ -0,0 +1,119 @@
dn: dc=aninix,dc=net
objectClass: dcObject
objectClass: organization
dc: aninix
o: AniNIXUsers
description: AniNIX::LDAP Crediential Directory
structuralObjectClass: organization
entryUUID: a521b05a-3532-4042-bf8f-3631a1e51b94
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20160901205333Z
entryCSN: 20160901205333.449191Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20160901205333Z
dn: cn=root,dc=aninix,dc=net
objectClass: organizationalRole
cn: root
description: Directory Manager
structuralObjectClass: organizationalRole
entryUUID: 9e4273d9-d002-4015-a774-bed02afd6cc9
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20160901205333Z
pwdLastSuccess: 20220918222625Z
entryCSN: 20220918222625.132392Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20220918222625Z
dn: ou=Group,dc=aninix,dc=net
ou: Group
objectClass: top
objectClass: organizationalUnit
structuralObjectClass: organizationalUnit
entryUUID: 475e1ae1-d992-4a9a-85de-e7f71974ac03
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20160901214257Z
entryCSN: 20160901214257.941445Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20160901214257Z
dn: cn=ldapuser,ou=Group,dc=aninix,dc=net
cn: ldapuser
gidNumber: 10000
objectClass: posixGroup
objectClass: top
structuralObjectClass: posixGroup
entryUUID: dc17d42d-fae9-496d-b362-82f27679476c
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20160903051753Z
entryCSN: 20160903051753.156600Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20160903051753Z
dn: cn=hypervisorauth,ou=Group,dc=aninix,dc=net
cn: hypervisorauth
gidNumber: 10001
objectClass: posixGroup
objectClass: top
structuralObjectClass: posixGroup
entryUUID: 88cb5e2c-ee93-4d62-a83a-63ceff9ceba0
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20160903061147Z
memberUid: lurso3
entryCSN: 20160903061653.689826Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20160903061653Z
dn: ou=pwpolicies,dc=aninix,dc=net
ou: pwpolicies
objectClass: top
objectClass: organizationalUnit
structuralObjectClass: organizationalUnit
entryUUID: ee2c6fc6-a40a-4d6f-992e-c1a04439f022
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20161029155416Z
entryCSN: 20161029155416.247439Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20161029155416Z
dn: cn=default,ou=pwpolicies,dc=aninix,dc=net
objectClass: pwdPolicy
objectClass: person
objectClass: top
cn: default
sn: Default
pwdAttribute: userPassword
pwdMaxAge: 31536000
pwdExpireWarning: 604800
pwdInHistory: 12
pwdCheckQuality: 1
pwdMaxFailure: 5
pwdLockout: TRUE
pwdLockoutDuration: 86400
pwdGraceAuthNLimit: 3
pwdFailureCountInterval: 3600
pwdMustChange: TRUE
pwdMinLength: 8
pwdAllowUserChange: TRUE
pwdSafeModify: FALSE
structuralObjectClass: person
entryUUID: f983ea45-deca-4b8f-8e55-cebbacf392ba
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20161029171109Z
entryCSN: 20161029171109.930559Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20161029171109Z
dn: cn=DarkFeather,ou=Group,dc=aninix,dc=net
cn: DarkFeather
gidNumber: 10002
objectClass: posixGroup
objectClass: top
memberUid: DarkFeather
structuralObjectClass: posixGroup
entryUUID: 1f333fb2-0611-4235-ba07-aa9fa0edb439
creatorsName: cn=root,dc=aninix,dc=net
createTimestamp: 20201018201805Z
entryCSN: 20201018201805.104347Z#000000#000#000000
modifiersName: cn=root,dc=aninix,dc=net
modifyTimestamp: 20201018201805Z

View File

@@ -0,0 +1,26 @@
binlist = ldap-adduser ldap-userreport ldap-resetpass
filelist = sample-user.ldif
compile:
@echo Nothing to do
install: clean ${binlist} ${filelist}
mkdir -p ${pkgdir}/opt/aninix/Password/
for i in ${filelist}; do install -m 0640 -o ldap -g ldap $$i ${pkgdir}/opt/aninix/Password/; done
mkdir -p ${pkgdir}/usr/local/sbin/
for i in ${binlist}; do install -m 0750 -o root -g root $$i ${pkgdir}/usr/local/sbin; done
test: compile
@echo Nothing to do
clean:
@echo Nothing to do.
diff:
@echo Nothing to do.
reverse:
@echo Nothing to do.
checkperm:
@echo Nothing to do.

View File

@@ -0,0 +1,46 @@
depends=('bash>=4.4' 'openldap')
makedepends=('make>=4.2')
checkdepends=()
optdepends=()
pkgname="Password-Scripts"
pkgver="$(git describe --tag --abbrev=0)"."$(git rev-parse --short HEAD)"
pkgrel=1
pkgrel() {
echo $(( `git log "$(git describe --tag --abbrev=0)"..HEAD | grep -c commit` + 1 ))
}
epoch="$(git log | grep -c commit)"
pkgdesc="AniNIX/Password Scripts"
arch=("x86_64")
url="$(git config remote.origin.url | sed 's/.git$//')"
license=('custom')
groups=()
provides=("${pkgname}")
conflicts=()
replaces=("${pkgname,,}" "aninix-${pkgname,,}")
backup=()
options=()
install=
changelog=
source=()
noextract=()
md5sums=()
validpgpkeys=()
prepare() {
git pull || true
}
build() {
make -C ..
}
check() {
chmod -R u+r ../pkg
make -C .. test
}
package() {
export pkgdir="${pkgdir}"
make -C .. install
install -D -m644 ../../../../LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}

View File

@@ -0,0 +1,61 @@
#!/bin/bash
nameRegEx='^[A-Z,a-z,0-9,\.,-]+$'
lockfile="/tmp/""$(echo $0 | rev | cut -f 1 -d '/' | rev)"
function helptext {
echo "$0 username [ userid ]"
}
# match email against regex and create shortname from email ID.
if [ ! -z "$1" ] && [[ "$1" =~ $nameRegEx ]]; then
username="$(echo $1)"
if getent passwd "$username"; then
echo User already exists!
exit 1;
fi
elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
helptext;
exit 0;
else
echo Need an username.
helptext
exit 1;
fi
# Create a new user ID.
if [ -z "$2" ]; then
newuserid="$(($(getent passwd | sort -k 3 -n -t ':' | tail -n 1 | cut -f 3 -d ':') + 1))"
else
if id "$newuserid" &>/dev/null; then
echo "User id $newuserid already exist!"
exit 2
else
newuserid="$2"
fi
fi
printf "Username: %s\nID: %s\n\nReady to add? [YES/no] " "$username" "$newuserid"
mkdir "$lockfile" 2>/dev/null
if [ "$?" -eq 0 ]; then
read answer
if [ "$answer" == "YES" ]; then
file="/etc/openldap/users.d/$username.ldif"
cp /opt/aninix/Password/sample-user.ldif "$file"
line="$(grep -E '^uid: ' "$file")"; sed -i "s/$line/uid: $username/" "$file"
line="$(grep -E '^dn: ' "$file" | cut -f 2 -d ' ' | cut -f 1 -d ',')"; sed -i "s/$line/uid=$username/" "$file"
line="$(grep -E '^homeDirectory: ' "$file")"; sed -i "s#$line#homeDirectory: /home/$username/#" "$file"
line="$(grep -E '^cn: ' "$file")"; sed -i "s/$line/cn: $username/" "$file"
line="$(grep -E '^mail: ' "$file")"; sed -i "s#$line#mail: ircs://aninix.net:6697/$username#" "$file"
line="$(grep -E '^uidNumber: ' "$file")"; sed -i "s/$line/uidNumber: $newuserid/" "$file"
ldapadd -D 'cn=root,dc=aninix,dc=net' -W -f "$file"
ldap-resetpass "$username"
fi
rmdir "$lockfile"
exit 0;
else
echo "Cannot add -- locked."
exit 1;
fi

View File

@@ -0,0 +1,17 @@
#!/bin/bash
uid="$1"
if [ -z "$uid" ]; then
echo "Need a user ID (uid)!"
exit 1
fi
ldappasswd -D 'cn=root,dc=aninix,dc=net' -W "uid=$uid,ou=People,dc=aninix,dc=net"
if [ `ldapsearch -x "(uid=$uid)" + \* | grep -c shadowLastChange\:` -ne 0 ]; then
(printf "dn: uid=$uid,ou=People,dc=aninix,dc=net\nchangetype: modify\ndelete: shadowLastChange\n\n") | ldapmodify -D 'cn=root,dc=aninix,dc=net' -W &>/dev/null;
fi
(printf "dn: uid=$uid,ou=People,dc=aninix,dc=net\nchangetype: modify\nadd: shadowLastChange\nshadowLastChange: 0\n\ndn: uid=$uid,ou=People,dc=aninix,dc=net\nchangetype: modify\nadd: pwdReset\npwdReset: TRUE\n\n") | ldapmodify -D 'cn=root,dc=aninix,dc=net' -W &>/dev/null;
exit $?

View File

@@ -0,0 +1,54 @@
#!/bin/bash
hostname=`hostname`
errortext="ERROR:NEVER"
arg="$1"
function shortshow() {
echo ${user}": "$email
}
basedn=`ldapsearch -x '(cn=root)' dn | grep -E ^dn:\ | sed 's/dn: cn=root,//'`
for user in `ldapsearch -x -b "ou=People,$basedn" '(uid=*)' uid | grep -E ^uid:\ | sed 's/^uid: //'`; do
# Pull changed stats
lastChanged=`/usr/sbin/ldapsearch -x "(uid=$user)" + | grep pwdChangedTime | cut -f 2 -d ' '`
created=`/usr/sbin/ldapsearch -x "(uid=$user)" + | grep createTimestamp | cut -f 2 -d ' '`
email=`/usr/sbin/ldapsearch -x "(uid=$user)" | grep mail | cut -f 2 -d ' '`
if [ -z "$lastChanged" ]; then
lastChanged="$errortext";
else
delta="$(( `date +%s` - `date -d $(echo $lastChanged | head -c 8) +%s`))"
fi
lastlog=`lastlog -u $user | tail -n 1`
if [ `echo $lastlog | grep -c 'Never logged in'` -gt 0 ]; then
lastlog=$errortext
else
lastlog=`echo $lastlog | awk '{$1="";$2="";$3="";print $0 }'`
fi
printf "User $user (email: $email, created: $created) last changed their password on $lastChanged. They last logged in to SSH on $hostname on $lastlog\n" | (
case "$arg" in
"--inactive")
if grep -E $errortext'$' &> /dev/null; then shortshow; fi
;;
"--needschange")
if [ "$lastChanged" == "$errortext" ]; then
shortshow
else
if [ $delta -gt 28512000 ] && [ $delta -lt 31536000 ]; then shortshow; fi
fi
;;
"--expired")
if [ "$lastChanged" != "$errortext" ] && [ "$delta" -ge 31536000 ]; then
shortshow;
fi
;;
*)
cat
;;
esac
)
done

View File

@@ -0,0 +1,21 @@
dn: uid=testuser,ou=People,dc=aninix,dc=net
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser
cn: Test User
sn: User
givenName: Test
title: User
telephoneNumber: +0 000 000 0000
mobile: +0 000 000 0000
postalAddress: AddressLine1$AddressLine2$AddressLine3
loginShell: /bin/bash
uidNumber: 10006
gidNumber: 10000
homeDirectory: /home/testuser
description: Work contact
mail: testuser@aninix.net

View File

@@ -0,0 +1,35 @@
---
- name: Create the base config
become: yes
template:
src: slapd.ldif
dest: /etc/openldap/slapd.ldif
owner: ldap
group: ldap
mode: 0640
- name: Create the directories
file:
path: "{{ item }}"
owner: ldap
group: ldap
mode: 0700
loop:
- /var/lib/openldap/openldap-data/
- /etc/openldap
- /etc/openldap/users.d
- /etc/openldap/groups.d
- /etc/openldap/slapd.d
- name: Initialize the instance
become: yes
command:
cmd: slapadd -n 0 -F /etc/openldap/slapd.d/ -l /etc/openldap/config.ldif && chown -R ldap: /etc/openldap
creates: /etc/openldap/slapd.d/cn=config
- name: Ensure the service
become: yes
service:
name: slapd
state: restarted
enabled: yes

View File

@@ -0,0 +1,17 @@
---
- name: Set login config
become: yes
template:
src: nslcd.conf.j2
dest: /etc/nslcd.conf
owner: nslcd
group: nslcd
mode: 0600
- name: Ensure login service
become: yes
service:
name: nslcd
state: restarted
enabled: yes

View File

@@ -0,0 +1,13 @@
---
- name: Sora packages
become: yes
package:
name:
- openldap
- Password-Scripts
- include_tasks: daemon.yml
- include_tasks: login.yml
- include_tasks: web.yml

View File

@@ -0,0 +1,24 @@
---
- name: Clone the web portal
become: yes
git:
repo: https://github.com/ltb-project/self-service-password
dest: /usr/share/webapps/self-service-password
- name: Ensure web portal ownership
file:
state: directory
owner: http
group: http
path: /usr/share/webapps/self-service-password
recurse: true
- name: Web portal config
become: yes
template:
src: config.inc.php.j2
dest: /usr/share/webapps/self-service-password/conf/config.inc.php
owner: http
group: http
mode: 0600