class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True))
        self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1')
        result = self.connection.add(dn_for_test(test_base, 'test-ldif-1'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-ldif-1', test_name_attr: 'test-ldif-1'})
        if not isinstance(result, bool):
            self.connection.get_response(result)
        result = self.connection.add(dn_for_test(test_base, 'test-ldif-2'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-ldif-2', test_name_attr: 'test-ldif-2'})
        if not isinstance(result, bool):
            self.connection.get_response(result)

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    def test_single_search_result_to_ldif(self):
        result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=test-ldif-1)', attributes=[test_name_attr, 'givenName', 'jpegPhoto', 'sn', 'cn', 'objectClass'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result

        l = self.connection.response_to_ldif(response)
        self.assertTrue('version: 1' in l)
        self.assertTrue('dn: cn=test-ldif-1,o=test' in l)
        self.assertTrue('objectClass: inetOrgPerson' in l)
        self.assertTrue('objectClass: Top' in l)
        self.assertTrue('cn: test-ldif-1' in l)
        self.assertTrue('sn: test-ldif-1' in l)
        self.assertTrue('total number of entries: 1' in l)

    def test_multiple_search_result_to_ldif(self):
        result = self.connection.search(search_base=test_base, search_filter='(sn=test-ldif*)', attributes=[test_name_attr, 'givenName', 'sn', 'objectClass'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        l = self.connection.response_to_ldif(response)
        self.assertTrue('version: 1' in l)
        self.assertTrue('dn: cn=test-ldif-1,o=test' in l)
        self.assertTrue('objectClass: inetOrgPerson' in l)
        self.assertTrue('objectClass: Top' in l)
        self.assertTrue('cn: test-ldif-1' in l)
        self.assertTrue('sn: test-ldif-1' in l)
        self.assertTrue('dn: cn=test-ldif-2,o=test' in l)
        self.assertTrue('cn: test-ldif-2' in l)
        self.assertTrue('sn: test-ldif-2' in l)
        self.assertTrue('total number of entries: 2' in l)
class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True))
        self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1')
        result = self.connection.add(dn_for_test(test_base, 'test-add-for-delete'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-add'})
        if not isinstance(result, bool):
            self.connection.get_response(result)

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    def test_delete(self):
        result = self.connection.delete(dn_for_test(test_base, 'test-add-for-delete'))
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'noSuchObject'])
class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info)
        self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=test_check_names)
        result = self.connection.delete(dn_for_test(test_base, 'test-add-operation'))
        if not isinstance(result, bool):
            self.connection.get_response(result)

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    @pytest.mark.skipif(True,  reason="needs rework")
    def test_add(self):
        result = self.connection.add(dn_for_test(test_base, 'test-add-operation'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-add', test_name_attr: 'test-add-operation'})
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result

        self.assertTrue(result['description'] in ['success', 'entryAlreadyExists'])
Esempio n. 4
0
class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=3)
        self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=True)

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    def test_wrong_assertion(self):
        ok = False
        try:
            result = self.connection.search(search_base=test_base, search_filter='(xxx=yyy)', attributes=[test_name_attr])
        except LDAPException:
            ok = True

        self.assertTrue(ok)

    def test_wrong_attribute(self):
        ok = False
        try:
            result = self.connection.search(search_base=test_base, search_filter='(cn=yyy)', attributes=[test_name_attr, 'xxx'])
        except LDAPException:
            ok = True

        self.assertTrue(ok)

    def test_wrong_object_class_add(self):
        ok = False
        try:
            result = self.connection.add(dn_for_test(test_base, 'test-add-operation-wrong'), 'iNetOrgPerson', {'objectClass': ['iNetOrgPerson', 'xxx'], 'sn': 'test-add', test_name_attr: 'test-add-operation'})
        except LDAPException:
            ok = True
        self.assertTrue(ok)

    def test_valid_assertion(self):
        result = self.connection.search(search_base=test_base, search_filter='(cn=test*)', attributes=[test_name_attr])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertTrue(len(response) > 1)

    def test_valid_attribute(self):
        result = self.connection.search(search_base=test_base, search_filter='(cn=test*)', attributes=[test_name_attr, 'givenName'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertTrue(len(response) > 1)

    def test_valid_object_class_add(self):
        result = self.connection.add(dn_for_test(test_base, 'test-add-operation-check-names'), 'iNetOrgPerson', {'objectClass': ['iNetOrgPerson', 'Person'], 'sn': 'test-add', test_name_attr: 'test-add-operation-check-names'})
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'entryAlreadyExists'])
class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True))
        self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1')

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    def test_modify_dn_operation(self):
        result = self.connection.delete(dn_for_test(test_base, 'test-add-modified-dn'))
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'noSuchObject'])

        result = self.connection.delete(dn_for_test(test_base, 'test-add-for-modify-dn'))
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'noSuchObject'])

        result = self.connection.add(dn_for_test(test_base, 'test-add-for-modify-dn'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-compare', 'givenName': 'modify-dn'})
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'entryAlreadyExists'])

        result = self.connection.modify_dn(dn_for_test(test_base, 'test-add-for-modify-dn'), test_name_attr + '=test-add-modified-dn')
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'noSuchObject'])

    def test_move_dn(self):
        result = self.connection.delete(dn_for_test(test_base, 'test-add-for-move-dn'))
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'noSuchObject'])

        result = self.connection.add(dn_for_test(test_base, 'test-add-for-move-dn'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-add-for-move-dn', 'givenName': 'move-dn'})
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'entryAlreadyExists'])

        result = self.connection.delete(dn_for_test(test_moved, 'test-add-for-move-dn'))
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['success', 'noSuchObject', 'busy'])

        result = self.connection.modify_dn(dn_for_test(test_base, 'test-add-for-move-dn'), test_name_attr + '=test-add-for-move-dn', new_superior=test_moved)
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertTrue(result['description'] in ['other', 'success', 'entryAlreadyExists', 'noSuchObject'])
Esempio n. 6
0
        conn.search('ou = students, dc = security, dc=ch', '(objectclass=person)')
        print(conn.entries)

    # If client wants to add an entry
    elif operation == '2' or operation == 'a':
        print('Entry will be added in ou=students, dc=security, dc=ch\n')
        to_add=[]
        to_add.append(input("Common name: > "))
        to_add.append(input("Surname: > "))
        to_add.append(input("Description: > "))
        to_add.append(input("User Password: > "))
        to_add.append(input("Telephone Number: > "))
        conn.add('cn = '+to_add[0]+', ou = students, dc = security, dc = ch',
                 attributes={'objectClass': 'person',
                             'sn': to_add[1] if to_add[1] != '' else ' ',
                             'description': to_add[2] if to_add[2] != '' else ' ',
                             'userPassword': to_add[3] if to_add[3] != '' else ' ',
                             'telephoneNumber': to_add[4] if to_add[4] != '' else '00000000000000'}
                 )
        print(conn.result)

    # If clients wants to remove an entry
    elif operation == '3' or operation == 'r':
        to_delete = input("Which user would you like to remove: > ")
        sure = input("Are you sure you want to delete " +to_delete+"? y/n : ")
        y_or_n = False
        # Just a little security to be sure what to delete
        while not y_or_n:
            if (sure == 'y' or sure == 'n'):
                y_or_n = True
            else:
Esempio n. 7
0
    def set_init(self, app, request):

        asyncio.get_event_loop().set_debug(True)
        logging.basicConfig(level=logging.DEBUG)

        ldap_server = app.app['settings']['ldap.server']
        conn = Connection(ldap_server, auto_bind=True)
        self.conn = conn

        # test entry is empty
        conn.search(self.base_dn,'(objectclass=top)')
        assert len(conn.entries) == 1, 'Refusing test: ldap entry is not empty'

        # set app testing
        settings = app.app['settings'].copy()
        config_dn = 'ou=config,' + self.base_dn
        userFilter = 'mail={username},ou=users,' + self.base_dn
        settings['ldap.base_dn'] = self.base_dn
        settings['ldap.config_dn'] = config_dn
        settings['ldap.user_filter'] = userFilter
        settings['valid_password'] = '******'
        settings['password_policy'] = 'plone.oauth.password.password_policy'
        new_app = main(settings)
        self.app = app
        self.params = {}
        self.headers = {}
        self.app.app['settings'] = new_app['settings']

        # mock redis
        if self.DISABLE_CACHE_REDIS:

            class AsyncMock(MagicMock):
                async def __call__(self, *args, **kwargs):
                    return super(AsyncMock, self).__call__(*args, **kwargs)

            self.original_redis_cache = redis.cache
            self.original_redis_get = redis.get
            self.mock_redis_cache = AsyncMock()
            self.mock_redis_cache.return_value = iter([None])
            self.mock_redis_get = AsyncMock(side_effect=KeyError)
            redis.cache = self.mock_redis_cache
            redis.get = self.mock_redis_get

        # pre add
        conn.add('ou=scopes,'+self.base_dn, 'organizationalUnit')
        conn.add('ou=users,'+self.base_dn, 'organizationalUnit')
        conn.add('ou=config,'+self.base_dn, 'organizationalUnit')
        conn.add('ou=clients,ou=config,'+self.base_dn, 'organizationalUnit')

        # post delete
        if request is not None:
            request.addfinalizer(self.set_teardown)

        # load data
        self.ldap = self.app.app['settings']['user_manager']

        self.create_scope()
        self.create_client()
        self.create_superuser()
        # load extra data
        self.create_manager()
        self.create_user()
        self.create_group()
