# Flask-SimpleLDAP
Flask-SimpleLDAP provides LDAP authentication for Flask and is compatible with and tested on Python 3.8+.
## Quickstart
First, install Flask-SimpleLDAP:
```shell
pip install flask-simpleldap
```
Flask-SimpleLDAP depends, and will install for you, a recent version of Flask
(2.2.5 or later) and [python-ldap](https://python-ldap.org/).
Please consult the [python-ldap installation instructions](https://www.python-ldap.org/en/latest/installing.html) if you get an error during installation.
Next, add an `LDAP` instance to your code and at least the three
required configuration options. The complete sample from
[examples/basic_auth/app.py](examples/basic_auth/app.py) looks like this:
```python
from flask import Flask, g
from flask_simpleldap import LDAP
app = Flask(__name__)
# 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"
ldap = LDAP(app)
@app.route("/")
@ldap.basic_auth_required
def index():
return f"Welcome, {g.ldap_username}!"
if __name__ == "__main__":
app.run()
```
When the user visits the protected URL, the browser will prompt for the
login and password via the built-in HTTP authentication window. Note that
with the default value of `LDAP_USER_OBJECT_FILTER` the login is expected
to match the [`userPrincipalName` attribute](https://ldapwiki.com/wiki/UserPrincipalName)
of the LDAP user, e.g. `me@mydomain.com`.
Once you get the basic example working, check out the more complex ones:
- [examples/groups](examples/groups) demonstrates using:
- `@ldap.login_required` for form/cookie-based auth, instead of basic HTTP authentication.
- `@ldap.group_required()` to restrict access to pages based on the user's LDAP groups.
- [examples/blueprints](examples/blueprints) implements the same functionality, but uses Flask's
[application factories](https://flask.palletsprojects.com/en/3.0.x/patterns/appfactories/)
and [blueprints](https://flask.palletsprojects.com/en/3.0.x/blueprints/).
## OpenLDAP
Add the `LDAP` instance to your code and depending on your OpenLDAP
configuration, add the following at least `LDAP_USER_OBJECT_FILTER` and
`LDAP_USER_OBJECT_FILTER`.
```python
from flask import Flask, g
from flask_simpleldap import LDAP
app = Flask(__name__)
# Base
app.config["LDAP_REALM_NAME"] = "OpenLDAP Authentication"
app.config["LDAP_HOST"] = "openldap.example.org"
app.config["LDAP_BASE_DN"] = "dc=users,dc=openldap,dc=org"
app.config["LDAP_USERNAME"] = "cn=user,ou=servauth-users,dc=users,dc=openldap,dc=org"
app.config["LDAP_PASSWORD"] = "password"
# OpenLDAP
app.config["LDAP_OBJECTS_DN"] = "dn"
app.config["LDAP_OPENLDAP"] = True
app.config["LDAP_USER_OBJECT_FILTER"] = "(&(objectclass=inetOrgPerson)(uid=%s))"
# Groups
app.config["LDAP_GROUP_MEMBERS_FIELD"] = "uniquemember"
app.config["LDAP_GROUP_OBJECT_FILTER"] = "(&(objectclass=groupOfUniqueNames)(cn=%s))"
app.config["LDAP_GROUP_MEMBER_FILTER"] = "(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))"
app.config["LDAP_GROUP_MEMBER_FILTER_FIELD"] = "cn"
ldap = LDAP(app)
@app.route("/")
@ldap.basic_auth_required
def index():
return f"Welcome, {g.ldap_username}!"
if __name__ == "__main__":
app.run()
```
## Configuration
| Setting | Description |
|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `LDAP_HOST` | The host name or IP address of your LDAP server. Default: `"localhost"`. |
| `LDAP_PORT` | The port number of your LDAP server. Default: `389`. |
| `LDAP_SCHEMA` | The LDAP schema to use between `"ldap"`, `"ldapi"` and `"ldaps"`. Default: `"ldap"`. |
| `LDAP_SOCKET_PATH` | If `LDAP_SCHEMA` is set to `"ldapi"`, the path to the Unix socket path. Default: `"/"`. |
| `LDAP_USERNAME` | **Required**: The username used to bind. |
| `LDAP_PASSWORD` | **Required**: The password used to bind. |
| `LDAP_TIMEOUT` | How long (seconds) a connection can take to be opened before timing out. Default: `10`. |
| `LDAP_LOGIN_VIEW` | Views decorated with `.login_required()` or`.group_required()` will redirect unauthenticated requests to this view. Default: `"login"`. |
| `LDAP_REALM_NAME` | Views decorated with `.basic_auth_required()` will use this as the "realm" part of HTTP Basic Authentication when responding to unauthenticated requests. |
| `LDAP_OPENLDAP` | Set to `True` if your server is running OpenLDAP. Default: `False`. |
| `LDAP_USE_SSL` | Set to `True` if your server uses SSL. Default: `False`. |
| `LDAP_USE_TLS` | Set to `True` if your server uses TLS. Default: `False`. |
| `LDAP_REQUIRE_CERT` | Set to `True` if your server requires a certificate. Default: `False`. |
| `LDAP_CERT_PATH` | Path to the certificate if `LDAP_REQUIRE_CERT` is `True`. |
| `LDAP_CUSTOM_OPTIONS` | `dict` of ldap options you want to set in this format: `{option: value}`. Default: `None`. |
| `LDAP_BASE_DN` | **Required**: The distinguished name to use as the search base. |
| `LDAP_OBJECTS_DN` | The field to use as the objects' distinguished name. Default: `"distinguishedName"`. |
| `LDAP_USER_FIELDS` | `list` of fields to return when searching for a user's object details. Default: `[]` (all). |
| `LDAP_USER_GROUPS_FIELD` | The field to return when searching for a user's groups. Default: `"memberOf"`. |
| `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_GROUP_FIELDS` | `list` of fields to return when searching for a group's object details. Default: `[]` (all). |
| `LDAP_GROUP_MEMBER_FILTER` | The group member filter to use when using OpenLDAP. Default: `"*"`. |
| `LDAP_GROUP_MEMBER_FILTER_FIELD` | The group member filter field to use when using OpenLDAP. Default: `"*"`. |
| `LDAP_GROUP_MEMBERS_FIELD` | The field to return when searching for a group's members. Default: `"member"`. |
| `LDAP_GROUP_OBJECT_FILTER` | The filter to use when searching for a group object. Default: `"(&(objectclass=Group)(userPrincipalName=%s))"`. |
| `LDAP_GROUPS_OBJECT_FILTER` | The filter to use when searching for groups objects. Default: `"objectclass=Group"`. |
Raw data
{
"_id": null,
"home_page": "https://github.com/alexferl/flask-simpleldap",
"name": "Flask-SimpleLDAP",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": null,
"author": "Alexandre Ferland",
"author_email": "me@alexferl.com",
"download_url": "https://files.pythonhosted.org/packages/85/a2/ec5fe979d2272b6e05dc9015df341f7a76324e3d503ea9c6a0992eb41772/Flask-SimpleLDAP-2.0.0.tar.gz",
"platform": null,
"description": "# Flask-SimpleLDAP\nFlask-SimpleLDAP provides LDAP authentication for Flask and is compatible with and tested on Python 3.8+.\n\n## Quickstart\nFirst, install Flask-SimpleLDAP:\n\n```shell\npip install flask-simpleldap\n```\n\nFlask-SimpleLDAP depends, and will install for you, a recent version of Flask\n(2.2.5 or later) and [python-ldap](https://python-ldap.org/).\nPlease consult the [python-ldap installation instructions](https://www.python-ldap.org/en/latest/installing.html) if you get an error during installation.\n\nNext, add an `LDAP` instance to your code and at least the three\nrequired configuration options. The complete sample from\n[examples/basic_auth/app.py](examples/basic_auth/app.py) looks like this:\n\n```python\nfrom flask import Flask, g\nfrom flask_simpleldap import LDAP\n\napp = Flask(__name__)\n# app.config[\"LDAP_HOST\"] = \"ldap.example.org\" # defaults to localhost\napp.config[\"LDAP_BASE_DN\"] = \"OU=users,dc=example,dc=org\"\napp.config[\"LDAP_USERNAME\"] = \"CN=user,OU=Users,DC=example,DC=org\"\napp.config[\"LDAP_PASSWORD\"] = \"password\"\n\nldap = LDAP(app)\n\n@app.route(\"/\")\n@ldap.basic_auth_required\ndef index():\n return f\"Welcome, {g.ldap_username}!\"\n\nif __name__ == \"__main__\":\n app.run()\n```\n\nWhen the user visits the protected URL, the browser will prompt for the\nlogin and password via the built-in HTTP authentication window. Note that\nwith the default value of `LDAP_USER_OBJECT_FILTER` the login is expected\nto match the [`userPrincipalName` attribute](https://ldapwiki.com/wiki/UserPrincipalName)\nof the LDAP user, e.g. `me@mydomain.com`.\n\nOnce you get the basic example working, check out the more complex ones:\n\n- [examples/groups](examples/groups) demonstrates using:\n - `@ldap.login_required` for form/cookie-based auth, instead of basic HTTP authentication.\n - `@ldap.group_required()` to restrict access to pages based on the user's LDAP groups.\n- [examples/blueprints](examples/blueprints) implements the same functionality, but uses Flask's\n[application factories](https://flask.palletsprojects.com/en/3.0.x/patterns/appfactories/)\nand [blueprints](https://flask.palletsprojects.com/en/3.0.x/blueprints/).\n\n\n## OpenLDAP\nAdd the `LDAP` instance to your code and depending on your OpenLDAP\nconfiguration, add the following at least `LDAP_USER_OBJECT_FILTER` and\n`LDAP_USER_OBJECT_FILTER`.\n\n```python\nfrom flask import Flask, g\nfrom flask_simpleldap import LDAP\n\napp = Flask(__name__)\n\n# Base\napp.config[\"LDAP_REALM_NAME\"] = \"OpenLDAP Authentication\"\napp.config[\"LDAP_HOST\"] = \"openldap.example.org\"\napp.config[\"LDAP_BASE_DN\"] = \"dc=users,dc=openldap,dc=org\"\napp.config[\"LDAP_USERNAME\"] = \"cn=user,ou=servauth-users,dc=users,dc=openldap,dc=org\"\napp.config[\"LDAP_PASSWORD\"] = \"password\"\n\n# OpenLDAP\napp.config[\"LDAP_OBJECTS_DN\"] = \"dn\"\napp.config[\"LDAP_OPENLDAP\"] = True\napp.config[\"LDAP_USER_OBJECT_FILTER\"] = \"(&(objectclass=inetOrgPerson)(uid=%s))\"\n\n# Groups\napp.config[\"LDAP_GROUP_MEMBERS_FIELD\"] = \"uniquemember\"\napp.config[\"LDAP_GROUP_OBJECT_FILTER\"] = \"(&(objectclass=groupOfUniqueNames)(cn=%s))\"\napp.config[\"LDAP_GROUP_MEMBER_FILTER\"] = \"(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))\"\napp.config[\"LDAP_GROUP_MEMBER_FILTER_FIELD\"] = \"cn\"\n\nldap = LDAP(app)\n\n@app.route(\"/\")\n@ldap.basic_auth_required\ndef index():\n return f\"Welcome, {g.ldap_username}!\"\n\nif __name__ == \"__main__\":\n app.run()\n```\n\n## Configuration\n| Setting | Description |\n|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `LDAP_HOST` | The host name or IP address of your LDAP server. Default: `\"localhost\"`. |\n| `LDAP_PORT` | The port number of your LDAP server. Default: `389`. |\n| `LDAP_SCHEMA` | The LDAP schema to use between `\"ldap\"`, `\"ldapi\"` and `\"ldaps\"`. Default: `\"ldap\"`. |\n| `LDAP_SOCKET_PATH` | If `LDAP_SCHEMA` is set to `\"ldapi\"`, the path to the Unix socket path. Default: `\"/\"`. |\n| `LDAP_USERNAME` | **Required**: The username used to bind. |\n| `LDAP_PASSWORD` | **Required**: The password used to bind. |\n| `LDAP_TIMEOUT` | How long (seconds) a connection can take to be opened before timing out. Default: `10`. |\n| `LDAP_LOGIN_VIEW` | Views decorated with `.login_required()` or`.group_required()` will redirect unauthenticated requests to this view. Default: `\"login\"`. |\n| `LDAP_REALM_NAME` | Views decorated with `.basic_auth_required()` will use this as the \"realm\" part of HTTP Basic Authentication when responding to unauthenticated requests. |\n| `LDAP_OPENLDAP` | Set to `True` if your server is running OpenLDAP. Default: `False`. |\n| `LDAP_USE_SSL` | Set to `True` if your server uses SSL. Default: `False`. |\n| `LDAP_USE_TLS` | Set to `True` if your server uses TLS. Default: `False`. |\n| `LDAP_REQUIRE_CERT` | Set to `True` if your server requires a certificate. Default: `False`. |\n| `LDAP_CERT_PATH` | Path to the certificate if `LDAP_REQUIRE_CERT` is `True`. |\n| `LDAP_CUSTOM_OPTIONS` | `dict` of ldap options you want to set in this format: `{option: value}`. Default: `None`. |\n| `LDAP_BASE_DN` | **Required**: The distinguished name to use as the search base. |\n| `LDAP_OBJECTS_DN` | The field to use as the objects' distinguished name. Default: `\"distinguishedName\"`. |\n| `LDAP_USER_FIELDS` | `list` of fields to return when searching for a user's object details. Default: `[]` (all). |\n| `LDAP_USER_GROUPS_FIELD` | The field to return when searching for a user's groups. Default: `\"memberOf\"`. |\n| `LDAP_USER_OBJECT_FILTER` | The filter to use when searching for a user object. Default: `\"(&(objectclass=Person)(userPrincipalName=%s))\"` |\n| `LDAP_USERS_OBJECT_FILTER` | The filter to use when searching for users objects. Default: `\"objectclass=Person\"` |\n| `LDAP_GROUP_FIELDS` | `list` of fields to return when searching for a group's object details. Default: `[]` (all). |\n| `LDAP_GROUP_MEMBER_FILTER` | The group member filter to use when using OpenLDAP. Default: `\"*\"`. |\n| `LDAP_GROUP_MEMBER_FILTER_FIELD` | The group member filter field to use when using OpenLDAP. Default: `\"*\"`. |\n| `LDAP_GROUP_MEMBERS_FIELD` | The field to return when searching for a group's members. Default: `\"member\"`. |\n| `LDAP_GROUP_OBJECT_FILTER` | The filter to use when searching for a group object. Default: `\"(&(objectclass=Group)(userPrincipalName=%s))\"`. |\n| `LDAP_GROUPS_OBJECT_FILTER` | The filter to use when searching for groups objects. Default: `\"objectclass=Group\"`. |\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "LDAP authentication extension for Flask",
"version": "2.0.0",
"project_urls": {
"Homepage": "https://github.com/alexferl/flask-simpleldap"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "809b0d4049bd954aad961b148979f2c3fd25f1ca2d6065b30f25d7dcfc746092",
"md5": "119cd05ba970f35021c285be6c329cd9",
"sha256": "8d4ca3173cc83ed1a7b9ca6211a63c68c7e65c97e4456ca2e7916ca87a734cb3"
},
"downloads": -1,
"filename": "Flask_SimpleLDAP-2.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "119cd05ba970f35021c285be6c329cd9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 8595,
"upload_time": "2024-04-03T19:24:01",
"upload_time_iso_8601": "2024-04-03T19:24:01.943824Z",
"url": "https://files.pythonhosted.org/packages/80/9b/0d4049bd954aad961b148979f2c3fd25f1ca2d6065b30f25d7dcfc746092/Flask_SimpleLDAP-2.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "85a2ec5fe979d2272b6e05dc9015df341f7a76324e3d503ea9c6a0992eb41772",
"md5": "ccb2bcd1036740d10fc8ccb5aa301b61",
"sha256": "d829f8163bae6d61d841707fa8a88bdcaae4862332c1acc13864b24ca82eaf25"
},
"downloads": -1,
"filename": "Flask-SimpleLDAP-2.0.0.tar.gz",
"has_sig": false,
"md5_digest": "ccb2bcd1036740d10fc8ccb5aa301b61",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 8825,
"upload_time": "2024-04-03T19:24:03",
"upload_time_iso_8601": "2024-04-03T19:24:03.321543Z",
"url": "https://files.pythonhosted.org/packages/85/a2/ec5fe979d2272b6e05dc9015df341f7a76324e3d503ea9c6a0992eb41772/Flask-SimpleLDAP-2.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-04-03 19:24:03",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "alexferl",
"github_project": "flask-simpleldap",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "flask-simpleldap"
}