mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-03-11 09:04:54 +00:00
users: Reorganize and make idempotent ldap setup
- Break down setup process into methods. - Make sure that LDAP entity setup is idempotent. - Peform all entry updates while slapd is running instead of using slapadd. - Start slapd only when necessary. Shutdown (only) if we have started slapd.
This commit is contained in:
parent
8d9480901b
commit
f68a757741
109
actions/users
109
actions/users
@ -68,57 +68,106 @@ def subcommand_pre_install(_):
|
||||
check=True)
|
||||
subprocess.run(
|
||||
['debconf-set-selections'],
|
||||
input=b'libnss-ldapd libnss-ldapd/nsswitch multiselect group, passwd, shadow',
|
||||
input=b'libnss-ldapd libnss-ldapd/nsswitch multiselect '
|
||||
b'group, passwd, shadow',
|
||||
check=True)
|
||||
|
||||
|
||||
def subcommand_setup(_):
|
||||
"""Setup LDAP."""
|
||||
# Make sure slapd isn't running when we use slapadd.
|
||||
action_utils.service_stop('slapd')
|
||||
subprocess.run(['slapadd'], input=b'''
|
||||
dn: ou=users,dc=thisbox
|
||||
objectClass: top
|
||||
objectClass: organizationalUnit
|
||||
ou: users
|
||||
|
||||
dn: ou=groups,dc=thisbox
|
||||
objectClass: top
|
||||
objectClass: organizationalUnit
|
||||
ou: groups
|
||||
''')
|
||||
action_utils.service_start('slapd')
|
||||
configure_access_conf()
|
||||
|
||||
# Update pam configs for access and mkhomedir.
|
||||
subprocess.run(['pam-auth-update', '--package'], check=True)
|
||||
|
||||
# Restrict console login to users in admin or sudo group.
|
||||
with open(ACCESS_CONF, 'r') as conffile:
|
||||
lines = conffile.readlines()
|
||||
configure_ldapscripts()
|
||||
|
||||
access_conf_completed = False
|
||||
for line in lines:
|
||||
if '-:ALL EXCEPT root fbx (admin) (sudo):ALL' in line:
|
||||
access_conf_completed = True
|
||||
configure_slapd()
|
||||
|
||||
if not access_conf_completed:
|
||||
with open(ACCESS_CONF, 'a') as conffile:
|
||||
conffile.write('-:ALL EXCEPT root fbx (admin) (sudo):ALL\n')
|
||||
|
||||
# Remove LDAP admin password. Allow root to modify the users directory.
|
||||
subprocess.run(
|
||||
['ldapmodify', '-Y', 'EXTERNAL', '-H', 'ldapi:///'],
|
||||
input=b'''
|
||||
def configure_slapd():
|
||||
"""Configure LDAP authentication and basic structure."""
|
||||
was_running = action_utils.service_is_running('slapd')
|
||||
if not was_running:
|
||||
action_utils.service_start('slapd')
|
||||
|
||||
try:
|
||||
setup_admin()
|
||||
create_organizational_unit('users')
|
||||
create_organizational_unit('groups')
|
||||
finally:
|
||||
if not was_running:
|
||||
action_utils.service_stop('slapd')
|
||||
|
||||
|
||||
def create_organizational_unit(unit):
|
||||
"""Create an organizational unit in LDAP."""
|
||||
distinguished_name = 'ou={unit},dc=thisbox'.format(unit=unit)
|
||||
try:
|
||||
subprocess.run(
|
||||
['ldapsearch', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///', '-s',
|
||||
'base', '-b', distinguished_name, '(objectclass=*)'],
|
||||
stdout=subprocess.DEVNULL, check=True)
|
||||
return # Already exists
|
||||
except subprocess.CalledProcessError:
|
||||
input = '''
|
||||
dn: ou={unit},dc=thisbox
|
||||
objectClass: top
|
||||
objectClass: organizationalUnit
|
||||
ou: {unit}'''.format(unit=unit)
|
||||
subprocess.run(['ldapadd', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///'],
|
||||
input=input.encode(), stdout=subprocess.DEVNULL,
|
||||
check=True)
|
||||
|
||||
|
||||
def setup_admin():
|
||||
"""Remove LDAP admin password and Allow root to modify the users."""
|
||||
process = subprocess.run(
|
||||
['ldapsearch', '-Q', '-L', '-L', '-L', '-Y', 'EXTERNAL', '-H',
|
||||
'ldapi:///', '-s', 'base', '-b', 'olcDatabase={1}mdb,cn=config',
|
||||
'(objectclass=*)', 'olcRootDN', 'olcRootPW'],
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
ldap_object = {}
|
||||
for line in process.stdout.decode().splitlines():
|
||||
if line:
|
||||
line = line.split(':')
|
||||
ldap_object[line[0]] = line[1]
|
||||
|
||||
if 'olcRootPW' in ldap_object:
|
||||
subprocess.run(
|
||||
['ldapmodify', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///'],
|
||||
check=True, stdout=subprocess.DEVNULL, input=b'''
|
||||
dn: olcDatabase={1}mdb,cn=config
|
||||
changetype: modify
|
||||
delete: olcRootPW
|
||||
delete: olcRootPW''')
|
||||
|
||||
root_dn = 'gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth'
|
||||
if ldap_object['olcRootDN'] != root_dn:
|
||||
subprocess.run(
|
||||
['ldapmodify', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///'],
|
||||
check=True, stdout=subprocess.DEVNULL, input=b'''
|
||||
dn: olcDatabase={1}mdb,cn=config
|
||||
changetype: modify
|
||||
replace: olcRootDN
|
||||
olcRootDN: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
''')
|
||||
|
||||
|
||||
def configure_access_conf():
|
||||
"""Restrict console login to users in admin or sudo group."""
|
||||
with open(ACCESS_CONF, 'r') as conffile:
|
||||
lines = conffile.readlines()
|
||||
|
||||
for line in lines:
|
||||
if '-:ALL EXCEPT root fbx (admin) (sudo):ALL' in line:
|
||||
return
|
||||
|
||||
with open(ACCESS_CONF, 'a') as conffile:
|
||||
conffile.write('-:ALL EXCEPT root fbx (admin) (sudo):ALL\n')
|
||||
|
||||
|
||||
def configure_ldapscripts():
|
||||
"""Set the configuration used by ldapscripts for later user management."""
|
||||
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
||||
augeas.Augeas.NO_MODL_AUTOLOAD)
|
||||
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user