Esempio n. 8
0
    class __Ldap:
        ldap = None

        def __init__(self, settings=None):
            self.settings = settings or Settings()
            self.logger = Logger(__name__)

        def getInstance(self):
            settings = self.settings.getSettings()
            user = settings['ldap']['admin_ldap_username']
            password = settings['ldap']['admin_ldap_password']
            host = self.settings.getServiceIp('ldap')
            self.logger.debug("Connecting to " + host + " with user " + user)
            self.dn_base = settings['ldap']['ldap_cn_base']
            server = Server(host, get_info=ALL)
            self.ldapClient = Connection(server, user=user, password=password, raise_exceptions=True)
            try:
                self.ldapClient.bind()
            except ldap.LDAPSocketOpenError as e:
                self.logger.error("Could not connect to LDAP - SocketOpenError: " + str(e))
            return self

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            return self.ldapClient.unbind()

        def disconnect(self):
            self.ldapClient.unbind()

        def createUser(self, user, firstname, lastname, password, email):
            password = password.encode('utf-8')
            hashPassword = hashlib.md5()
            hashPassword.update(password)
            password = base64.b64encode(hashPassword.digest())
            dn = "cn=" + user + "," + self.dn_base
            attrs = {}
            attrs['objectClass'] = ['inetOrgPerson', 'person', 'top', 'organizationalPerson']
            attrs['cn'] = user
            attrs['userPassword'] = "******" + password.decode('utf-8')
            attrs['sn'] = lastname
            attrs['givenName'] = firstname
            attrs['mail'] = email
            try:
                self.ldapClient.add(dn, attributes=attrs)
                self.logger.info(self.ldapClient.result)
            except ldap.LDAPEntryAlreadyExistsResult:
                self.logger.error("Could not create user, duplicated " + user)
                return False
            except Exception as e:
                self.logger.error("Could not create user: "******"cn="+user+","+self.dn_base
            self.ldapClient.delete(deleteDN)
            return True

        def findUser(self, user):
            self.ldapClient.search(search_base=self.dn_base,
                                   search_filter='(&(objectClass=inetOrgPerson)(cn=' + user + '))',
                                   search_scope=SUBTREE,
                                   attributes=['cn'])

            usernames = []
            for result in self.ldapClient.response:
                cn = result['attributes']['cn'][0]
                if cn:
                    usernames.append(cn)

            return usernames
Esempio n. 9
0
class Generator:
    def __init__(self, configFile, hostFile, owner):
        self.configFile = configFile
        self.hostFile = hostFile
        self.owner = owner

        self.initLogging()
        self.initialise()
        self.connectLDAP()

        self.processHostFile()

        self.disconnectLDAP()

    def initialise(self):
        parser = configparser.ConfigParser()
        with open(self.configFile) as f:
            lines = '[top]\n' + f.read(
            )  # hack, do not want [top] in config file, so add it here
            parser.read_string(lines)

        # we expect certain entries in the config file, or we will bail. There are no defaults

        parser = parser['top']
        self.setConfig('ldaps_url', parser)
        self.setConfig('username', parser)
        self.setConfig('password', parser)
        self.setConfig('realm', parser)
        self.setConfig('service_password', parser)
        self.setConfig('base_dn', parser)

    def initLogging(self):
        self.logger = logging.getLogger('create-service-user')
        self.logger.setLevel(
            logging.DEBUG)  # change to INFO or DEBUG for more output

        handler = logging.StreamHandler()
        handler.setLevel(logging.INFO)

        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)

        self.logger.addHandler(handler)

    def setConfig(self, key, parser):
        if key not in parser:
            self.logger.error(f"Cannot find {key} in config file. Aborting")
            sys.exit(2)
        self.__setattr__(key, parser[key])
        self.logger.info(f"{key} : {parser[key]}")

    def connectLDAP(self):
        self.ldap = Connection(self.ldaps_url,
                               user=self.username,
                               password=self.password,
                               auto_bind=True)
        self.logger.info(self.ldap)

    def archiveAndDeleteFiles(self, files):
        with zipfile.ZipFile(f"{self.owner}.zip", "w") as archive:
            for f in files:
                archive.write(f)

        for f in files:
            p = Path(f)
            p.unlink()

    def processHostFile(self):
        with open(self.hostFile) as f:
            content = f.read()

        # split into lines
        lines = content.split("\n")
        files = []
        for line in lines:
            if line != "":
                entries = line.split(",")
                principal = entries[0]
                host = entries[1]

                print(f"{principal} --> {host}")
                (service_name,
                 filename) = self.createServiceUser(principal, host)

                self.create_keytab(service_name, filename)
                files.append(filename)

        self.archiveAndDeleteFiles(files)

    def createServiceUser(self, principal, host):
        short_host = host.split('.')[0]
        cn = f"{principal} {short_host}"
        dn = f"CN={cn},{self.base_dn}"
        service_name = f"{principal}/{host}"
        user_principal_name = f"{service_name}@{self.realm}"

        user_attrs = {}
        user_attrs['objectClass'] = [
            'top', 'person', 'organizationalPerson', 'user'
        ]
        user_attrs['cn'] = cn
        user_attrs['accountExpires'] = '0'
        user_attrs['userPrincipalName'] = user_principal_name
        user_attrs['servicePrincipalName'] = service_name

        self.logger.info(user_attrs)

        self.ldap.add(dn, attributes=user_attrs)
        self.logger.info(self.ldap.result)

        # set the password

        self.ldap.extend.microsoft.modify_password(dn, self.service_password)
        self.logger.info(self.ldap.result)

        # set the account active and password non-expiring

        self.ldap.modify(dn,
                         {"userAccountControl": [('MODIFY_REPLACE', 66048)]})
        self.logger.info(self.ldap.result)

        filename = f"{principal}-{short_host}.keytab"

        return (service_name, filename)

    def create_keytab(self, service_name, filename):
        # expects ktutil to be installed in the path
        encryptions = ["aes256-cts", "aes128-cts", "rc4-hmac"]

        prompt = "ktutil:  "

        child = pexpect.spawn("ktutil")

        for encryption in encryptions:
            cmd = f"addent -password -p {service_name} -k 1 -e {encryption}"
            child.expect(prompt)
            child.sendline(cmd)
            child.expect("Password for .*:")
            child.sendline(self.service_password)
            child.expect(prompt)
            child.sendline(f"write_kt {filename}")

        child.expect(prompt)
        child.sendline("q")

    def disconnectLDAP(self):
        self.ldap.unbind()
