我正在使用出色的ldap3软件包,并且尝试与活动目录服务器建立连接,但无需提供纯文本形式的实际凭据。
支持以下SASL机制。
['GSSAPI', 'GSS-SPNEGO', 'EXTERNAL', 'DIGEST-MD5']
我尝试安装GSSAPI软件包,但是在Windows计算机上不起作用。
pip install gssapi
的错误是:
subprocess.CalledProcessError: Command 'krb5-config --libs gssapi' returned non-zero exit status 1.
有人可以提供一个简单的例子吗? 我相信GSS-SPNEGO可能是解决方案,但我在互联网上找不到任何可理解的例子。
答案 0 :(得分:5)
谢谢您提出这个问题。今天我给了它最后一枪,让它起作用。
在此链接中查看戴维德的答案:How to install gssapi python module on windows?
它要求您具有ldap3软件包并安装winkerberos软件包:
pip安装winkerberos
然后,您需要用他链接到replacement kerberos.py的文件替换站点文件(PYTHON_HOME \ Lib \ site-packages \ ldap3 \ protocol \ sasl \ kerberos.py)中的kerberos.py文件。
您需要在替换的kerberos.py文件中更改以下行:
从跑步机上将kerberoswrapper导入为kerberos
更改为
将winkerberos导入为kerberos
然后您可以像这样连接:
from ldap3 import Server, Connection, Tls, SASL, GSSAPI
import ssl
tls = Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1)
server = Server('server_fqdn', use_ssl=True, tls=tls)
c = Connection(server, authentication=SASL, sasl_mechanism=GSSAPI)
c.bind()
print(c.extend.standard.who_am_i())
c.unbind()
将server_fqdn替换为AD服务器的标准域名。
您可能希望将版本值更改为AD服务器使用的任何协议。
如果某人不太杂乱的方法来完成此操作,请输入提示音!
答案 1 :(得分:0)
使用最初的答案并避免猴子打补丁,可以根据提供的there文件和ldap3\core\connection.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
安装 winkerberos :pip install winkerberos
在脚本中,使用以下代码(connect_timeout
,mode
和receive_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