Django Auth LDAP - 使用 sAMAccountName 直接绑定

问题描述 投票:0回答:7

有两种使用 Django Auth LDAP 对用户进行身份验证的方法

  1. 搜索/绑定和
  2. 直接绑定。

第一个涉及匿名或使用固定帐户连接到 LDAP 服务器并搜索身份验证用户的可分辨名称。然后我们可以尝试再次使用用户的密码进行绑定。

第二种方法是从用户的用户名中获取用户的 DN,并尝试直接绑定为用户。

我希望能够使用尝试访问应用程序的用户的用户 ID (sAMAccountName) 和密码进行直接绑定。请告诉我是否有办法实现这一目标?目前,由于下面解释的问题,我似乎无法完成这项工作。

在我的例子中,LDAP 中用户的 DN 具有以下格式

**'CN=Steven Jones,OU=Users,OU=Central,OU=US,DC=client,DC=corp'**

这基本上翻译为 'CN=FirstName LastName,OU=Users,OU=Central,OU=US,DC=client,DC=corp'

这阻止我使用直接绑定,因为用户的 sAMAccountNamesjones,这是与用户名 (%user) 相对应的参数,我无法找到一种方法来构建正确的 AUTH_LDAP_USER_DN_TEMPLATE 用于派生用户的 DN。

由于上述问题,我现在使用搜索/绑定,但这要求我在 AUTH_LDAP_BIND_DNAUTH_LDAP_BIND_PASSWORD 中指定固定的用户凭据。

这是我当前的settings.py配置

AUTH_LDAP_SERVER_URI = "ldap://10.5.120.161:389"
AUTH_LDAP_BIND_DN='CN=Steven Jones,OU=Users,OU=Central,OU=US,DC=client,DC=corp'
AUTH_LDAP_BIND_PASSWORD='fga.1234'
#AUTH_LDAP_USER_DN_TEMPLATE = 'CN=%(user)s,OU=Appl Groups,OU=Central,OU=US,DC=client,DC=corp'
AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
    LDAPSearch("OU=Users, OU=Central,OU=US,DC=client,DC=corp",ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)"),
    LDAPSearch("OU=Users,OU=Regional,OU=Locales,OU=US,DC=client,DC=corp",ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)"),
    )
AUTH_LDAP_USER_ATTR_MAP = {"first_name": "givenName", "last_name": "sn","email":"mail"}
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("CN=GG_BusinessApp_US,OU=Appl Groups,OU=Central,OU=US,DC=client,DC=corp",ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_REQUIRE_GROUP = 'CN=GG_BusinessApp_US,OU=Appl Groups,OU=Central,OU=US,DC=client,DC=corp'

期待这里优秀人士的一些指导。

python django active-directory django-authentication django-auth-ldap
7个回答
10
投票

我也有同样的问题。

我在现已删除的 bitbucket 存储库中遇到了票证 21。 (

cant-bind-and-search-on-activedirectory
)。这些问题没有迁移到他们的github,但作者提出了一种方法来更改
django-auth-ldap
的库文件,以便它可以直接绑定。

归结为更改

<python library path>/django_auth_ldap/backend.py
以在
_authenticate_user_dn
中包含两行:

if sticky and ldap_settings.AUTH_LDAP_USER_SEARCH:
    self._search_for_user_dn()

我能够让它在运行 Arch Linux 3.9.8-1-ARCH 的本地计算机上运行,但我无法在运行 Ubuntu 13.04 的开发服务器上复制它。

希望这能有所帮助。


5
投票

(这实际上是对 @amethystdragon 答案的评论,但它是一堆代码,因此作为单独的答案发布。) django_auth_ldap 1.2.5 似乎仍然存在问题。这是一个更新的补丁。如果您不想或无法修改源代码,可以进行猴子修补。只需将此代码放入例如即可。

settings.py
结束。 (是的,我知道猴子修补很丑陋。)

import ldap
from django_auth_ldap import backend

def monkey(self, password):
  """
  Binds to the LDAP server with the user's DN and password. Raises
  AuthenticationFailed on failure.
  """
  if self.dn is None:
    raise self.AuthenticationFailed("failed to map the username to a DN.")

  try:
    sticky = self.settings.BIND_AS_AUTHENTICATING_USER

    self._bind_as(self.dn, password, sticky=sticky)

    #### The fix -->
    if sticky and self.settings.USER_SEARCH:
      self._search_for_user_dn()
    #### <-- The fix

  except ldap.INVALID_CREDENTIALS:
    raise self.AuthenticationFailed("user DN/password rejected by LDAP server.")

backend._LDAPUser._authenticate_user_dn = monkey

1
投票

我也遇到了这个问题,但我不想修改

settings.py
文件。对我来说,解决方法是注释掉“AUTH_LDAP_USER_DN_TEMPLATE =”uid=%(user)s,ou=path,dc=to,dc=domain”这一行。我还添加了
NestedActiveDirectoryGroupType
作为故障排除的一部分。不确定是否有必要,但它现在正在工作,所以我要离开它。这是我的
ldap_config.py
文件。

import ldap

# Server URI
AUTH_LDAP_SERVER_URI = "ldap://urlForLdap"

# The following may be needed if you are binding to Active Directory.
AUTH_LDAP_CONNECTION_OPTIONS = {
       # ldap.OPT_DEBUG_LEVEL: 1,
    ldap.OPT_REFERRALS: 0
}

# Set the DN and password for the NetBox service account.
AUTH_LDAP_BIND_DN = "CN=Netbox,OU=xxx,DC=xxx,DC=xxx"
AUTH_LDAP_BIND_PASSWORD = "password"

# Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert.
# Note that this is a NetBox-specific setting which sets:
#     ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
LDAP_IGNORE_CERT_ERRORS = True

from django_auth_ldap.config import LDAPSearch, NestedActiveDirectoryGroupType

# This search matches users with the sAMAccountName equal to the provided username. This is required if the user's
# username is not in their DN (Active Directory).
AUTH_LDAP_USER_SEARCH = LDAPSearch("OU=xxx,DC=xxx,DC=xxx",
                                    ldap.SCOPE_SUBTREE,
                                    "(sAMAccountName=%(user)s)")

# If a user's DN is producible from their username, we don't need to search.
# AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,dc=corp,dc=loc"

# You can map user attributes to Django attributes as so.
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail"
}