Esempio n. 10
0
class LDAPUserManager(object):

    def __init__(
            self,
            ldap_server,
            user_filter,
            base_dn=None,
            root_dn=None,
            passwd_dn=None,
            user_profile=[],
            read_only=True,
            cache_users=None,
            cache_groups=None):
        self.ldap_server = ldap_server
        self.root_dn = root_dn
        self.passwd_dn = passwd_dn
        self.base_dn = base_dn
        self.user_filter = user_filter
        self.user_profile = user_profile
        self.read_only = read_only
        self.cache_users = cache_users
        self.cache_groups = cache_groups
        self.ttl_users = 3660
        self.bind()


    def scopes_filter(self):
        f = 'ou=scopes,' + self.base_dn
        return f

    def scope_filter(self, scope):
        f = 'ou={scope},' + self.scopes_filter()
        return f.format(scope=scope)

    def groups_filter(self, scope):
        return 'ou=groups,' + self.scope_filter(scope=scope)

    def group_filter(self, scope, group):
        f = 'cn={group},' + self.groups_filter(scope=scope)
        return f.format(group=group)

    def roles_filter(self, scope):
        return 'ou=roles,' + self.scope_filter(scope=scope)

    def role_filter(self, scope, role):
        f = 'cn={role},' + self.roles_filter(scope)
        return f.format(role=role)

    def users_filter(self):
        f = 'ou=users,' + self.base_dn
        return f

    def userdn2id(self, user_dn):
        """
        :param user_dn: can be a user or a group dn
        :type user_dn: str
        """
        parse_dn = None
        if user_dn.startswith('mail='):
            parse_dn = 'mail='
        elif user_dn.startswith('cn='):
            parse_dn = 'cn='

        if parse_dn:
            return user_dn[len(parse_dn):user_dn.find(',')]

    def bind(self):
        if self.root_dn is None:
            raise Exception('No LDAP Admin Configuration')

        authentication_method = SIMPLE
        bind_type = ASYNC

        self.ldap_conn_mng = Connection(
            self.ldap_server,
            authentication=authentication_method,
            client_strategy=bind_type,
            user=self.root_dn,
            password=self.passwd_dn,
            read_only=self.read_only)
        self.ldap_conn_mng.bind()

    def bind_root_readonly(self):
        """
        A root connection to LDAP server only read_only
        """
        if self.root_dn is None:
            raise Exception('No LDAP Admin Configuration')

        authentication_method = SIMPLE
        bind_type = ASYNC

        ldap_conn_mng = Connection(
            self.ldap_server,
            authentication=authentication_method,
            client_strategy=bind_type,
            user=self.root_dn,
            password=self.passwd_dn,
            read_only=True)

        ldap_conn_mng.bind()
        return ldap_conn_mng

    def unbind(self):
        self.ldap_conn_mng.unbind()

    def checkUserName(self, username):
        if ',' in username:
            raise TypeError('No , in username')

    def parse_async_add(self, return_code):
        """
        Parser the response for an LDAP async ADD
        """
        result = 'Not done'
        if return_code:
            result = self.ldap_conn_mng.get_response(return_code)
            result = result[1].get('description', 'Error no description')
        return result

    async def addScope(self, scope):
        """
        !!!Admin add: must be protected when calling
        """
        # Needs admin
        if self.read_only:
            raise Exception('LDAP in Read only mode')

        self.bind()

        scope_dn = self.scope_filter(scope=scope)
        done = self.ldap_conn_mng.add(scope_dn, 'organizationalUnit')

        result = self.parse_async_add(done)

        if result == 'success':
            #add subelements for scope
            roles_dn = self.roles_filter(scope=scope)
            done = self.ldap_conn_mng.add(roles_dn, 'organizationalUnit')
            if self.parse_async_add(done) != 'success':
                result = 'Failed creating roles'

            groups_dn = self.groups_filter(scope=scope)
            done = self.ldap_conn_mng.add(groups_dn, 'organizationalUnit')
            if self.parse_async_add(done) != 'success':
                result = 'Failed creating groups'

        self.unbind()
        return result

    def addUser(self, username, password):
        """
        !!!Admin add: must be protected when calling
        """
        # Needs admin
        if self.read_only:
            raise Exception('LDAP in Read only mode')

        self.bind()

        self.checkUserName(username)
        user_dn = self.user_filter.format(username=username)
        if '@' in username:
            sn = username.split('@')[0]
        else:
            sn = username

        done = self.ldap_conn_mng.add(
            user_dn,
            self.user_profile,
            {
            'cn': username,
            'sn': sn,
            'mail': username,
            'userPassword': password,
            })

        result = self.parse_async_add(done)
        self.unbind()
        return result

    async def addGroup(self, scope, group):
        """
        !!!Admin add: must be protected when calling
        """
        # Needs admin
        if self.read_only:
            raise Exception('LDAP in Read only mode')

        self.bind()

        self.checkUserName(group)
        group_dn = self.group_filter(scope=scope, group=group)

        done = self.ldap_conn_mng.add(
            group_dn,
            'groupOfUniqueNames',
            {
            'cn': group,
            'uniqueMember': group_dn #  group itself as an empty members list
            })

        result = self.parse_async_add(done)
        self.unbind()
        return result

    async def setPassword(self, username, password):
        """
        !!!Admin add: must be protected when calling
        """
        # Needs admin
        if self.read_only:
            raise Exception('LDAP in Read only mode')
        self.bind()
        user_dn = self.user_filter.format(username=username)
        hashed_password = hashed(HASHED_SHA512, password)
        done = self.ldap_conn_mng.modify(
            user_dn,
            {'userPassword': [(MODIFY_REPLACE, [hashed_password])]}
            )
        result = self.parse_async_add(done)
        if result == 'success':
            return True
        else:
            return False

    async def addScopeRole(self, scope, user_dn, role):
        """
        !!!Admin add: must be protected when calling

        `user_dn` can be a user or a group dn.
        """
        # Needs admin
        if self.read_only:
            raise Exception('LDAP in Read only mode')

        self.bind()

        role_dn = self.role_filter(scope=scope, role=role.lower())

        #Create role for first time
        done = self.ldap_conn_mng.add(
            role_dn,
            'groupOfUniqueNames',
            {'cn': role, 'uniqueMember': user_dn}
            )
        result = self.parse_async_add(done)
        if  result == 'entryAlreadyExists':
            #Extend role with new user
            done = self.ldap_conn_mng.modify(
                role_dn,
                {'uniqueMember': [(MODIFY_ADD, [user_dn])]}
                )
            result = self.parse_async_add(done)

        self.unbind()
        return result

    async def addScopeRoleUser(self, scope, username, role):
        user_dn = self.user_filter.format(username=username)
        return await self.addScopeRole(scope, user_dn, role)

    async def addScopeRoleGroup(self, scope, groupname, role):
        group_dn = self.group_filter(scope, groupname)
        return await self.addScopeRole(scope, group_dn, role)

    async def delScopeRole(self, scope, username, role):
        """
        !!!Admin del: must be protected when calling
        """
        # Needs admin
        if self.read_only:
            raise Exception('LDAP in Read only mode')

        self.bind()

        role_dn = self.role_filter(scope=scope, role=role.lower())
        user_dn = self.user_filter.format(username=username)

        #Find role for first time
        done = self.ldap_conn_mng.modify(
            role_dn,
            {'uniqueMember': [(MODIFY_DELETE, [user_dn])]}
            )
        result = self.parse_async_add(done)

        if result == 'objectClassViolation':
            # member was the last remaining
            done = self.ldap_conn_mng.delete(role_dn)
            result = self.parse_async_add(done)

        self.unbind()
        return result

    async def searchUser(self, scope, criteria, exact_match, attrs, page=None, num_x_page=0):
        """ !!!Admin search: must be protected when calling
        """
        total = 0
        result = []
        paged_size = num_x_page
        paged_cookie = page

        if exact_match is False and any(criteria.values()):
            for k in criteria.keys():
                criteria[k] = "*" + criteria[k] + "*"

        for objclass in self.user_profile:
            criteria['objectClass'] = objclass

        filter_ldap = ""
        for j, v in criteria.items():
            filter_ldap += "(%s=%s)" % (j, v)
        filter_ldap = "(&%s)" % filter_ldap

        self.ldap_conn_mng.bind()
        done = self.ldap_conn_mng.search(
            self.base_dn,
            filter_ldap,
            search_scope=SUBTREE,
            dereference_aliases=DEREF_ALWAYS,
            attributes=USER_ATTRIBUTES,
            size_limit=0,
            time_limit=0,
            types_only=False,
            get_operational_attributes=False,
            controls=None,
            paged_size=paged_size,
            paged_criticality=False,
            paged_cookie=paged_cookie)

        if done:
            result = self.ldap_conn_mng.get_response(done)[0]
            total = len(result)
        self.ldap_conn_mng.unbind()
        return [dict(r['attributes']) for r in result], total

    async def getUser(self, dn, ldap_conn):
        # We should be logged in with the user
        with (await self.cache_users) as redis:
            user = await redis.get(dn)
            if user and user != b'{}':
                return ujson.loads(user)
        r = ldap_conn.search(
            dn,
            '(objectClass=*)',
            search_scope=BASE,
            attributes=USER_ATTRIBUTES)
        if r:
            res = ldap_conn.response[0]
            with (await self.cache_users) as redis:
                redis.set(res['dn'], ujson.dumps(dict(res['attributes'])))
                redis.expire(res['dn'], self.ttl_users)
            return res['attributes']

    async def loginUser(self, username, password):
        user_dn = self.user_filter.format(username=username)
        bind_type = SYNC
        authentication_method = SIMPLE
        ldap_conn = Connection(
            self.ldap_server,
            authentication=authentication_method,
            client_strategy=bind_type,
            user=user_dn,
            password=password,
            read_only=True)
        try:
            result = ldap_conn.bind()
            if result:
                user = await self.getUser(user_dn, ldap_conn)
                ldap_conn.unbind()
                return user
            else:
                return None
        except LDAPException:
            return None

    async def getUserName(self, username):
        dn = self.user_filter.format(username=username)
        with (await self.cache_users) as redis:
            user = await redis.get(dn)
            if user and user != b'{}':
                return ujson.loads(user)
        ldap_conn = self.bind_root_readonly()
        r = ldap_conn.search(
            dn,
            '(objectClass=*)',
            search_scope=BASE,
            attributes=USER_ATTRIBUTES)
        if r:
            names = ldap_conn.get_response(r)[0]
            res = [res['attributes']['cn'][0] for res in names]
        else:
            res = []
        ldap_conn.unbind()
        return ' '.join(res)

    async def get_user_groups(self, ldap_conn, scope, user_dn):
        """
        Return all groups cn that `user_dn` has in `scope`

        :param user_dn: can be a user or a group dn
        :type user_dn: str
        """
        groups_dn = self.groups_filter(scope=scope)

        search_filter = '(uniqueMember={0})'.format(user_dn)

        r = ldap_conn.search(
            groups_dn,
            search_filter,
            search_scope=SUBTREE,
            attributes=['cn']
        )
        if r:
            groups = ldap_conn.get_response(r)[0]
            groups = filter(lambda x: x['dn'] != user_dn, groups) # filter self
            return [res['attributes']['cn'][0] for res in groups]

    async def get_user_roles(self, ldap_conn, scope, user_dn, groups=None):
        """
        Return all roles cn that `user_dn` has in `scope`.
        Return all roles cn that each of `groups` has in `scope`.

        :param user_dn: can be a user or a group dn
        :type user_dn: str
        :param groups: (Optionally)
        :type groups: list
        """
        roles_dn = self.roles_filter(scope=scope)
        search_filter = '(uniqueMember={0})'.format(user_dn)

        if groups is not None:
            search_filter = '(|' + search_filter
            for group_cn in groups:
                group_dn = self.group_filter(scope=scope, group=group_cn)
                search_filter += '(uniqueMember={0})'.format(group_dn)
            search_filter += ')'


        r = ldap_conn.search(
            roles_dn,
            search_filter,
            search_scope=SUBTREE,
            attributes=['cn']
            )
        if r:
            roles = ldap_conn.get_response(r)[0]
            return [res['attributes']['cn'][0] for res in roles]

    async def get_info_user_or_group(self, user_dn, scope):
        """
        !!!Admin search: must be protected when calling

        :returns:
            {
                'groups': {
                    'group1': 1,
                },
                'roles': {
                    'plone.Manager': 1,
                }
            }
        """
        ldap_conn = self.bind_root_readonly()
        groups = await self.get_user_groups(ldap_conn, scope, user_dn)
        roles = await self.get_user_roles(
            ldap_conn,
            scope,
            user_dn,
            groups=groups,
        )
        ldap_conn.unbind()

        return {
            'roles': {e: 1 for e in roles},
            'groups': {e: 1 for e in groups},
        }

    async def getUserInfo(self, username, scope):
        """
        !!!Admin search: must be protected when calling

        :returns:
            {
                'groups': {
                    'group1': 1,
                },
                'roles': {
                    'plone.Manager': 1,
                }
                'name': 'Name'
            }
        """
        user_dn = self.user_filter.format(username=username)
        info = await self.get_info_user_or_group(user_dn, scope)
        info['name'] = username
        return info

    async def getGroupInfo(self, scope, group=None):
        """
        !!!Admin search: must be protected when calling

        :rtype: dict or list of dict or None
        :returns:
            {
                'members': [
                    member1,
                ],
                'name': 'Name'
            }

            or list of groups if group is None
            or None if group is not found

        """
        ldap_conn = self.bind_root_readonly()

        groups_dn = self.groups_filter(scope=scope)

        if group is None:
            search_filter = '(objectClass=groupOfUniqueNames)'
        else:
            search_filter = '(cn={0})'.format(group)

        r = ldap_conn.search(
            groups_dn,
            search_filter,
            search_scope=SUBTREE,
            attributes=['cn', 'uniqueMember']
            )

        if not r:
            raise Exception('LDAP Group search bad formed')

        groups = ldap_conn.get_response(r)[0]
        ldap_conn.unbind()

        async def ldap2json(entry):
            group_dn = entry['dn']
            group_name = entry['attributes']['cn'][0]
            members_ldap = entry['attributes']['uniqueMember']
            members_ldap = filter(lambda x: x != group_dn, members_ldap) # filter self
            info = await self.get_info_user_or_group(group_dn, scope)
            info.update({
                'name': group_name,
                'members': list(map(self.userdn2id, members_ldap)),
                })
            return info

        groups = await asyncio.gather(*map(ldap2json, groups))

        if group is None:
            return groups
        try:
            return groups[0]
        except IndexError:
            return None

    async def get_all_scopes(self, ldap_conn):
        """
        """
        r = ldap_conn.search(
            self.scopes_filter(),
            "(objectClass=organizationalUnit)",
            search_scope=LEVEL,
            attributes=['ou']
            )
        if r:
            scopes = ldap_conn.get_response(r)[0]
            return [scope['attributes']['ou'][0] for scope in scopes]

    async def getUserScopes(self, username):
        """
        Aquesta crida retorna tots els scopes als quals pertany un usuari

        Nota: es pot millorar. Recorre dos cops tots els scopes. Un cop per
        obtenir-los tots i un altre per filtrar segons si l'usuari pertany o no
        """
        ldap_conn = self.bind_root_readonly()

        all_scopes = await self.get_all_scopes(ldap_conn)

        if plone.oauth.is_superuser(username):
            scopes = all_scopes
        else:
            user_dn = self.user_filter.format(username=username)
            scopes = []
            for scope in all_scopes:
                roles = await self.get_user_roles(ldap_conn, scope, user_dn)
                if roles:
                    scopes.append(scope)

        ldap_conn.unbind()

        return {
            'scopes': scopes
        }

    async def get_all_users(self, ldap_conn):
        """
        Return all users cn that `username` has in `scope`.
        Optionally also search by `groups`.
        """
        r = ldap_conn.search(
            self.users_filter(),
            "(objectClass=organizationalPerson)",
            search_scope=LEVEL,
            attributes=['mail']
            )
        if r:
            users = ldap_conn.get_response(r)[0]
            return [user['attributes']['mail'][0] for user in users]

    async def getScopeUsers(self, scope):
        """
        Retorna tots els usuaris que pertanyen a un scope

        Nota: es pot millorar. Recorre dos cops tots els usuaris. Un cop per
        obtenir-los tots i un altre per filtrar segons si l'usuari pertany o no
        """
        ldap_conn = self.bind_root_readonly()

        all_users_ids = await self.get_all_users(ldap_conn)

        users = []
        for user_id in all_users_ids:
            user_dn = self.user_filter.format(username=user_id)
            roles = await self.get_user_roles(ldap_conn, scope, user_dn)
            if roles:
                user = {
                    'id': user_id,
                    'roles': roles
                }
                users.append(user)

        ldap_conn.unbind()

        return {
            'users': users
        }
