【问题标题】:How to install gssapi python module on windows?如何在 Windows 上安装 gssapi python 模块?
【发布时间】:2015-09-22 07:01:05
【问题描述】:

我目前正在尝试让 python 的 gssapi module 在 Windows 上运行。我的目标是使用 python 模块ldap3 对 Active Directory 进行身份验证。 gssapi 是这个工作的必要条件。但是,安装失败,因为它找不到 krb5-config。在 Linux 上很容易install。我安装了Kerberos for Windows,但它没有 krb5-config,我在其他任何地方都找不到它(Linux 除外)。有谁知道在哪里可以找到所需的工具或如何继续(如果可能的话)?

【问题讨论】:

  • 刚刚遇到了同样的问题。你有想过这个吗?
  • 没有。显然它不起作用(至少当时不起作用)。我切换到 C# 和 PowerShell 来完成与 AD 相关的任务。
  • Mongo 人将 PyKerberos 移植到使用本机 Windows SSPI,也许可以看看:github.com/mongodb-labs/winkerberos
  • 遇到了同样的问题。有这方面的更新吗?
  • 我对此进行了一些研究(试图让 ldap3 在具有 Kerberos 身份验证的 Windows 上的 MINGW64 下工作),它似乎在寻找一个它找不到的 libgss-3.dll:github.com/pythongssapi/python-gssapi/blob/master/setup.py#L98 (它在 ctypes.CDLL 行上失败了)它还显示了关于缺少 krb5-config 的错误。

标签: python windows installation kerberos gssapi


【解决方案1】:

