Skip to content

Commit

Permalink
Allow users to configure group search filter and attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
kinow committed Jul 9, 2020
1 parent 65b234a commit 31bdcf5
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 8 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,35 @@ c.LDAPAuthenticator.allowed_groups = [
]
```

#### `LDAPAuthenticator.group_filter` ####

The LDAP group search filter.

The default value is a LDAP OR search that looks like the following:

```
(|(member={userdn})(uniqueMember={userdn})(memberUid={uid}))
```

So it basically compares the `userdn` attribute against the `member` attribute,
then against the `uniqueMember`, and finally checks the `memberUid` against
the `uid`.

If you modify this value, you probably want to change `group_attributes` too.
Here is an example that should work with OpenLDAP servers.

```
(member={userdn})
```

#### `LDAPAuthenticator.group_attributes` ####

A list of attributes used when searching for LDAP groups.

By default uses `member`, `uniqueMember`, and `memberUid`. Certain
servers may reject invalid values causing exceptions during
authentication.

#### `LDAPAuthenticator.valid_username_regex` ####

All usernames will be checked against this before being sent
Expand Down
32 changes: 24 additions & 8 deletions ldapauthenticator/ldapauthenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ def _server_port_default(self):
""",
)

group_filter = Unicode(
config=True,
default_value="(|(member={userdn})(uniqueMember={userdn})(memberUid={uid}))",
help="""
The search filter used to locate groups.
Certain server types may use different values, and may also
reject invalid values by raising exceptions.
""",
)

group_attributes = List(
config=True,
default_value=["member", "uniqueMember", "memberUid"],
help="List of attributes to be searched",
)

# FIXME: Use something other than this? THIS IS LAME, akin to websites restricting things you
# can use in usernames / passwords to protect from SQL injection!
valid_username_regex = Unicode(
Expand Down Expand Up @@ -428,18 +445,17 @@ def authenticate(self, handler, data):
return None

if self.allowed_groups:
if not self.group_filter or not self.group_attributes:
self.log.warning(
"Missing group_filter or group_attributes. Both are required."
)
return None
self.log.debug("username:%s Using dn %s", username, userdn)
found = False
for group in self.allowed_groups:
group_filter = (
"(|"
"(member={userdn})"
"(uniqueMember={userdn})"
"(memberUid={uid})"
")"
)
group_filter = self.group_filter
group_filter = group_filter.format(userdn=userdn, uid=username)
group_attributes = ["member", "uniqueMember", "memberUid"]
group_attributes = self.group_attributes
found = conn.search(
group,
search_scope=ldap3.BASE,
Expand Down
2 changes: 2 additions & 0 deletions ldapauthenticator/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ def authenticator():
authenticator.escape_userdn = True
authenticator.attributes = ["uid", "cn", "mail", "ou"]
authenticator.use_lookup_dn_username = False
authenticator.group_filter = '(|(member={userdn})(uniqueMember={userdn})(memberUid={uid}))'
authenticator.group_attributes = ["member", "uniqueMember", "memberUid"]

authenticator.allowed_groups = [
"cn=admin_staff,ou=people,dc=planetexpress,dc=com",
Expand Down
12 changes: 12 additions & 0 deletions ldapauthenticator/tests/test_ldapauthenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,15 @@ async def test_ldap_auth_state_attributes(authenticator):
)
assert authorized["name"] == "fry"
assert authorized["auth_state"] == {"employeeType": ["Delivery boy"]}


async def test_ldap_auth_state_attributes2(authenticator):
authenticator.group_filter = "(cn=ship_crew)"
authenticator.group_attributes = ["cn"]
authenticator.auth_state_attributes = ["description"]
# proper username and password in allowed group
authorized = await authenticator.get_authenticated_user(
None, {"username": "leela", "password": "leela"}
)
assert authorized["name"] == "leela"
assert authorized["auth_state"] == {"description": ["Mutant"]}

0 comments on commit 31bdcf5

Please sign in to comment.