Esempio n. 11
0
class LDAP:
    def __init__(self, domain_controllers):
        self.domain_controllers = domain_controllers
        pass

    def bind(self, ad_username, ad_password):
        """
        Function that can be called to bind to a list of domain controllers as a pool
        """
        logger.debug("Trying to connect to domain controllers: {}".format(
            self.domain_controllers))
        server_pool_list = []
        for dc in self.domain_controllers:
            server_pool_list.append(
                Server(host=dc,
                       get_info=ALL,
                       port=636,
                       use_ssl=True,
                       connect_timeout=120))
        server_pool = ServerPool(server_pool_list,
                                 FIRST,
                                 active=True,
                                 exhaust=120)
        try:
            self.conn = Connection(server_pool,
                                   auto_bind=True,
                                   user=ad_username,
                                   password=ad_password,
                                   raise_exceptions=True)
            self.conn.bind()
        except LDAPTimeLimitExceededResult as e:
            logger.critical(
                "Unable to establish a connection with the LDAP server, timed out after 60 seconds"
            )
            exit(1)
        except Exception as e:
            logger.critical(
                "Unable to create an LDAP connection to provision users in Active Directory. The error was: {}"
                .format(str(e)))
            raise
            exit(1)

    def list_groups(self, ou, attributes=ALL_ATTRIBUTES):

        if not attributes == ALL_ATTRIBUTES and not "sAMAccountName" in attributes:
            raise Exception(
                "The attribute 'sAMAccountName' must be included in the attributes list passed"
            )
        ad_groups = {}
        try:
            groups = self.conn.extend.standard.paged_search(
                search_base=ou,
                search_filter="(objectClass=Group)",
                search_scope=SUBTREE,
                attributes=attributes,
                paged_size=100,
                generator=False,
            )
        except Exception as e:
            raise Exception(
                "Unable to list groups in AD. The error was: {}".format(
                    str(e)))
        if not self.conn.result.get("description") == "success":
            raise Exception(
                "Unable to list users in AD. The error was: {}".format(
                    self.conn.result))
        elif len(groups) == 0:
            logger.info(
                "No groups were found in Active Directory, but got a good response. Proceeding."
            )
            return {}

        for group in groups:
            # print(json.dumps(group, indent=2, sort_keys=True, default=str))
            try:
                ad_groups[group.get("attributes", {}).get("cn", "")] = dict(
                    group.get("attributes", {}))
            except Exception as e:
                logger.warning(
                    "Unable to add group {} to ad_groups list. The error was: {}"
                    .format(group.get("cn", ""), e))
        return ad_groups

    def list_users(self, ou, attributes=ALL_ATTRIBUTES):
        """
        List all users in a given OU or CN
        :param ou: The DN path where you want the listing to occur
        :param attributes: a list of attributes that you would like returned in the query (must contain at least userPrincipalName), defaults to ALL
        :return: a dictionary of returned objects from the specified search DN with the key set to the user's UPN and value their AD record
        """
        if not attributes == ALL_ATTRIBUTES and not "sAMAccountName" in attributes:
            raise Exception(
                "The attribute 'sAMAccountName' must be included in the attributes list passed"
            )
        ad_users = {}
        try:
            users = self.conn.extend.standard.paged_search(
                search_base=ou,
                search_filter="(objectClass=User)",
                search_scope=SUBTREE,
                attributes=attributes,
                paged_size=100,
                generator=False,
            )
        except Exception as e:
            raise Exception(
                "Unable to list users in AD. The error was: {}".format(str(e)))
        if not self.conn.result.get("description") == "success":
            raise Exception(
                "Unable to list users in AD. The error was: {}".format(
                    self.conn.result))
        elif len(users) == 0:
            logger.info(
                "No users were found in Active Directory, but got a good response. Proceeding."
            )
            return {}

        for user in users:
            # print(json.dumps(user, indent=2, sort_keys=True, default=str))
            try:
                # we append each user to a dictionary and set the value to the user record
                # we are primarily using this as a lookup reference to know if the user was already in AD or not
                ad_users[user.get("attributes",
                                  {}).get("sAMAccountName", "")] = dict(
                                      user.get("attributes", {}))
            except Exception as e:
                logger.warning(
                    "Unable to add user {} to ad_users list. The error was: {}"
                    .format(user.get("dn", ""), e))
        return ad_users

    def create_user(self, user, password, ou):
        """
        Create a new user in Active Directory with default attributes
        (including a generated secure password, and account enablement)
        :param ou: the path in AD for the user to be created
        :param ldap_user_attributes: the JSON formatted user record
        :return: bool status of whether the creation succeeded or not
        """
        ldap_user_attributes = {
            "objectClass": ["top", "person", "organizationalPerson", "user"],
            "cn": [f"{user['first_name']} {user['last_name']}"],
            "sAMAccountName":
            [user['username'][:20]
             ],  # we need to strip the sAMAccountName to 20 chars
            "displayName": [f"{user['first_name']} {user['last_name']}"],
            "mail": [user['email']],
            "userPrincipalName": [user['email']],
            # mind the extra set of quotes in the uncodePWd value, this is required, do not change
            # this is very specific to MS AD, so this needs be the encoding
            "unicodePwd": f'"{password}"'.encode("utf-16-le"),
            "userAccountControl":
            "66048",  # userAccountControl mappings: https://vaportech.wordpress.com/2007/12/06/useraccountcontrol/
            "department": user['team'],
            "givenName": user['first_name'],
            "sn": user['last_name'],
            "title": user['title'],
            "description": f"{user['title']} for {user['team']}"
        }

        try:
            username = ldap_user_attributes.get(
                "cn",
                {})[0]  # sAMAccountName is a list, we need the first entry
        except IndexError as e:
            logger.error(
                "Unable to retrieve the sAMAccountName for record {}".format(
                    ldap_user_attributes))
            return False
        logger.debug("Attempting to create AD user {}".format(username))
        dn = "CN={},{}".format(username, ou)
        logger.debug("The DN will be set to {}".format(dn))
        logger.debug(
            f"The ldap_user_attributes will be: {json.dumps(ldap_user_attributes, default=str)}"
        )
        try:
            resp = self.conn.add(dn, attributes=ldap_user_attributes)
        except LDAPEntryAlreadyExistsResult as e:
            logger.warning(
                "The user {} already exists in Active Directory, skipping".
                format(username))
            ## we return True here since the user does already exist in the domain
            exit(1)
            return True
        except LDAPConstraintViolationResult as e:
            logger.error(
                "Unable to update account {} due to a Contstraint Violation".
                format(username))
            return False
        except Exception as e:
            logger.error(
                "An unexpected error occurred while trying to create user {}. The error was: {}"
                .format(
                    ldap_user_attributes.get("userPrincipalName", [])[0],
                    str(e)))
            return False
        if not resp:
            logger.error("Unable to create user {}. The error was: {}".format(
                ldap_user_attributes.get("userPrincipalName", ""),
                self.conn.result))
            return False
        return True

    def dump_stuff(self, search_base):
        total_entries = 0

        self.conn.search(search_base=search_base,
                         search_filter='(objectClass=OrganizationalUnit)',
                         search_scope=SUBTREE,
                         paged_size=5)

        total_entries += len(self.conn.response)

        for entry in self.conn.response:
            print(entry)

        print('Total entries retrieved:', total_entries)

    def add_user_to_group(self, user, group_name, AD_OU):
        rndUser = f"CN={user},{AD_OU}"
        rndGroup = f"CN={group_name},{AD_OU}"

        addUsersInGroups(self.conn, rndUser, rndGroup)

    def create_group(self, group_name, ou):
        """
        Create a new user in Active Directory with default attributes
        (including a generated secure password, and account enablement)
        :param ou: the path in AD for the user to be created
        :param ldap_user_attributes: the JSON formatted user record
        :return: bool status of whether the creation succeeded or not
        """
        ldap_group_attributes = {
            "objectClass": ["top", "group"],
            "cn": [group_name],
            "sAMAccountName":
            [group_name[:20]
             ],  # we need to strip the sAMAccountName to 20 chars
            "name": [group_name],
        }

        logger.debug("Attempting to create AD group {}".format(group_name))
        dn = "CN={},{}".format(group_name, ou)
        logger.debug("The DN will be set to {}".format(dn))
        logger.debug(
            f"The ldap_group_attributes will be: {json.dumps(ldap_group_attributes, default=str)}"
        )
        try:
            resp = self.conn.add(dn, attributes=ldap_group_attributes)
        except LDAPEntryAlreadyExistsResult as e:
            logger.warning(
                "The group {} already exists in Active Directory, skipping".
                format(group_name))
            return True
        except LDAPConstraintViolationResult as e:
            logger.error(
                "Unable to update account {} due to a Contstraint Violation".
                format(group_name))
            return False
        except Exception as e:
            logger.error(
                "An unexpected error occurred while trying to create group {}. The error was: {}"
                .format(
                    ldap_user_attributes.get("userPrincipalName", [])[0],
                    str(e)))
            return False
        if not resp:
            logger.error(
                f"Unable to create group {group_name}. The error was: {self.conn.result}"
            )
            return False
        return True
