Skip to content

Commit

Permalink
add AUTH_LDAP_USE_NESTED_GROUPS_FOR_ROLES flag which enable getting n…
Browse files Browse the repository at this point in the history
…ested groups from ms active directory
  • Loading branch information
Stanislav Lysikov committed Nov 27, 2023
1 parent ba63c5c commit a5e679d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 6 deletions.
10 changes: 6 additions & 4 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ Use config.py to configure the following parameters. By default it will use SQLL
| | | |
| | It authenticates with "format-userexample".| |
+----------------------------------------+--------------------------------------------+-----------+
| AUTH_LDAP_USE_NESTED_GROUPS_FOR_ROLES | Get users nested groups from LDAP(MS AD) | No |
+----------------------------------------+--------------------------------------------+-----------+
| AUTH_ROLE_ADMIN | Configure the name of the admin role. | No |
+----------------------------------------+--------------------------------------------+-----------+
| AUTH_ROLE_PUBLIC | Special Role that holds the public | No |
Expand Down Expand Up @@ -333,10 +335,10 @@ It should be a long random bytes or str. For example, copy the output of this to

Using config.py
---------------

My favorite way, and the one I advise if you are building a medium to large size application
is to place all your configuration keys on a config.py file

Next you only have to import them to the Flask app object, like this
::

Expand All @@ -351,10 +353,10 @@ Take a look at the skeleton `config.py <https://github.com/dpgaspar/Flask-AppBui
Using JMESPath to map user registration role
--------------------------------------------

If user self registration is enabled and ``AUTH_USER_REGISTRATION_ROLE_JMESPATH`` is set, it is
If user self registration is enabled and ``AUTH_USER_REGISTRATION_ROLE_JMESPATH`` is set, it is
used as a `JMESPath <http://jmespath.org/>`_ expression to evalate user registration role. The input
values is ``userinfo`` dict, returned by ``get_oauth_user_info`` function of Security Manager.
Usage of JMESPath expressions requires `jmespath <https://pypi.org/project/jmespath/>`_ package
Usage of JMESPath expressions requires `jmespath <https://pypi.org/project/jmespath/>`_ package
to be installed.

In case of Google OAuth, userinfo contains user's email that can be used to map some users as admins
Expand Down
38 changes: 36 additions & 2 deletions flask_appbuilder/security/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ def __init__(self, appbuilder):
app.config.setdefault("AUTH_LDAP_FIRSTNAME_FIELD", "givenName")
app.config.setdefault("AUTH_LDAP_LASTNAME_FIELD", "sn")
app.config.setdefault("AUTH_LDAP_EMAIL_FIELD", "mail")
# Nested groups options
app.config.setdefault("AUTH_LDAP_USE_NESTED_GROUPS_FOR_ROLES", False)

# Rate limiting
app.config.setdefault("AUTH_RATE_LIMITED", False)
Expand Down Expand Up @@ -495,6 +497,10 @@ def auth_ldap_tls_certfile(self):
def auth_ldap_tls_keyfile(self):
return self.appbuilder.get_app.config["AUTH_LDAP_TLS_KEYFILE"]

@property
def auth_ldap_use_nested_groups_for_roles(self):
return self.appbuilder.get_app.config["AUTH_LDAP_USE_NESTED_GROUPS_FOR_ROLES"]

@property
def openid_providers(self):
return self.appbuilder.get_app.config["OPENID_PROVIDERS"]
Expand Down Expand Up @@ -963,11 +969,39 @@ def _search_ldap(self, ldap, con, username):
user_dn = search_result[0][0]
# extract the other attributes
user_info = search_result[0][1]
# return
return user_dn, user_info
except (IndexError, NameError):
return None, None

# get nested groups for user
if self.auth_ldap_use_nested_groups_for_roles:

Check warning on line 976 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L976

Added line #L976 was not covered by tests
log.debug("Nested groups for LDAP enabled.")
# filter for microsoft active directory only
nested_groups_filter_str = (
f"(&(objectCategory=Group)(member:1.2.840.113556.1.4.1941:={user_dn}))"
)
nested_groups_request_fields = ["cn"]

nested_groups_search_result = con.search_s(

Check warning on line 984 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L983-L984

Added lines #L983 - L984 were not covered by tests
self.auth_ldap_search,
ldap.SCOPE_SUBTREE,
nested_groups_filter_str,
nested_groups_request_fields,

Check warning on line 988 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L988

Added line #L988 was not covered by tests
)
log.debug(

Check warning on line 990 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L990

Added line #L990 was not covered by tests
"LDAP search for nested groups returned: %s",
nested_groups_search_result,
)

Check warning on line 993 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L993

Added line #L993 was not covered by tests

nested_groups = [

Check warning on line 995 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L995

Added line #L995 was not covered by tests
x[0].encode() for x in nested_groups_search_result if x[0] is not None
]
log.debug("LDAP nested groups for users: %s", nested_groups)

user_info[self.auth_ldap_group_field] = nested_groups

Check warning on line 1001 in flask_appbuilder/security/manager.py

View check run for this annotation

Codecov / codecov/patch

flask_appbuilder/security/manager.py#L1001

Added line #L1001 was not covered by tests
# return
return user_dn, user_info

def _ldap_calculate_user_roles(
self, user_attributes: Dict[str, bytes]
) -> List[str]:
Expand Down

0 comments on commit a5e679d

Please sign in to comment.