按照@keithhendry (https://github.com/cannatag/ldap3/issues/190) 的建议,我将ldap3\protocol\sasl\ 下的kerberos.py 替换为this one

为了使用 Windows 的 GSSAPI,您还需要安装 winkerberos 包和 替换 kerberos.py 中第 15 行的 kerberos 导入,如下所示:

import winkerberos as kerberos

这是透明的,因为 winkerberos 遵循与 pykerberos 相同的 API 结构,编辑后的 ​​kerberos.py 就是基于该结构。

现在您可以在使用 ldap3 构造 Connection 时使用 authentication=SASL, sasl_mechanism=GSSAPI,并且一切都应该自动运行(假设其他 999 项 Kerberos 可能出错的事情不会出错)。

【讨论】:

    【解决方案2】:

    使用这个answer,为了避免猴子补丁,可以使用以下代码,基于there提供的文件和ldap3\core\connection.py模块。

    ldap3kerberos.py

    ​​>
    """Replaces the use of python-gssapi with kerberos in ldap3.
    """
    
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    from __future__ import unicode_literals
    
    import base64
    import socket
    
    import ldap3
    from ldap3.core.exceptions import LDAPCommunicationError
    from ldap3.protocol.sasl.sasl import send_sasl_negotiation
    from ldap3.protocol.sasl.sasl import abort_sasl_negotiation
    
    from ldap3.protocol.sasl.external import sasl_external
    from ldap3.protocol.sasl.digestMd5 import sasl_digest_md5
    from ldap3.protocol.sasl.plain import sasl_plain
    from ldap3.utils.log import log, log_enabled, BASIC
    from ldap3 import EXTERNAL, DIGEST_MD5, GSSAPI
    
    
    import winkerberos as kerberos
    
    NO_SECURITY_LAYER = 1
    INTEGRITY_PROTECTION = 2
    CONFIDENTIALITY_PROTECTION = 4
    
    
    class Connection(ldap3.Connection):
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
        def do_sasl_bind(self,
                         controls):
            if log_enabled(BASIC):
                log(BASIC, 'start SASL BIND operation via <%s>', self)
            self.last_error = None
            with self.connection_lock:
                result = None
    
                if not self.sasl_in_progress:
                    self.sasl_in_progress = True
                    try:
                        if self.sasl_mechanism == EXTERNAL:
                            result = sasl_external(self, controls)
                        elif self.sasl_mechanism == DIGEST_MD5:
                            result = sasl_digest_md5(self, controls)
                        elif self.sasl_mechanism == GSSAPI:
                            result = sasl_gssapi(self, controls)
                        elif self.sasl_mechanism == 'PLAIN':
                            result = sasl_plain(self, controls)
                    finally:
                        self.sasl_in_progress = False
    
                if log_enabled(BASIC):
                    log(BASIC, 'done SASL BIND operation, result <%s>', result)
    
                return result
    
    
    def sasl_gssapi(connection, controls):
        """
        Performs a bind using the Kerberos v5 ("GSSAPI") SASL mechanism
        from RFC 4752. Does not support any security layers, only authentication!
        sasl_credentials can be empty or a tuple with one or two elements.
        The first element determines which service principal to request a ticket
        for and can be one of the following:
        - None or False, to use the hostname from the Server object
        - True to perform a reverse DNS lookup to retrieve the canonical hostname
          for the hosts IP address
        - A string containing the hostname
        The optional second element is what authorization ID to request.
        - If omitted or None, the authentication ID is used as the authorization ID
        - If a string, the authorization ID to use. Should start with "dn:" or
          "user:".
        """
        # pylint: disable=too-many-branches
        target_name = None
        authz_id = b''
        if connection.sasl_credentials:
            if (len(connection.sasl_credentials) >= 1 and
                    connection.sasl_credentials[0]):
                if connection.sasl_credentials[0] is True:
                    hostname = \
                        socket.gethostbyaddr(connection.socket.getpeername()[0])[0]
                    target_name = 'ldap@' + hostname
    
                else:
                    target_name = 'ldap@' + connection.sasl_credentials[0]
            if (len(connection.sasl_credentials) >= 2 and
                    connection.sasl_credentials[1]):
                authz_id = connection.sasl_credentials[1].encode("utf-8")
        if target_name is None:
            target_name = 'ldap@' + connection.server.host
    
        gssflags = (
            kerberos.GSS_C_MUTUAL_FLAG |
            kerberos.GSS_C_SEQUENCE_FLAG |
            kerberos.GSS_C_INTEG_FLAG |
            kerberos.GSS_C_CONF_FLAG
        )
    
        _, ctx = kerberos.authGSSClientInit(target_name, gssflags=gssflags)
    
        in_token = b''
        try:
            while True:
                status = kerberos.authGSSClientStep(
                    ctx,
                    base64.b64encode(in_token).decode('ascii')
                )
                out_token = kerberos.authGSSClientResponse(ctx) or ''
                result = send_sasl_negotiation(
                    connection,
                    controls,
                    base64.b64decode(out_token)
                )
                in_token = result['saslCreds'] or b''
                if status == kerberos.AUTH_GSS_COMPLETE:
                    break
    
            kerberos.authGSSClientUnwrap(
                ctx,
                base64.b64encode(in_token).decode('ascii')
            )
            unwrapped_token = base64.b64decode(
                kerberos.authGSSClientResponse(ctx) or ''
            )
    
            if len(unwrapped_token) != 4:
                raise LDAPCommunicationError('Incorrect response from server')
    
            server_security_layers = unwrapped_token[0]
            if not isinstance(server_security_layers, int):
                server_security_layers = ord(server_security_layers)
            if server_security_layers in (0, NO_SECURITY_LAYER):
                if unwrapped_token.message[1:] != '\x00\x00\x00':
                    raise LDAPCommunicationError(
                        'Server max buffer size must be 0 if no security layer'
                    )
            if not server_security_layers & NO_SECURITY_LAYER:
                raise LDAPCommunicationError(
                    'Server requires a security layer, but this is not implemented'
                )
    
            client_security_layers = bytearray([NO_SECURITY_LAYER, 0, 0, 0])
            kerberos.authGSSClientWrap(
                ctx,
                base64.b64encode(
                    bytes(client_security_layers) + authz_id
                ).decode('ascii')
            )
            out_token = kerberos.authGSSClientResponse(ctx) or ''
    
            return send_sasl_negotiation(
                connection,
                controls,
                base64.b64decode(out_token)
            )
        except (kerberos.GSSError, LDAPCommunicationError):
            abort_sasl_negotiation(connection, controls)
            raise
    

    安装 winkerberospip install winkerberos

    在您的脚本中,使用以下代码(connect_timeoutmodereceive_timeout 参数仅作为示例,可以省略或更改):

    import ldap
    import ldap3kerberos
    
    server = ldap3.Server(fqdn, connect_timeout=10, mode=ldap3.IP_V4_ONLY)
    conn = ldap3kerberos.Connection(
        server, authentication=ldap3.SASL, sasl_mechanism=ldap3.GSSAPI,
        auto_bind=True, receive_timeout=10
    )
    

    如果您有多个用于 AD 域的域控制器服务器,请确保您连接到某个特定的服务器,否则您将收到异常:

    winkerberos.GSSError: SSPI: InitializeSecurityContext: The specified target is unknown or unreachable

    【讨论】:

      【解决方案3】:

      我也无法在 Windows 上安装 gssapi 模块,但我确实设法让 ldap3 模块在 Windows 上使用如下代码对 Active Directory 进行身份验证:

      import ssl
      import ldap3
      
      tls_configuration = ldap3.Tls(validate=ssl.CERT_NONE,
                                    version=ssl.PROTOCOL_TLSv1_2)
      server = ldap3.Server(host='domaincontroller.example.com', port=636,
                            use_ssl=True, tls=tls_configuration,
                            get_info=ldap3.ALL)
      con = ldap3.Connection(server, version=3,
                             auto_bind=True,
                             raise_exceptions=True,
                             user='EXAMPLE\\username',
                             password='MySecret',
                             authentication=ldap3.NTLM)
      

      【讨论】:

      • 是的,但这不进行 Kerberos 身份验证,您必须提供用户名和密码。 ://
      猜你喜欢
      • 2015-09-02
      • 1970-01-01
      • 2011-01-23
      • 2011-07-28
      • 1970-01-01
      • 1970-01-01
      • 2016-09-22
      • 2016-11-30
      • 1970-01-01
      相关资源
      最近更新 更多