Esempio n. 12
0
#Print server's schema
#print (server.schema)

#look for all Uniperson and print them before adding
conn.search('ou=people,dc=ldap,dc=secuis,dc=fun', '(objectClass=UniPerson)')
#print(conn.entries)

#look for all attributes of Uniperson from schema, save it in an iterable "ObjectDef"

#print(person)
#for test in person:
#    if test['mandatory': True]: print('mandatory')

#add a UniPerson user with attributes mail and userPassword
conn.add('cn=' + name + ',ou=people,dc=ldap,dc=secuis,dc=fun', 'UniPerson', {
    'mail': email,
    'userPassword': '******'
})
#print(conn.result)
#print()

#modify a UniPerson's attributes mail and userPassword
conn.modify(
    'cn=' + name + ',ou=people,dc=ldap,dc=secuis,dc=fun', {
        'mail': [(MODIFY_REPLACE, [email])],
        'userPassword': [(MODIFY_REPLACE, ['111111'])]
    })
#print(conn.result)
#print()

#compare Uniperson's attributes userPassword
pwd = '123456'
Esempio n. 13
0
class ad :
    """ Simple class for interaction with active Directory using ldap """
    def __init__(self):
        """ Initialize common variables and load config from ? what file """
        
    def connect (self,user,password,server) :
        """
        Create server object and connection with it,
        latter accessible as \"s\" and \"c\" inside \"ad\" object
        """
        # define an unsecure LDAP server, requesting info on DSE and schema
        self.s = Server(server, use_ssl=True , get_info = ALL, tls=Tls(validate=ssl.CERT_NONE))  
        self.c = Connection(self.s, auto_bind = True, client_strategy = SYNC, user=user, \
             password=password, authentication=SIMPLE, check_names=True)

    def disconnect (self) :
        """
        Closes connection with current server
        """
        try :
            self.c.unbind()
            return True
        except:
            return False

    def createUser(self,dn,attr) :
        """
        Create user with dn and attr
        Password is stored in attr['password']
        """
        unicode_pass='******'+str(attr['password'])+'"'
        ready_pass=unicode_pass.encode('utf-16-le')
        del attr['password']
        self.c.add(dn,['top','person','organizationalPerson','user'],attr)
        self.c.modify(dn,{'unicodePwd':(MODIFY_REPLACE,ready_pass)})
        self.c.modify(dn,{'userAccountControl':(MODIFY_REPLACE,512)})

        return True

    def resetPassword(self,dn,password) :
        """
        Reset password for user with supplied dn
        """
        unicode_pass='******'+str(password)+'"'
        ready_pass=unicode_pass.encode('utf-16-le')
        self.c.modify(dn,{'unicodePwd':(MODIFY_REPLACE,ready_pass)})
        return True

    def searchUsers(self,attr,value,request,baseDn):
        """
        Search users in baseDN, filtered by attr with specific value.
        Returns list of users and requested atributes. Attributes specified
        by list of names in \"'request\"
        """
        users=[]
        ldapFilter='(&(objectCategory=person)(objectClass=user)('+str(attr)+'='+str(value)+'))'
        self.c.search(search_base=baseDn,search_filter=ldapFilter,search_scope=SUBTREE,attributes=request)
        for record in self.c.response :
            if record['type'] == 'searchResEntry' :
                users.append(record['attributes'])
        return users

    def searchOrgUnits(self,attr,value,request,baseDn):
        """
        Search users in baseDN, filtered by attr with specific value.
        Returns list of users and requested atributes. Attributes specified
        by list of names in \"'request\"
        """
        ou=[]
        #print('(&(objectCategory=organizationalUnit)('+attr+'='+value+'))')
        ldapFilter='(&(objectCategory=organizationalUnit)('+str(attr)+'='+str(value)+'))'
        self.c.search(search_base=baseDn,search_filter=ldapFilter,search_scope=SUBTREE,attributes=request)
        for record in self.c.response :
            #print(record)
            if record['type'] == 'searchResEntry' :
                ou.append(record['attributes'])
        return ou

    def addToGroup (self,user,group):
        """
        Add user to group. Both specified by distinguished name
        """
        try:
            self.c.modify(group,{'member':(MODIFY_ADD,user)})
            return True
        except:
            return False

    def removeFromGroup (self,user,group):
        """
        Remove user from group. Both specified by distinguished name
        """
        try:
            self.c.modify(group,{'member':(MODIFY_DELETE,user)})
            return True
        except:
            return False

    def modifyAttribute (self,attribute,newValue,adObject,mod=MODIFY_REPLACE):
        """
        Modify any attribute. Replace old attribute by default
        """
        #print(str(attribute)+" "+str(adObject)+" "+str(newValue))
        try:
            self.c.modify(adObject,{attribute:(mod,newValue)})
            print(str(attribute)+" "+str(adObject)+" "+str(newValue))
            return True
        except:
            print("ooops")
            return False