from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, NestedActiveDirectoryGroupType

# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group
# heirarchy.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=xxx,dc=xxx", ldap.SCOPE_SUBTREE,
                                    "(objectClass=group)")
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()

# Define a group required to login.
AUTH_LDAP_REQUIRE_GROUP = "CN=NetBox_Users,OU=NetBox,OU=xxx,DC=xxx,DC=xxx"

# Define special user types using groups. Exercise great caution when assigning superuser status.
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
    "is_active": "CN=NetBox_Active,OU=NetBox,OU=xxx,DC=xxx,DC=xxx",
    "is_staff": "CN=NetBox_Staff,OU=NetBox,OU=xxx,DC=xxx,DC=xxx",
    "is_superuser": "CN=NetBox_Superuser,OU=NetBox,OU=xxx,DC=xxx,DC=xxx"
}

# For more granular permissions, we can map LDAP groups to Django groups.
AUTH_LDAP_FIND_GROUP_PERMS = True

# Cache groups for one hour to reduce LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

0
投票

我也遇到了这个问题,旧的 ldap 服务器有一个以 uid 开头的 dn,但新服务器的 DN 以 CN('Steven Jones')开头。我在setting.py中使用了这个配置(它为我解决了这个问题):

AUTH_LDAP_BIND_DN = 'CN=adreader,CN=Users,DC=xxx, DC=yyy'

from django_auth_ldap.config import LDAPSearch
import ldap
AUTH_LDAP_USER_SEARCH = LDAPSearch(base_dn='ou=People, ou=xxx, dc=yyy, dc=zzz, 
  scope=ldap.SCOPE_SUBTREE, filterstr='(sAMAccountName=%(user)s)')

0
投票

我认为使用直接绑定(如下所示),然后在登录界面中传递通用名称就可以完成这项工作,因此不需要设置静态身份验证凭据。

AUTH_LDAP_USER_DN_TEMPLATE = "CN=%(user)s,OU=users,OU=OR-TN,DC=OrangeTunisie,DC=intra"

0
投票

上述答案对我来说不起作用,但我找到了一种让它发挥作用的方法。 技巧是使用 sAMAAcountname 与域名结合进行绑定。

  1. 修改模板 DN,以使其使用 [电子邮件受保护] 格式。
  2. 使用修改后的猴子补丁来查找并存储真实用户 CN (self._user_dn)。

设置:

AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True
AUTH_LDAP_USER_DN_TEMPLATE = '%(user)[email protected]'

补丁:

import ldap
from django_auth_ldap import backend

def monkey(self, password):
    """
    Binds to the LDAP server with the user's DN and password. Raises
    AuthenticationFailed on failure.
    """
    if self.dn is None:
        raise self.AuthenticationFailed("failed to map the username to a DN.")

    try:
        sticky = self.settings.BIND_AS_AUTHENTICATING_USER

    self._bind_as(self.dn, password, sticky=sticky)

    # Search for the user DN -->
    if sticky and self.settings.USER_SEARCH:
        self._user_dn = self._search_for_user_dn()

    except ldap.INVALID_CREDENTIALS:
        raise self.AuthenticationFailed("user DN/password rejected by LDAP server.")

backend._LDAPUser._authenticate_user_dn = monkey

0
投票

我遇到了同样的问题,但是(至少在我的设置中)我发现解决方案并不那么困难,甚至不需要任何猴子修补。

在我看来,命名

AUTH_LDAP_USER_DN_TEMPLATE
有点误导(@jan-staal 的答案向我指出了这一点),因为它不一定需要可分辨名称 (DN)。模块
django-auth-ldap
调用
python-ldap
LDAPObject.simple_bind_s(username, pw)
函数,其中您在
AUTH_LDAP_USER_DN_TEMPLATE
中提供的任何内容都将用作用户名,并且接受多个身份验证快捷方式。我在 jupyter 笔记本中使用
python-ldap
设置了一个简单的测试连接,如下所示:

import ldap
str_ldap_server = "ldap://internal.company.com"
# use sAMAccountName and the ldap uri
username = "[email protected]"  
# alternatively use the company domain name and sAMAccountName
# username = r"company\sjones"
pw = "topsecret"
conn = ldap.initialize(str_ldap_server)
conn.simple_bind_s(username, pw)
conn.whoami_s()

两个用户名选项都返回给我

u:company\\sjones
,确认连接成功

重要:提供用户名的第一个变体不一定等同于您的ldap的

userPrincipalName
!在我的示例中,我的 userPrincipalName 是 [email protected],但绑定需要 [email protected](以匹配 ldap url)

无论如何,通过上面的连接测试,我发现以下设置在 django 中对我有用:

AUTH_LDAP_SERVER_URI = "ldap://internal.company.com"
AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True  # this is probably not necessary, since there is not initial bind to perform a search
AUTH_LDAP_USER_DN_TEMPLATE = '%(user)[email protected]'

我希望这对某人有帮助。 :)

我的设置是

  • Django==4.2.6
  • django-auth-ldap==4.8.0 与
  • python-ldap==3.4.4
© www.soinside.com 2019 - 2024. All rights reserved.