Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble-scripts.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hacker <dd0t@users.sourceforge.net>2014-07-30 08:37:48 +0400
committerStefan Hacker <dd0t@users.sourceforge.net>2014-07-30 08:37:48 +0400
commit3fd78445ba8e9dff59919d643d79adab37c87ebd (patch)
treedfa7915997e008b603f47cc9d60a797afd7f1cd8
parent21235a5a896d120e54c1ac34016cdefa71229b14 (diff)
parentf7e5d8be1fd75d11b04f343e57c873310dd9ddfc (diff)
Merge pull request #1 from mrogaski/master
Enhancement and cleanup of the LDAP bind_dn option.
-rw-r--r--Authenticators/LDAP/LDAPauth.ini3
-rw-r--r--Authenticators/LDAP/LDAPauth.py119
2 files changed, 84 insertions, 38 deletions
diff --git a/Authenticators/LDAP/LDAPauth.ini b/Authenticators/LDAP/LDAPauth.ini
index 9e374e8..13d065e 100644
--- a/Authenticators/LDAP/LDAPauth.ini
+++ b/Authenticators/LDAP/LDAPauth.ini
@@ -4,6 +4,9 @@
id_offset = 1000000000
;Reject users if the authenticator experiences an internal error during authentication
reject_on_error = True
+;Reject users that are not found when bind_dn is used with non-user credentials.
+;Setting this to False will cause a fall-through when the user is not found in LDAP.
+reject_on_miss = True
;Ice configuration
[ice]
diff --git a/Authenticators/LDAP/LDAPauth.py b/Authenticators/LDAP/LDAPauth.py
index dddc887..f323ac1 100644
--- a/Authenticators/LDAP/LDAPauth.py
+++ b/Authenticators/LDAP/LDAPauth.py
@@ -89,6 +89,14 @@
# Finally, it optionally logs in the user with a separate "display_attr" name.
# This allows user1 to log in with the USERNAME "user1" but is displayed in mumble as "User One".
#
+# If you use the bind_dn option, the script will bind with the specified DN
+# and check for the existence of user and (optionally) the group membership
+# before it binds with the username/password. This allows you to use a server
+# which only allows authentication by end users without any search
+# permissions. It also allows you to set the reject_on_miss option to false
+# and let login IDs not found in LDAP fall-through to an alternate
+# authentication scheme.
+#
# Requirements:
# * python >=2.4 and the following python modules:
# * ice-python
@@ -136,7 +144,8 @@ default = { 'ldap':(('ldap_uri', str, 'ldap://127.0.0.1'),
('group_attr', str, 'member')),
'user':(('id_offset', int, 1000000000),
- ('reject_on_error', x2bool, True)),
+ ('reject_on_error', x2bool, True),
+ ('reject_on_miss', x2bool, True)),
'ice':(('host', str, '127.0.0.1'),
('port', int, 6502),
@@ -425,54 +434,88 @@ def do_main_program():
FALL_THROUGH = -2
AUTH_REFUSED = -1
+ # SuperUser is a special login.
if name == 'SuperUser':
debug('Forced fall through for SuperUser')
return (FALL_THROUGH, None, None)
-
- #Otherwise, let's check the LDAP server
+
+ # Otherwise, let's check the LDAP server.
uid = None
- try:
- #Attempt to bind to LDAP server with user-provided credentials
- ldap_conn = ldap.initialize(cfg.ldap.ldap_uri, 0)
- if cfg.ldap.bind_dn:
- bind_dn = cfg.ldap.bind_dn
- bind_pass = cfg.ldap.bind_pass
+ ldap_conn = ldap.initialize(cfg.ldap.ldap_uri, 0)
+ if cfg.ldap.bind_dn:
+ # Bind the functional account to search the directory.
+ bind_dn = cfg.ldap.bind_dn
+ bind_pass = cfg.ldap.bind_pass
+ try:
+ ldap_conn.bind_s(bind_dn, bind_pass)
+ except ldap.INVALID_CREDENTIALS:
+ ldap_conn.unbind()
+ warning('Invalid credentials for bind_dn=' + bind_dn)
+ return (AUTH_REFUSED, None, None)
+ else:
+ # Prevent anonymous authentication.
+ if not pw:
+ warning("No password supplied for user " + name)
+ return (AUTH_REFUSED, None, None)
+
+ # Bind the user account to search the directory.
+ bind_dn = "%s=%s,%s" % (cfg.ldap.username_attr, name, cfg.ldap.users_dn)
+ bind_pass = pw
+ try:
+ ldap_conn.bind_s(bind_dn, bind_pass)
+ except ldap.INVALID_CREDENTIALS:
+ ldap_conn.unbind()
+ warning('User ' + name + ' failed with invalid credentials')
+ return (AUTH_REFUSED, None, None)
+
+ # Search for the user.
+ res = ldap_conn.search_s(cfg.ldap.users_dn, ldap.SCOPE_SUBTREE, '(%s=%s)' % (cfg.ldap.username_attr, name), [cfg.ldap.number_attr, cfg.ldap.display_attr])
+ if len(res) == 0:
+ warning("User " + name + " not found")
+ if cfg.user.reject_on_miss:
+ return (AUTH_REFUSED, None, None)
else:
- bind_dn = "%s=%s,%s" % (cfg.ldap.username_attr, name, cfg.ldap.users_dn)
- bind_pass = pw
- ldap_conn.bind_s(bind_dn, bind_pass)
- res = ldap_conn.search_s(cfg.ldap.users_dn, ldap.SCOPE_SUBTREE, '(%s=%s)' % (cfg.ldap.username_attr, name), [cfg.ldap.number_attr, cfg.ldap.display_attr])
- match = res[0] #Only interested in the first result, as there should only be one match
+ return (FALL_THROUGH, None, None)
+ match = res[0] #Only interested in the first result, as there should only be one match
- #Parse the user information
- uid = int(match[1][cfg.ldap.number_attr][0])
- displayName = match[1][cfg.ldap.display_attr][0]
- debug('User match found, display "' + displayName + '" with UID ' + repr(uid))
+ # Parse the user information.
+ uid = int(match[1][cfg.ldap.number_attr][0])
+ displayName = match[1][cfg.ldap.display_attr][0]
+ debug('User match found, display "' + displayName + '" with UID ' + repr(uid))
- #Optionally check groups
- if cfg.ldap.group_cn != "" :
- debug('Checking group membership for ' + name)
+ # Optionally check groups.
+ if cfg.ldap.group_cn != "" :
+ debug('Checking group membership for ' + name)
- #Search for user in group
- res = ldap_conn.search_s(cfg.ldap.group_cn, ldap.SCOPE_SUBTREE, '(%s=%s=%s,%s)' % (cfg.ldap.group_attr, cfg.ldap.username_attr, name, cfg.ldap.users_dn), [cfg.ldap.number_attr, cfg.ldap.display_attr])
+ #Search for user in group
+ res = ldap_conn.search_s(cfg.ldap.group_cn, ldap.SCOPE_SUBTREE, '(%s=%s=%s,%s)' % (cfg.ldap.group_attr, cfg.ldap.username_attr, name, cfg.ldap.users_dn), [cfg.ldap.number_attr, cfg.ldap.display_attr])
- # Check if the user is a member of the group
- if len(res) < 1:
- debug('User ' + name + ' failed with no group membership')
- return (AUTH_REFUSED, None, None)
+ # Check if the user is a member of the group
+ if len(res) < 1:
+ debug('User ' + name + ' failed with no group membership')
+ return (AUTH_REFUSED, None, None)
- #Unbind and close connection
- ldap_conn.unbind()
-
- #What follows below are various what-if scenarios: authentication failures and successes
-
- #LDAP bind failed - expected to happen if bad login
- except ldap.INVALID_CREDENTIALS:
- warning("User " + name + " failed with wrong password")
+ # Second bind to test user credentials if using bind_dn.
+ if cfg.ldap.bind_dn:
+ # Prevent anonymous authentication.
+ if not pw:
+ warning("No password supplied for user " + name)
return (AUTH_REFUSED, None, None)
-
- #If we get here, the login is correct.
- #Add the user/id combo to cache, then accept:
+
+ bind_dn = "%s=%s,%s" % (cfg.ldap.username_attr, name, cfg.ldap.users_dn)
+ bind_pass = pw
+ try:
+ ldap_conn.bind_s(bind_dn, bind_pass)
+ except ldap.INVALID_CREDENTIALS:
+ ldap_conn.unbind()
+ warning('User ' + name + ' failed with wrong password')
+ return (AUTH_REFUSED, None, None)
+
+ # Unbind and close connection.
+ ldap_conn.unbind()
+
+ # If we get here, the login is correct.
+ # Add the user/id combo to cache, then accept:
self.name_uid_cache[displayName] = uid
debug("Login accepted for " + name)
return (uid + cfg.user.id_offset, displayName, [])