9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov#
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov# OpenLDAP directory server instance class
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov#
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#
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#
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#
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#
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport hashlib
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport base64
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport time
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport ldap
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport os
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport errno
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport signal
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport shutil
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovimport sys
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovfrom util import *
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovfrom ds import DS
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
c46dec3dfad9e83321cc9d3185d93f0e8c38f57eLukas Slebodniktry:
c46dec3dfad9e83321cc9d3185d93f0e8c38f57eLukas Slebodnik from urllib import quote as url_quote
c46dec3dfad9e83321cc9d3185d93f0e8c38f57eLukas Slebodnikexcept ImportError:
c46dec3dfad9e83321cc9d3185d93f0e8c38f57eLukas Slebodnik from urllib.parse import quote as url_quote
c46dec3dfad9e83321cc9d3185d93f0e8c38f57eLukas Slebodnik
60713f738cedb6e4239604baf6619a0ca986fa49Michal Židek
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovdef hash_password(password):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """Generate userPassword value for a password."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov salt = os.urandom(4)
e1711a2b2cb904f7edc26cc68566e064896d4f8aLukas Slebodnik hash = hashlib.sha1(password.encode('utf-8'))
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov hash.update(salt)
e1711a2b2cb904f7edc26cc68566e064896d4f8aLukas Slebodnik hash_base64 = base64.standard_b64encode(hash.digest() + salt)
e1711a2b2cb904f7edc26cc68566e064896d4f8aLukas Slebodnik return "{SSHA}" + hash_base64.decode('utf-8')
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
60713f738cedb6e4239604baf6619a0ca986fa49Michal Židek
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashovclass DSOpenLDAP(DS):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """OpenLDAP directory server instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov def __init__(self, dir, port, base_dn, admin_rdn, admin_pw):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov Initialize the instance.
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov Arguments:
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 """
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_dir = self.dir + "/etc/ldap"
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.conf_slapd_d_dir = self.conf_dir + "/slapd.d"
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.data_dir = self.dir + "/var/lib/ldap"
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov def _setup_config(self):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """Setup the instance initial configuration."""
bf472d2422599d14345e7cd9999289c26455c622Lukas Slebodnik dist_lib_dir = first_dir("/usr/lib64/openldap",
bf472d2422599d14345e7cd9999289c26455c622Lukas Slebodnik "/usr/lib/openldap",
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov "/usr/lib/ldap")
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov dist_conf_dir = first_dir("/etc/ldap",
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov "/etc/openldap")
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov args_file = self.run_dir + "/slapd.args"
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov admin_pw_hash = hash_password(self.admin_pw)
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov uid = os.geteuid()
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov gid = os.getegid()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Add configuration
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov config = unindent("""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcGlobal
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov cn: config
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
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
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
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Load schemas
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: cn=schema,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcSchemaConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov cn: schema
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
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
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Load module
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
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Set defaults for the backend
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov dn: olcBackend=hdb,cn=config
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov objectClass: olcBackendConfig
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcBackend: hdb
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
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 self write
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov by anonymous auth
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov by * none
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: to dn.base="" by * read
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov olcAccess: to *
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov by * read
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """).format(**locals())
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov slapadd = subprocess.Popen(
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config"],
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov stdin=subprocess.PIPE, close_fds=True
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov )
73c9e3d710434857b5e13d5ccfc1f1245b1d2997Lukas Slebodnik slapadd.communicate(config.encode('utf-8'))
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov if slapadd.returncode != 0:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov raise Exception("Failed to add configuration with slapadd")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Add database config (example from distribution)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov db_config = unindent("""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # One 0.25 GB cache
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov set_cachesize 0 268435456 1
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Transaction Log settings
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov set_lg_regionmax 262144
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov set_lg_bsize 2097152
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov """)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov db_config_file = open(self.data_dir + "/DB_CONFIG", "w")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov db_config_file.write(db_config)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov db_config_file.close()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik def _start_daemon(self):
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Start the instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov if subprocess.call(["slapd", "-F", self.conf_slapd_d_dir,
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik "-h", self.url_list]) != 0:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov raise Exception("Failed to start slapd")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Wait until it is available
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov attempt = 0
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov while True:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov try:
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik ldap_conn = ldap.initialize(self.ldapi_url)
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config",
efdcf49660505e13607b99ba82eb504cf37b8794Nikolai Kondrashov self.admin_pw)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.unbind_s()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn = ldap.initialize(self.ldap_url)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.unbind_s()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov break
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov except ldap.SERVER_DOWN:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov pass
c4d2fc3c12656faeb3fb7ca20c922ca62edf13a0Nikolai Kondrashov attempt = attempt + 1
c4d2fc3c12656faeb3fb7ca20c922ca62edf13a0Nikolai Kondrashov if attempt > 30:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov raise Exception("Failed to start slapd")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov time.sleep(1)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik def setup(self):
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Setup the instance."""
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik ldapi_socket = self.run_dir + "/ldapi"
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self.ldapi_url = "ldapi://" + url_quote(ldapi_socket, "")
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self.url_list = self.ldapi_url + " " + self.ldap_url
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik os.makedirs(self.conf_slapd_d_dir)
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik os.makedirs(self.run_dir)
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik os.makedirs(self.data_dir)
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik #
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik # Setup initial configuration
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik #
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self._setup_config()
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self._start_daemon()
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Relax requirement of member attribute presence in groupOfNames
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov modlist = [
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov (ldap.MOD_DELETE, "olcObjectClasses",
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 ) )"),
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov (ldap.MOD_ADD, "olcObjectClasses",
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 ]
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik ldap_conn = ldap.initialize(self.ldapi_url)
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.unbind_s()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Add data
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov #
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn = ldap.initialize(self.ldap_url)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.add_s(self.base_dn, [
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik ("objectClass", [b"dcObject", b"organization"]),
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik ("o", b"Example Company"),
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ])
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.add_s("cn=Manager," + self.base_dn, [
1097a61a8d4a892e126d14631c1b80fc1a5ce976Lukas Slebodnik ("objectClass", b"organizationalRole"),
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ])
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"]),
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ])
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov ldap_conn.unbind_s()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik def _stop_daemon(self):
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Stop the instance."""
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov # Wait for slapd to stop
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov try:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov pid_file = open(self.pid_path, "r")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov try:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov os.kill(int(pid_file.read()), signal.SIGTERM)
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov finally:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov pid_file.close()
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov attempt = 0
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov while os.path.isfile(self.pid_path):
c4d2fc3c12656faeb3fb7ca20c922ca62edf13a0Nikolai Kondrashov attempt = attempt + 1
c4d2fc3c12656faeb3fb7ca20c922ca62edf13a0Nikolai Kondrashov if attempt > 30:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov raise Exception("Failed to stop slapd")
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov time.sleep(1)
872aa0d01d1642f9c8fc204d4c33e5c5640c3352Lukas Slebodnik except IOError as e:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov if e.errno != errno.ENOENT:
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov raise
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik def teardown(self):
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik """Teardown the instance."""
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik self._stop_daemon()
ebbd9a2b551feffd2040f35d938f6800fba1b278Lukas Slebodnik
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov for path in (self.conf_slapd_d_dir, self.run_dir, self.data_dir):
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov shutil.rmtree(path, True)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnikclass FakeAD(DSOpenLDAP):
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Fake Active Directory based on OpenLDAP directory server."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik def _setup_config(self):
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Setup the instance initial configuration."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Import ad schema
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik subprocess.check_call(
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik "-l", "data/ad_schema.ldif"],
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik )
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik def setup(self):
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Setup the instance."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldapi_socket = self.run_dir + "/ldapi"
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik self.ldapi_url = "ldapi://" + url_quote(ldapi_socket, "")
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik self.url_list = self.ldapi_url + " " + self.ldap_url
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik os.makedirs(self.conf_slapd_d_dir)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik os.makedirs(self.run_dir)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik os.makedirs(self.data_dir)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik super(FakeAD, self)._setup_config()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik self._setup_config()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Start the daemon
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik super(FakeAD, self)._start_daemon()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Relax requirement of surname attribute presence in person
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik modlist = [
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik (ldap.MOD_DELETE, "olcObjectClasses",
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 (ldap.MOD_ADD, "olcObjectClasses",
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 ]
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn = ldap.initialize(self.ldapi_url)
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 ldap_conn.unbind_s()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # restart daemon for reloading schema
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik super(FakeAD, self)._stop_daemon()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik super(FakeAD, self)._start_daemon()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # Add data
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn = ldap.initialize(self.ldap_url)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.add_s(self.base_dn, [
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ("objectClass", [b"dcObject", b"organization"]),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ("o", b"Example Company"),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ])
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.add_s("cn=Manager," + self.base_dn, [
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ("objectClass", b"organizationalRole"),
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ])
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 ])
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ldap_conn.unbind_s()
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik # import data from real AD
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik subprocess.check_call(
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik ["ldapadd", "-x", "-w", self.admin_pw, "-D",
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik self.admin_dn, "-H", self.ldap_url,
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik "-f", "data/ad_data.ldif"],
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik )
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik def teardown(self):
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik """Teardown the instance."""
36df33cd44774a5b5eab52ab222bcd3240b3ca5aLukas Slebodnik super(FakeAD, self).teardown()