diff --git a/docs/index.rst b/docs/index.rst index 0dc97d5..e4bb3ac 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -81,6 +81,8 @@ directives: object details. Default: ``list`` (all). ``LDAP_USER_OBJECT_FILTER`` The filter to use when searching for a user object. Default: '(&(objectclass=Person)(userPrincipalName=%s))' +``LDAP_USERS_OBJECT_FILTER`` The filter to use when searching for users objects. + Default: 'objectclass=Person' ``LDAP_USER_GROUPS_FIELD`` The field to return when searching for a user's groups. Default: 'memberOf'. ``LDAP_GROUPS_OBJECT_FILTER`` The filter to use when searching for groups objects. diff --git a/examples/basic_auth/app.py b/examples/basic_auth/app.py index 2cff66f..12bad8b 100644 --- a/examples/basic_auth/app.py +++ b/examples/basic_auth/app.py @@ -2,10 +2,13 @@ from flask_simpleldap import LDAP app = Flask(__name__) -# app.config['LDAP_HOST'] = 'ldap.example.org' # defaults to localhost +#app.config["LDAP_HOST"] = "ldap.example.org" # defaults to localhost app.config["LDAP_BASE_DN"] = "OU=users,dc=example,dc=org" app.config["LDAP_USERNAME"] = "CN=user,OU=Users,DC=example,DC=org" app.config["LDAP_PASSWORD"] = "password" +app.config["LDAP_USER_OBJECT_FILTER"] = "(&(objectclass=inetOrgPerson)(uid=%s))" +app.config["LDAP_USERS_OBJECT_FILTER"] = "objectclass=inetOrgPerson" +app.config["LDAP_USER_FIELDS"] = ["cn", "uid"] ldap = LDAP(app) diff --git a/examples/basic_auth/app_oldap.py b/examples/basic_auth/app_oldap.py index 89edb07..dce343b 100644 --- a/examples/basic_auth/app_oldap.py +++ b/examples/basic_auth/app_oldap.py @@ -14,6 +14,7 @@ app.config["LDAP_OPENLDAP"] = True app.config["LDAP_OBJECTS_DN"] = "dn" app.config["LDAP_USER_OBJECT_FILTER"] = "(&(objectclass=inetOrgPerson)(uid=%s))" +app.config["LDAP_USERS_OBJECT_FILTER"] = "objectclass=inetOrgPerson" # Groups configuration app.config["LDAP_GROUP_MEMBERS_FIELD"] = "uniquemember" diff --git a/flask_simpleldap/__init__.py b/flask_simpleldap/__init__.py index ba5afd9..6d73cfd 100644 --- a/flask_simpleldap/__init__.py +++ b/flask_simpleldap/__init__.py @@ -45,16 +45,16 @@ def init_app(app): app.config.setdefault("LDAP_BASE_DN", None) app.config.setdefault("LDAP_OBJECTS_DN", "distinguishedName") app.config.setdefault("LDAP_USER_FIELDS", []) - app.config.setdefault( - "LDAP_USER_OBJECT_FILTER", "(&(objectclass=Person)(userPrincipalName=%s))" - ) app.config.setdefault("LDAP_USER_GROUPS_FIELD", "memberOf") + app.config.setdefault("LDAP_USER_OBJECT_FILTER", + "(&(objectclass=Person)(userPrincipalName=%s))") + app.config.setdefault("LDAP_USERS_OBJECT_FILTER", + "objectclass=Person") app.config.setdefault("LDAP_GROUP_FIELDS", []) - app.config.setdefault("LDAP_GROUPS_OBJECT_FILTER", "objectclass=Group") - app.config.setdefault( - "LDAP_GROUP_OBJECT_FILTER", "(&(objectclass=Group)(userPrincipalName=%s))" - ) app.config.setdefault("LDAP_GROUP_MEMBERS_FIELD", "member") + app.config.setdefault("LDAP_GROUP_OBJECT_FILTER", + "(&(objectclass=Group)(userPrincipalName=%s))") + app.config.setdefault("LDAP_GROUPS_OBJECT_FILTER", "objectclass=Group") app.config.setdefault("LDAP_LOGIN_VIEW", "login") app.config.setdefault("LDAP_REALM_NAME", "LDAP authentication") app.config.setdefault("LDAP_OPENLDAP", False) @@ -63,11 +63,14 @@ def init_app(app): app.config.setdefault("LDAP_CUSTOM_OPTIONS", None) if app.config["LDAP_USE_SSL"] or app.config["LDAP_USE_TLS"]: - ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, + ldap.OPT_X_TLS_NEVER) if app.config["LDAP_REQUIRE_CERT"]: - ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) - ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, app.config["LDAP_CERT_PATH"]) + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, + ldap.OPT_X_TLS_DEMAND) + ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, + app.config["LDAP_CERT_PATH"]) if app.config["LDAP_BASE_DN"] is None: raise LDAPException("LDAP_BASE_DN cannot be None!") @@ -168,9 +171,45 @@ def bind_user(self, username, password): except ldap.LDAPError: return - def get_object_details( - self, user=None, group=None, query_filter=None, dn_only=False - ): + def get_users(self, fields=None, dn_only=False): + """Returns a ``list`` with the users in base dn + or empty ``list`` if unsuccessful. + + LDAP query setting is ``LDAP_USERS_OBJECT_FILTER`` + + :param fields: list of user fields to retrieve. + if ``None`` or empty, default user fields + ``LDAP_USER_FIELDS`` is used + :param bool dn_only: If we should only retrieve the object's + distinguished name or not. Default: ``False``. + :type fields: list + """ + conn = self.bind + try: + fields = fields or current_app.config["LDAP_USER_FIELDS"] + if current_app.config["LDAP_OPENLDAP"]: + records = conn.search_s( + current_app.config["LDAP_BASE_DN"], ldap.SCOPE_SUBTREE, + current_app.config["LDAP_USERS_OBJECT_FILTER"], + fields) + else: + records = conn.search_s( + current_app.config["LDAP_BASE_DN"], ldap.SCOPE_SUBTREE, + current_app.config["LDAP_USERS_OBJECT_FILTER"], + fields) + conn.unbind_s() + if records: + if dn_only: + return [r[0] for r in records] + else: + return [r[1] for r in records] + else: + return [] + except ldap.LDAPError as e: + raise LDAPException(self.error(e.args)) + + def get_object_details(self, user=None, group=None, query_filter=None, + dn_only=False): """Returns a ``dict`` with the object's (user or group) details. :param str user: Username of the user object you want details for. @@ -371,10 +410,10 @@ def wrapped(*args, **kwargs): if g.user is None: next_path = request.full_path or request.path if next_path == "/?": - return redirect(url_for(current_app.config["LDAP_LOGIN_VIEW"])) - return redirect( - url_for(current_app.config["LDAP_LOGIN_VIEW"], next=next_path) - ) + return redirect( + url_for(current_app.config["LDAP_LOGIN_VIEW"])) + return redirect(url_for(current_app.config["LDAP_LOGIN_VIEW"], + next=next_path)) return func(*args, **kwargs) return wrapped