Esempio n. 14
0
class Test(unittest.TestCase):
    def setUp(self):
        # server = Server(host = test_server, port = test_port, allowed_referral_hosts = ('*', True))
        self.connection = Connection(server=None, client_strategy=STRATEGY_LDIF_PRODUCER)
        self.connection.open()

    def tearDown(self):
        self.connection.unbind()
        self.assertFalse(self.connection.bound)

    def test_add_request_to_ldif(self):
        controls = list()
        controls.append(('2.16.840.1.113719.1.27.103.7', True, 'givenName'))
        controls.append(('2.16.840.1.113719.1.27.103.7', False, 'sn'))
        if str != bytes:  # python3
            controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray('\u00e0\u00e0', encoding='UTF-8')))
        else:
            controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray(unicode('\xe0\xe0', encoding='latin1'), encoding='UTF-8')))  # for python2 compatability
        controls.append(('2.16.840.1.113719.1.27.103.7', False, 'trailingspace '))
        self.connection.add(dn_for_test(test_base, 'test-add-operation'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'test-add', test_name_attr: 'test-add-operation'}, controls=controls)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-add-operation,o=test' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 true: givenName' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false: sn' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: w6DDoA==' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: dHJhaWxpbmdzcGFjZSA=' in response)
        self.assertTrue('changetype: add' in response)
        self.assertTrue('objectClass: inetorgperson' in response)
        self.assertTrue('sn: test-add' in response)
        self.assertTrue('cn: test-add-operation' in response)

    def test_delete_request_to_ldif(self):
        self.connection.strategy.order = dict(delRequest=['dn:', 'changetype', 'vers'])
        self.connection.delete(dn_for_test(test_base, 'test-del-operation'))
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-del-operation,o=test' in response)
        self.assertTrue('changetype: delete' in response)

    def test_modify_dn_request_to_ldif(self):
        result = self.connection.modify_dn(dn_for_test(test_base, 'test-modify-dn-operation'), test_name_attr + '=test-modified-dn-operation')
        if not isinstance(result, bool):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-modify-dn-operation,o=test' in response)
        self.assertTrue('changetype: moddn' in response)
        self.assertTrue('newrdn: cn=test-modified-dn-operation' in response)
        self.assertTrue('deleteoldrdn: 1' in response)

    def test_move_dn_request_to_ldif(self):
        result = self.connection.modify_dn(dn_for_test(test_base, 'test-move-dn-operation'), test_name_attr + '=test-move-dn-operation', delete_old_dn=False, new_superior=test_moved)
        if not isinstance(result, bool):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-move-dn-operation,o=test' in response)
        self.assertTrue('changetype: modrdn' in response)
        self.assertTrue('newrdn: cn=test-move-dn-operation' in response)
        self.assertTrue('deleteoldrdn: 0' in response)
        self.assertTrue('newsuperior: ou=moved,o=test' in response)

    def test_modify_add_to_ldif(self):
        result = self.connection.modify(dn_for_test(test_base, 'test-add-for-modify'), {'givenName': (MODIFY_ADD, ['test-modified-added'])})
        if not isinstance(result, bool):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-add-for-modify,o=test' in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('add: givenName' in response)
        self.assertTrue('givenName: test-modified-added' in response)
        self.assertEqual('-', response[-1])

    def test_modify_replace_to_ldif(self):
        result = self.connection.modify(dn_for_test(test_base, 'test-add-for-modify'), {'givenName': (MODIFY_REPLACE, ['test-modified-replace'])})
        if not isinstance(result, bool):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-add-for-modify,o=test' in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('replace: givenName' in response)
        self.assertTrue('givenName: test-modified-replace' in response)
        self.assertEqual('-', response[-1])

    def test_modify_delete_to_ldif(self):
        result = self.connection.modify(dn_for_test(test_base, 'test-add-for-modify'), {'givenName': (MODIFY_DELETE, ['test-modified-added2'])})
        if not isinstance(result, bool):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=test-add-for-modify,o=test' in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('delete: givenName' in response)
        self.assertTrue('givenName: test-modified-added2' in response)
        self.assertEqual('-', response[-1])

    def test_multiple_modify_to_ldif(self):
        # from rfc 2849 example
        result = self.connection.modify('cn=Paula Jensen, ou=Product Development, dc=airius, dc=com',
                                        {'postaladdress': (MODIFY_ADD, ['123 Anystreet $ Sunnyvale, CA $ 94086']), 'description': (MODIFY_DELETE, []), 'telephonenumber': (MODIFY_REPLACE, ['+1 408 555 1234', '+1 408 555 5678']),
                                         'facsimiletelephonenumber': (MODIFY_DELETE, ['+1 408 555 9876'])})
        if not isinstance(result, bool):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com' in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('delete: facsimiletelephonenumber' in response)
        self.assertTrue('facsimiletelephonenumber: +1 408 555 9876' in response)
        self.assertTrue('replace: telephonenumber' in response)
        self.assertTrue('telephonenumber: +1 408 555 1234' in response)
        self.assertTrue('telephonenumber: +1 408 555 5678' in response)
        self.assertTrue('add: postaladdress' in response)
        self.assertTrue('postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086' in response)
        self.assertTrue('delete: description' in response)
        self.assertEqual('-', response[-1])
def ldap_conn_from_new_admin(local_salt_client):
    """
      1. Create a test user 'DT_test_user' in openldap
      2. Add the user to admin group

    :return:  connection to ldap with new created user
    Finally, delete the user from admin group and openldap
    """
    ldap_password = get_password(local_salt_client, 'openldap:client')
    # Check that ldap_password is exists, otherwise skip test
    if not ldap_password:
        pytest.skip("Openldap service or openldap:client pillar \
        are not found on this environment.")
    ldap_port = local_salt_client.pillar_get(
        tgt='I@openldap:client and not I@salt:master',
        param='_param:haproxy_openldap_bind_port',
        expr_form='compound')
    ldap_address = local_salt_client.pillar_get(
        tgt='I@openldap:client and not I@salt:master',
        param='_param:haproxy_openldap_bind_host',
        expr_form='compound')
    ldap_dc = local_salt_client.pillar_get(tgt='openldap:client',
                                           param='_param:openldap_dn')
    ldap_admin_name = local_salt_client.pillar_get(
        tgt='openldap:client', param='openldap:client:server:auth:user')
    ldap_admin_password = local_salt_client.pillar_get(
        tgt='openldap:client', param='openldap:client:server:auth:password')

    ldap_user_name = 'cn={0},ou=people,{1}'.format(user_name, ldap_dc)

    # Admins group CN
    admin_gr_dn = 'cn=admins,ou=groups,{0}'.format(ldap_dc)
    # List of attributes for test user
    attrs = {
        'cn': user_name,
        'sn': user_name,
        'uid': user_name,
        'userPassword': user_pass,
        'objectClass': ['shadowAccount', 'inetOrgPerson'],
        'description': 'Test user for CVP DT test'
    }
    logging.warning("LOCALS  {}".format(locals()))
    ldap_server = Server(host=ldap_address,
                         port=ldap_port,
                         use_ssl=False,
                         get_info='NO_INFO')
    admin_conn = Connection(ldap_server,
                            user=ldap_admin_name,
                            password=ldap_admin_password)

    admin_conn.bind()
    # Add new user
    new_user = admin_conn.add(ldap_user_name, 'person', attrs)
    if not new_user:
        logging.warning('new_user: {}\n error: {}'.format(
            new_user, admin_conn.result))
    # Add him to admins group
    modified_user = admin_conn.modify(admin_gr_dn,
                                      {'memberUid': (MODIFY_ADD, [user_name])})
    if not modified_user:
        logging.warning("added user to admins: {} \n error: {}".format(
            modified_user, admin_conn.result))

    user_conn = Connection(ldap_server,
                           user=ldap_user_name,
                           password=user_pass)
    user_conn.bind()

    # ###########################
    yield user_conn
    # ###########################
    user_conn.unbind()
    admin_conn.modify(admin_gr_dn, {'memberUid': (MODIFY_DELETE, [user_name])})
    admin_conn.delete(ldap_user_name)
    admin_conn.unbind()
Esempio n. 16
0
                                   ["organization", "top"]):
            raise LdapError("Unable to create organization : %s" % org_id)

    def exists(self, org_id):
        return self.connection.search(search_base=self.base_org_dn, search_filter='(cn=%s)' % org_id)


reg = re.compile(r"^cn=([^,]+),%s" % ORGS_DN)

conn = Connection(LDAP_URI, LDAP_BINDDN, LDAP_PASSWD, auto_bind=True)
conn2 = Connection(LDAP_URI, LDAP_BINDDN, LDAP_PASSWD, auto_bind=True)

# Create Orgs organizational unit if needed
if not conn.search(search_base=LDAP_DOMAIN, search_filter='(ou=%s)' % ORGS_BRANCH_NAME):
    if not conn.add(ORGS_DN,
                               ["organizationalUnit", "top"],
                               {"ou" : ORGS_BRANCH_NAME}):
        raise LdapError("Unable to create orgs organizational unit")
    print('Successful creation of %s entry' % ORGS_DN)

conn.search(search_base=USERS_DN,
            search_filter='(objectClass=%s)' % USER_OBJECT_CLASS,
            search_scope=SUBTREE,
            attributes=['uid', 'cn', 'memberOf', 'o'])

orgHelper = OrganizationHelper(USERS_DN, ORGS_DN, conn2)

# Browsing Users
for user in conn.entries:

    uid = user.uid.value
