def getServer():
    if not Server:
        return None
    if not SERVER or not SERVER[0]:
        return None
    for s in SERVER:
        server = Server(s, connect_timeout=1, use_ssl=True)
        if server.check_availability():
            try:
                with Connection(server):
                    return server
            except:
                continue
    for s in SERVER:
        server = Server(s, connect_timeout=1)
        if server.check_availability():
            return server
    return None
    def authenticate(self, userPrincipalName, password):
        """
        [概要]
            認証

        [引数]
            userPrincipalName: ユーザ名
            password: パスワード
            read_timeout: 取得タイムアウト値(秒)

        [戻り値]
            AD_AUTH結果コード(define.AD_AUTH.RESULT_*)
        """

        # TODO:server_poolのほうが使える?
        server = None
        serverList = []
        for host in self._hosts:
            server = Server(host, port=self._port, use_ssl=self._use_ssl, get_info='ALL', connect_timeout=self._connect_timeout)

            # 対象hostの応答がなければ次のhostへ
            if not server.check_availability() :
                continue

            # 応答があればそれを使用する
            logger.logic_log('LOSI11003', host)
            serverList.append(server)

        if len(serverList) == 0:
            # すべてのhostがNGの場合はエラー
            logger.logic_log('LOSM11001', ', '.join(self._hosts))
            return AD_AUTH.RESULT_OTHER_ERROR

        try:
            # step1. domainに対する認証
            conn = Connection(
                        serverList,
                        auto_bind=AUTO_BIND_NONE,
                        client_strategy=SYNC,
                        user=userPrincipalName,
                        password=password,
                        authentication=SIMPLE,
                        check_names=True,
                        receive_timeout=self._read_timeout
                    )

            if not conn.bind():
                logger.logic_log('LOSM11002', conn.last_error, conn.result['message'])
                result_message = conn.result['message']

                error_code = AD_AUTH.RESULT_OTHER_ERROR
                if AD_AUTH.REGEXP_INVALID_CREDENCIALS_MESSAGE.match(result_message):
                    error_code = AD_AUTH.RESULT_INVALID_CREDENCIALS
                    error_message = 'Authentication information error'
                if AD_AUTH.REGEXP_ACCOUNT_LOCKED_MESSAGE.match(result_message):
                    error_code = AD_AUTH.RESULT_ACCOUNT_LOCKED
                    error_message = 'Account lock status'

                logger.logic_log('LOSM11003', error_code, error_message)
                return error_code

            # step2. 検索文字列で指定される組織内に存在するか
            # TODO 管理者の認証のときは除外する?
            success = conn.search(search_base=self._search_path,
                        search_filter='(userPrincipalName=%s)' % userPrincipalName,
                        search_scope=SUBTREE)
            if not success or len(conn.entries) != 1:
                logger.logic_log('LOSM11004', self._search_path)
                return AD_AUTH.RESULT_INVALID_CREDENCIALS

        except Exception as e:
            logger.system_log('LOSM11005', server.host, userPrincipalName)
            return AD_AUTH.RESULT_OTHER_ERROR

        logger.system_log('LOSI11004', conn)

        # 成功時
        self._conn = conn
        return AD_AUTH.RESULT_SUCCESS
 def server_connect(self):
     server = Server(self.host, port=self.port, get_info=ALL)
     if not server.check_availability():
         raise Exception('LDAP Server is not reachable')
     return server
Beispiel #4
0
class LdapOperations(object):
    #"single star" syntax ignores unspecified positional args
    # and provides keyword-only arguments, see PEP-3102
    def __init__(self,
                 type,
                 *,
                 server=None,
                 domain=None,
                 user=None,
                 ntlm_hash=None,
                 plaintext_pw=None,
                 use_ssl=True,
                 windows_user_format=False):
        if not server and user and domain:
            raise ML_Error(
                'Server, user, and domain are required for LDAP Operations')
        self.user = user
        self.domain = domain
        if type == LdapServerType.Windows_AD:
            if ntlm_hash:
                self.ntlm_hash = ntlm_hash
            elif plaintext_pw:
                self.hash = self.ntlm_hash(plaintext_pw)
            else:
                raise ValueError(
                    'Windows AD requires ntlm_hash or plaintext_pw keyword.')

            self.server = Server(server, get_info=ALL)
            self.conn = Connection(self.server,
                                   user=self.domain + '\\' + self.user,
                                   password=self.hash,
                                   authentication=NTLM)
        elif type == LdapServerType.FreeIPA:
            # TODO: something that will actually work here.
            tls = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            self.server = Server(server,
                                 get_info=ALL,
                                 tls=tls,
                                 use_ssl=use_ssl)
            self.conn = Connection(self.server,
                                   authentication=SASL,
                                   sasl_mechanism='EXTERNAL')

        elif type == LdapServerType.Generic_LDAP:
            self.server = Server(
                server,
                get_info=ALL,
            )
            self.conn = Connection(self.server,
                                   user=user,
                                   password=plaintext_pw)

        else:
            raise LdapServerTypeError(type)
        '''
		Ldap3 doesn't raise exceptions on connection errors, so we make sure everything worked below
		'''
        if self.server.check_availability():
            pass
        else:
            raise LdapConnectError("Failed to connect to server")
        if self.conn.bind():
            pass
        else:
            raise LdapBindError("Incorrect Login information")

    def serverInfo(self):
        return self.server.info

    def ntlm_hash(self, pw):
        #correct function for ntlm hash
        h = hashlib.new('md4', pw.encode('utf-16le')).hexdigest()

        ## For some reason, this is the desired format (LM:NTLM):
        return '00000000000000000000000000000000:' + h

    def users_in_group(self, baseDN, groupDN, attributes=['cn']):
        self.conn.search(search_base=baseDN,
                         search_filter='(memberOf=' + groupDN + ')',
                         search_scope=SUBTREE,
                         attributes=attributes)
        return self.conn.entries

    def find_dn_from_username(self,
                              basedn,
                              username,
                              attributes=['userPrincipalName', 'user']):
        search_string = '(|'
        for a in attributes:
            search_string = search_string + '({}={})'.format(a, username)
        search_string = search_string + ')'
        self.conn.search(basedn, search_string, attributes='distinguishedName')
        try:
            return self.conn.entries[0].distinguishedName.value
        except IndexError:
            return None