9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# OpenLDAP directory server instance class
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# Copyright (c) 2015 Red Hat, Inc.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# Author: Nikolai Kondrashov <Nikolai.Kondrashov@redhat.com>
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik# Author: Lukas Slebodnik <lslebodn@redhat.com>
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# This is free software; you can redistribute it and/or modify it
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# under the terms of the GNU General Public License as published by
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# the Free Software Foundation; version 2 only
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# This program is distributed in the hope that it will be useful, but
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# WITHOUT ANY WARRANTY; without even the implied warranty of
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# General Public License for more details.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# You should have received a copy of the GNU General Public License
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# along with this program. If not, see <http://www.gnu.org/licenses/>.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """Generate userPassword value for a password."""
e1711a2b2cb904f7edc26cc68566e064896d4f8aLukas Slebodnik hash = hashlib.sha1(password.encode('utf-8'))
e1711a2b2cb904f7edc26cc68566e064896d4f8aLukas Slebodnik hash_base64 = base64.standard_b64encode(hash.digest() + salt)
e1711a2b2cb904f7edc26cc68566e064896d4f8aLukas Slebodnik return "{SSHA}" + hash_base64.decode('utf-8')
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """OpenLDAP directory server instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov def __init__(self, dir, port, base_dn, admin_rdn, admin_pw):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov Initialize the instance.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dir Path to the root of the filesystem hierarchy to create
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov the instance under.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov port TCP port on localhost to bind the server to.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov base_dn Base DN.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov admin_rdn Administrator DN, relative to BASE_DN.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov admin_pw Administrator password.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov DS.__init__(self, dir, port, base_dn, admin_rdn, admin_pw)
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.run_dir = self.dir + "/var/run/ldap"
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.pid_path = self.run_dir + "/slapd.pid"
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.conf_slapd_d_dir = self.conf_dir + "/slapd.d"
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.data_dir = self.dir + "/var/lib/ldap"
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """Setup the instance initial configuration."""
bf472d2422599d14345e7cd9999289c26455c622Lukas Slebodnik dist_lib_dir = first_dir("/usr/lib64/openldap",
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov admin_pw_hash = hash_password(self.admin_pw)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Add configuration
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcGlobal
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcPidFile: {self.pid_path}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcArgsFile: {args_file}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Read slapd.conf(5) for possible values
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcLogLevel: none
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Frontend settings
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: olcDatabase={{-1}}frontend,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcDatabaseConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcFrontendConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDatabase: {{-1}}frontend
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # The maximum number of entries that is returned for
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # a search operation
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcSizeLimit: 500
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Allow unlimited access to local connection from the local root
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: {{0}}to * by dn.exact=gidNumber={gid}+uidNumber={uid},
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov cn=peercred,cn=external,cn=auth manage by * break
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Allow unauthenticated read access for schema and
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # base DN autodiscovery
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: {{1}}to dn.exact="" by * read
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: {{2}}to dn.base="cn=Subschema" by * read
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Config db settings
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: olcDatabase=config,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcDatabaseConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDatabase: config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Allow unlimited access to local connection from the local root
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: to * by dn.exact=gidNumber={gid}+uidNumber={uid},
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov cn=peercred,cn=external,cn=auth manage by * break
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcRootDN: {self.admin_rdn},cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcRootPW: {admin_pw_hash}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Load schemas
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: cn=schema,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcSchemaConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov include: file://{dist_conf_dir}/schema/core.ldif
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov include: file://{dist_conf_dir}/schema/cosine.ldif
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov include: file://{dist_conf_dir}/schema/nis.ldif
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov include: file://{dist_conf_dir}/schema/inetorgperson.ldif
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: cn=module{{0}},cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcModuleList
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov cn: module{{0}}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcModulePath: {dist_lib_dir}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcModuleLoad: back_hdb
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Set defaults for the backend
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: olcBackend=hdb,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcBackendConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcBackend: hdb
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # The database definition.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: olcDatabase=hdb,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcDatabaseConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcHdbConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDatabase: hdb
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDbCheckpoint: 512 30
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcLastMod: TRUE
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcSuffix: {self.base_dn}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDbDirectory: {self.data_dir}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcRootDN: {self.admin_dn}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcRootPW: {admin_pw_hash}
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDbIndex: objectClass eq
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDbIndex: cn,uid eq
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDbIndex: uidNumber,gidNumber eq
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcDbIndex: member,memberUid eq
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: to attrs=userPassword,shadowLastChange
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov by anonymous auth
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: to dn.base="" by * read
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: to *
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config"],
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov raise Exception("Failed to add configuration with slapadd")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Add database config (example from distribution)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # One 0.25 GB cache
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov set_cachesize 0 268435456 1
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Transaction Log settings
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov set_lg_regionmax 262144
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov set_lg_bsize 2097152
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov db_config_file = open(self.data_dir + "/DB_CONFIG", "w")
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Start the instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov if subprocess.call(["slapd", "-F", self.conf_slapd_d_dir,
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Wait until it is available
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config",
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn = ldap.initialize(self.ldap_url)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Setup the instance."""
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self.ldapi_url = "ldapi://" + url_quote(ldapi_socket, "")
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self.url_list = self.ldapi_url + " " + self.ldap_url
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik # Setup initial configuration
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Relax requirement of member attribute presence in groupOfNames
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"{7}( 2.5.6.9 NAME 'groupOfNames' "
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"DESC 'RFC2256: a group of names (DNs)' SUP top "
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ "
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"seeAlso $ owner $ ou $ o $ description ) )"),
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"{7}( 2.5.6.9 NAME 'groupOfNames' "
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"DESC 'RFC2256: a group of names (DNs)' SUP top "
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"STRUCTURAL MUST ( cn ) MAY ( member $ businessCategory $ "
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik b"seeAlso $ owner $ ou $ o $ description ) )"),
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config", self.admin_pw)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.modify_s("cn={0}core,cn=schema,cn=config", modlist)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn = ldap.initialize(self.ldap_url)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik ("objectClass", [b"dcObject", b"organization"]),
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.add_s("cn=Manager," + self.base_dn, [
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.add_s("ou=" + ou + "," + self.base_dn, [
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik ("objectClass", [b"top", b"organizationalUnit"]),
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Stop the instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Wait for slapd to stop
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov os.kill(int(pid_file.read()), signal.SIGTERM)
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Teardown the instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov for path in (self.conf_slapd_d_dir, self.run_dir, self.data_dir):
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Fake Active Directory based on OpenLDAP directory server."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Setup the instance initial configuration."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Import ad schema
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Setup the instance."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik self.ldapi_url = "ldapi://" + url_quote(ldapi_socket, "")
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik self.url_list = self.ldapi_url + " " + self.ldap_url
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Start the daemon
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Relax requirement of surname attribute presence in person
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik b"{4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top "
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik b"STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ "
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik b"telephoneNumber $ seeAlso $ description ) )"),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik b"{4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top "
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik b"STRUCTURAL MUST ( cn ) MAY ( sn $ userPassword $ "
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik b"telephoneNumber $ seeAlso $ description ) )"),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config", self.admin_pw)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.modify_s("cn={0}core,cn=schema,cn=config", modlist)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # restart daemon for reloading schema
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ("objectClass", [b"dcObject", b"organization"]),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.add_s("cn=Manager," + self.base_dn, [
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"):
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.add_s("ou=" + ou + "," + self.base_dn, [
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ("objectClass", [b"top", b"organizationalUnit"]),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # import data from real AD
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ["ldapadd", "-x", "-w", self.admin_pw, "-D",
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Teardown the instance."""