class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info)
        self.connection = Connection(server, auto_bind=True, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1', check_names=test_check_names)
        result = self.connection.add(dn_for_test(test_base, 'test-search-(parentheses)'), [], {'objectClass': 'iNetOrgPerson', 'sn': 'test-search-(parentheses)', 'loginGraceLimit': 10})
        if not isinstance(result, bool):
            self.connection.get_response(result)

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    def test_search_exact_match(self):
        result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=test-add-operation)', attributes=[test_name_attr, 'givenName', 'jpegPhoto'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(len(response), 1)

    def test_search_extensible_match(self):
        result = self.connection.search(search_base=test_base, search_filter='(&(o:dn:=test)(objectclass=inetOrgPerson))', attributes=[test_name_attr, 'givenName', 'sn'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertTrue(len(response) > 8)

    def test_search_present(self):
        result = self.connection.search(search_base=test_base, search_filter='(objectClass=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName', 'jpegPhoto'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertTrue(len(response) > 9)

    def test_search_substring_many(self):
        result = self.connection.search(search_base=test_base, search_filter='(sn=t*)', attributes=[test_name_attr, 'givenName', 'sn'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')

        self.assertTrue(len(response) > 8)

    def test_search_substring_one(self):
        result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=*y)', attributes=[test_name_attr, 'givenName', 'sn'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')

        self.assertTrue(len(response) > 1)

    def test_search_raw(self):
        result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName', 'photo'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')

        self.assertTrue(len(response) > 8)

    def test_search_with_operational_attributes(self):
        result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=test-add-operation)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName', 'photo'], get_operational_attributes=True)
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(response[0]['attributes']['entryDN'][0], dn_for_test(test_base, 'test-add-operation'))

    def test_search_simple_paged(self):
        paged_size = 1
        total_entries = 0
        result = self.connection.search(search_base=test_base, search_filter='(objectClass=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName'], paged_size=paged_size)
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(len(response), paged_size)
        total_entries += len(response)
        cookie = result['controls']['1.2.840.113556.1.4.319']['value']['cookie']
        while cookie:
            paged_size += 1
            result = self.connection.search(search_base=test_base, search_filter='(objectClass=*)', search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, attributes=[test_name_attr, 'givenName'], paged_size=paged_size, paged_cookie=cookie)
            if not isinstance(result, bool):
                response, result = self.connection.get_response(result)
            else:
                response = self.connection.response
                result = self.connection.result
            self.assertEqual(result['description'], 'success')
            total_entries += len(response)
            self.assertTrue(len(response) <= paged_size)
            cookie = result['controls']['1.2.840.113556.1.4.319']['value']['cookie']
        self.assertTrue(total_entries > 9)

    def test_search_exact_match_with_parentheses_in_filter(self):
        result = self.connection.search(search_base=test_base, search_filter='(' + test_name_attr + '=*' + escape_bytes(')') + '*)', attributes=[test_name_attr, 'sn'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(len(response), 1)
        self.assertEqual(response[0]['attributes']['cn'][0], 'test-search-(parentheses)')

    def test_search_integer_exact_match(self):
        result = self.connection.search(search_base=test_base, search_filter='(loginGraceLimit=10)', attributes=[test_name_attr, 'loginGraceLimit'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(len(response), 2)

    def test_search_integer_less_than(self):
        result = self.connection.search(search_base=test_base, search_filter='(loginGraceLimit<=11)', attributes=[test_name_attr, 'loginGraceLimit'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(len(response), 2)

    def test_search_integer_greater_than(self):
        result = self.connection.search(search_base=test_base, search_filter='(loginGraceLimit>=9)', attributes=[test_name_attr, 'loginGraceLimit'])
        if not isinstance(result, bool):
            response, result = self.connection.get_response(result)
        else:
            response = self.connection.response
            result = self.connection.result
        self.assertEqual(result['description'], 'success')
        self.assertEqual(len(response), 2)
Esempio n. 18
0
conn = Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123', auto_bind=True)
print(0, conn.extend.standard.who_am_i())

# print(server.schema)
# print(server.info)
# print(server.schema.object_classes['inetorgperson'])
# print(server.schema.object_classes['organizationalperson'])
# print(server.schema.object_classes['person'])
# print(server.schema.object_classes['top'])

# conn.search('dc=demo1, dc=freeipa, dc=org', '(&(objectclass=person)(uid=admin))', attributes=['sn', 'krbLastPwdChange', 'objectclass'])
# entry = conn.entries[0]

# print(entry)

conn.add('ou=ldap3-tutorial, dc=demo1, dc=freeipa, dc=org', 'organizationalUnit')

# conn.delete('cn=b.smith,ou=moved,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org')
# from ldap3.protocol.rfc4527 import pre_read_control, post_read_control
# print(1, conn.last_error)
# conn.add('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetOrgPerson', {'givenName': 'Beatrix', 'sn': 'Young', 'departmentNumber': 'DEV', 'telephoneNumber': 1111})
# print(2, conn.modify('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', {'sn': [(MODIFY_ADD, ['Smyth'])]}, controls=[pre_read_control('sn'), post_read_control('sn')]))
# print(3, conn.result['controls'])
# print(4, conn.modify('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', {'sn': [(MODIFY_REPLACE, ['Smith'])]}))
# print(5, conn.result)

# conn.add('cn=j.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetOrgPerson', {'givenName': 'John', 'sn': 'Smith', 'departmentNumber': 'DEV', 'telephoneNumber': 2222})
# conn.add('cn=m.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetOrgPerson', {'givenName': 'Marianne', 'sn': 'Smith', 'departmentNumber': 'QA',  'telephoneNumber': 3333})
# conn.add('cn=quentin.cat,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetOrgPerson', {'givenName': 'Quentin', 'sn': 'Cat', 'departmentNumber': 'CC', 'telephoneNumber': 4444})
# conn.modify_dn('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'cn=b.smith')
# conn.add('ou=moved, ou=ldap3-tutorial, dc=demo1, dc=freeipa, dc=org', 'organizationalUnit')
Esempio n. 19
0
class Test(unittest.TestCase):
    def setUp(self):
        self.connection = Connection(server=None, client_strategy=LDIF)
        self.connection.open()

    def tearDown(self):
        self.connection.unbind()
        self.assertFalse(self.connection.bound)

    def test_add_request_to_ldif(self):
        controls = list()
        controls.append(('2.16.840.1.113719.1.27.103.7', True, 'givenName'))
        controls.append(('2.16.840.1.113719.1.27.103.7', False, 'sn'))
        if str != bytes:  # python3
            controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray('\u00e0\u00e0', encoding='UTF-8')))
        else:
            controls.append(('2.16.840.1.113719.1.27.103.7', False, bytearray(unicode('\xe0\xe0', encoding='latin1'), encoding='UTF-8')))  # for python2 compatability
        controls.append(('2.16.840.1.113719.1.27.103.7', False, 'trailingspace '))
        self.connection.add(generate_dn(test_base, testcase_id, 'ldif-change-1'), 'iNetOrgPerson', {'objectClass': 'iNetOrgPerson', 'sn': 'ldif-change-1', test_name_attr: 'ldif-change-1'}, controls=controls)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-1,' + test_base in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 true: givenName' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false: sn' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: w6DDoA==' in response)
        self.assertTrue('control: 2.16.840.1.113719.1.27.103.7 false:: dHJhaWxpbmdzcGFjZSA=' in response)
        self.assertTrue('changetype: add' in response)
        self.assertTrue('objectClass: iNetOrgPerson' in response)
        self.assertTrue('sn: ldif-change-1' in response)
        self.assertTrue(test_name_attr + ': ldif-change-1' in response)

    def test_delete_request_to_ldif(self):
        self.connection.strategy.order = dict(delRequest=['dn:', 'changetype', 'vers'])
        self.connection.delete(generate_dn(test_base, testcase_id, 'ldif-change-2'))
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-2,' + test_base in response)
        self.assertTrue('changetype: delete' in response)

    def test_modify_dn_request_to_ldif(self):
        result = self.connection.modify_dn(generate_dn(test_base, testcase_id, 'ldif-change-3'), test_name_attr + '=' + testcase_id + 'ldif-change-4,' + test_base)
        if isinstance(result, int):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-3,' + test_base in response)
        self.assertTrue('changetype: moddn' in response)
        self.assertTrue('newrdn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-4,' + test_base in response)
        self.assertTrue('deleteoldrdn: 1' in response)

    def test_move_dn_request_to_ldif(self):
        result = self.connection.modify_dn(generate_dn(test_base, testcase_id, 'ldif-change-5'), test_name_attr + '=' + testcase_id + 'ldif-change-5', delete_old_dn=False, new_superior=test_moved)
        if isinstance(result, int):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-5,' + test_base in response)
        self.assertTrue('changetype: modrdn' in response)
        self.assertTrue('newrdn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-5' in response)
        self.assertTrue('deleteoldrdn: 0' in response)
        self.assertTrue('newsuperior: ' + test_moved in response)

    def test_modify_add_to_ldif(self):
        result = self.connection.modify(generate_dn(test_base, testcase_id, 'ldif-change-6'), {'givenName': (MODIFY_ADD, ['givenname-6-modified'])})
        if isinstance(result, int):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-6,' + test_base in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('add: givenName' in response)
        self.assertTrue('givenName: givenname-6-modified' in response)
        self.assertEqual('-', response[-1])

    def test_modify_replace_to_ldif(self):
        result = self.connection.modify(generate_dn(test_base, testcase_id, 'ldif-change-7'), {'givenName': (MODIFY_REPLACE, ['givenname-7-replaced'])})
        if isinstance(result, int):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-7,' + test_base in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('replace: givenName' in response)
        self.assertTrue('givenName: givenname-7-replaced' in response)
        self.assertEqual('-', response[-1])

    def test_modify_delete_to_ldif(self):
        result = self.connection.modify(generate_dn(test_base, testcase_id, 'ldif-change-8'), {'givenName': (MODIFY_DELETE, ['givenname-8-deleted'])})
        if isinstance(result, int):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: ' + test_name_attr + '=' + testcase_id + 'ldif-change-8,' + test_base in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('delete: givenName' in response)
        self.assertTrue('givenName: givenname-8-deleted' in response)
        self.assertEqual('-', response[-1])

    def test_multiple_modify_to_ldif(self):
        # from rfc 2849 example
        result = self.connection.modify('cn=Paula Jensen, ou=Product Development, dc=airius, dc=com',
                                        {'postaladdress': (MODIFY_ADD, ['123 Anystreet $ Sunnyvale, CA $ 94086']),
                                         'description': (MODIFY_DELETE, []),
                                         'telephonenumber': (MODIFY_REPLACE, ['+1 408 555 1234', '+1 408 555 5678']),
                                         'facsimiletelephonenumber': (MODIFY_DELETE, ['+1 408 555 9876'])})
        if isinstance(result, int):
            self.connection.get_response(result)
        response = self.connection.response
        self.assertTrue('version: 1' in response)
        self.assertTrue('dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com' in response)
        self.assertTrue('changetype: modify' in response)
        self.assertTrue('delete: facsimiletelephonenumber' in response)
        self.assertTrue('facsimiletelephonenumber: +1 408 555 9876' in response)
        self.assertTrue('replace: telephonenumber' in response)
        self.assertTrue('telephonenumber: +1 408 555 1234' in response)
        self.assertTrue('telephonenumber: +1 408 555 5678' in response)
        self.assertTrue('add: postaladdress' in response)
        self.assertTrue('postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086' in response)
        self.assertTrue('delete: description' in response)
        self.assertEqual('-', response[-1])
Esempio n. 20
0
from ldap3 import Server, Connection, ObjectDef, AttrDef, Reader, Writer, ALL, MODIFY_ADD, MODIFY_REPLACE, MODIFY_DELETE, OFFLINE_SLAPD_2_4, MOCK_SYNC
# server = Server('my_fake_server', get_info=OFFLINE_SLAPD_2_4)
# conn = Connection(server, 'uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org', 'Secret123', client_strategy=MOCK_SYNC)
# conn.strategy.add_entry('uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org', {'userPassword': '******', 'sn': 'admin_sn', 'revision': 0})


server = Server('ipa.demo1.freeipa.org', get_info=ALL)
conn = Connection(server, 'uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org', 'Secret123')
print(conn.bind())
print(1, conn.last_error)
print(conn.result)
conn.add('ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'organizationalUnit')
print(1, conn.last_error)
conn.add('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetOrgPerson', {'givenName': 'Beatrix', 'sn': 'Young', 'departmentNumber': 'DEV', 'telephoneNumber': 1111})
print(2, conn.last_error)
conn.modify_dn('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'cn=b.smith')
print(3, conn.last_error)
conn.add('ou=moved, ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'organizationalUnit')
print(4, conn.last_error)
conn.modify_dn('cn=b.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'cn=b.smith', new_superior='ou=moved, ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org')
print(5, conn.last_error)
conn.modify('cn=b.smith,ou=moved,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', {'sn': [(MODIFY_ADD, ['Smyth'])]})
print(6, conn.last_error)
conn.modify('cn=b.smith,ou=moved,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', {'sn': [(MODIFY_DELETE, ['Young'])]})
print(8, conn.last_error)
conn.modify('cn=b.smith,ou=moved,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', {'sn': [(MODIFY_REPLACE, ['Smith'])]})
print(9, conn.last_error)
conn.modify('cn=b.smith,ou=moved,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', {'sn': [(MODIFY_ADD, ['Young', 'Johnson']), (MODIFY_DELETE, ['Smith'])], 'givenname': [(MODIFY_REPLACE, ['Mary', 'Jane'])]})
print(10, conn.last_error)
conn.modify_dn('cn=b.smith,ou=moved,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'cn=b.smith', new_superior='ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org')
print(11, conn.last_error)
Esempio n. 21
0
class Session:
    def __init__(self):
        self.config = config
        self.ldap_config = self.config['ldap']

        url = urlparse(self.ldap_config.get('url'))

        self.server = Server(url.hostname, port=url.port, get_info=ALL)
        self.connection = Connection(self.server, auto_bind=True, client_strategy=SYNC,
                                     user=self.ldap_config.get('bind_dn'), password=self.ldap_config.get('passwd'),
                                     authentication=SIMPLE, check_names=True)

    def close(self):
        self.connection.unbind()

    def get_simple(self, search_base, attributes, search_filter=None, flaten=None):
        search_filter = search_filter or '(objectClass=*)'

        if flaten is False:
            flaten = []
        else:
            flaten = flaten or ['cn', 'uid']

        entries = self.connection.extend.standard.paged_search(search_base=search_base,
                                                               search_filter=search_filter,
                                                               search_scope=SUBTREE,
                                                               attributes=attributes,
                                                               paged_size=10,
                                                               generator=True)

        results = []

        for entry in entries:
            if len(entry['attributes']) == 0:
                continue

            result = entry['attributes']
            result['dn'] = entry['dn']

            for attribute_name in result:
                if attribute_name in flaten:
                    result[attribute_name] = result[attribute_name][0]

            results.append(result)

        return results

    def get_groups(self, attributes=None):
        attributes = attributes or ['cn', 'gidNumber', 'description']
        return self.get_simple(search_base=self.ldap_config.get('group_ou'),
                               attributes=attributes)

    def get_users(self, attributes=None):
        attributes = attributes or ['uid', 'cn', 'mail']

        casual = list(attributes)
        casual.remove('groups')

        users = self.get_simple(search_base=self.ldap_config.get('user_ou'),
                                attributes=casual)

        if 'groups' in attributes:
            for user in users:
                user['groups'] = [group['cn'] for group in self.get_user_groups(uid=user['uid'])]

        return users

    def get_user_dn(self, uid):
        return 'uid={uid},{user_ou}'.format(user_ou=self.ldap_config.get('user_ou'), uid=uid)

    def get_group_dn(self, cn):
        return 'cn={cn},{group_ou}'.format(group_ou=self.ldap_config.get('group_ou'), cn=cn)

    def get_user_groups(self, uid, attributes=None):
        user_dn = self.get_user_dn(uid)

        groups = self.get_simple(
            search_base=self.ldap_config.get('group_ou'),
            search_filter='(|(member={dn})(memberUid={uid}))'.format(dn=user_dn, uid=uid),
            attributes=attributes or ['cn'])

        return groups

    def add_user(self, username, common_name, email=None):
        attributes = {'cn': common_name,
                      'sn': common_name.split()[-1],
                      'mail': email}

        self.connection.add(
            dn="uid={username},{user_ou}".format(username=username, user_ou=self.ldap_config.get('user_ou')),
            object_class=['inetOrgPerson', 'organizationalPerson', 'person', 'top'],
            attributes=attributes)

        self.upgrade_user_schema(username=username)

    def get_top_uid(self):
        users = self.get_simple(search_base=self.ldap_config.get('user_ou'),
                                attributes=['uidNumber'])
        return max([user['uidNumber'] for user in users])

    def _migration0(self, username):
        user_dn = self.get_user_dn(uid=username)

        self.connection.modify(
            dn=user_dn,
            changes={
                'objectClass': [(MODIFY_ADD, ['posixAccount'])],
                'loginShell': [(MODIFY_ADD, ['/bin/bash'])],
                'homeDirectory': [(MODIFY_ADD, ['/home/{}'.format(username)])],
                'gidNumber': [(MODIFY_ADD, ['1999'])],
                'uidNumber': [(MODIFY_ADD, [self.get_top_uid() + 1])],
            })

    def upgrade_user_schema(self, username):
        self._migration0(username=username)

    def delete_user(self, username):
        user_dn = self.get_user_dn(uid=username)
        groups = self.get_user_groups(uid=username)

        for group in groups:
            self.delete_from_group(username=username, group=group['cn'])

        self.connection.delete(user_dn)

    def change_password(self, username, password):
        self.connection.extend.standard.modify_password(user=self.get_user_dn(uid=username),
                                                        new_password=password)

    def add_to_group(self, username, group):
        user_dn = self.get_user_dn(uid=username)
        group_dn = self.get_group_dn(cn=group)

        self.connection.modify(dn=group_dn,
                               changes={'member': [(MODIFY_ADD, [user_dn])]})

    def delete_from_group(self, username, group):
        user_dn = self.get_user_dn(uid=username)
        group_dn = self.get_group_dn(cn=group)

        self.connection.modify(dn=group_dn,
                               changes={'member': [(MODIFY_DELETE, [user_dn])]})

    def add_to_groups(self, username, groups):
        for group in groups:
            self.add_to_group(username=username, group=group)

    def delete_from_groups(self, username, groups):
        for group in groups:
            self.delete_from_group(username=username, group=group)

    def activate(self, username):
        self.add_to_group(username=username, group='members')

    def deactivate(self, username):
        self.delete_from_group(username=username, group='members')