# Python OpenVPN LDAP Auth
[![PyPI license](https://img.shields.io/pypi/l/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)
[![PyPI status](https://img.shields.io/pypi/status/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)
[![PyPI version shields.io](https://img.shields.io/pypi/v/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)
![main build status](https://github.com/phihos/Python-OpenVPN-LDAP-Auth/actions/workflows/test.yml/badge.svg?branch=main)
An auth verify script for [OpenVPN](https://community.openvpn.net) to authenticate via LDAP. Each VPN login is
forwarded to this script and the script in turn attempts a simple bind against the specified LDAP server. When the bind
is successful the script returns exit code 0 telling OpenVPN that the credentials are valid.
Although there already is the [openvpn-auth-ldap](https://github.com/threerings/openvpn-auth-ldap) plugin I felt the
need to write this auth script. First the source code is more accessible due to it being written in Python. Second it
offers more possibilities regarding
OpenVPN's [`static-challenge`](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) parameter (see
below).
The downsides of using a script instead of a C-plugin
are [less performance and slightly reduced security](https://openvpn.net/community-resources/using-alternative-authentication-methods/).
If you are fine with that go ahead.
## Quickstart
Install the package via pip:
```shell
pip install openvpn-ldap-auth
```
Then create `/etc/openvpn/ldap.yaml`:
```yaml
ldap:
url: 'ldaps://first.ldap.tld:636/ ldaps://second.ldap.tld:636/'
bind_dn: 'uid=readonly,dc=example,dc=org'
password: 'somesecurepassword'
timeout: 5 # (optional) wait this many seconds for connection and response
authorization:
base_dn: 'ou=people,dc=example,dc=org'
search_filter: '(uid={})' # optional, {} will be replaced with the username
static_challenge: 'ignore' # optional, other values are prepend, append
```
Find out where `openvpn-ldap-auth` lives:
```shell
which openvpn-ldap-auth
```
Add the following line to your OpenVPN server configuration:
```
script-security 2
auth-user-pass-verify /path/to/openvpn-ldap-auth via-file
```
Now you can start your OpenVPN server and try to connect with a client.
## Installation
### Single Executable
For those who wish to [sacrifice a little more performance](https://pyinstaller.readthedocs.io/en/stable/operating-mode.html#how-the-one-file-program-works) for not having to install or compile a Python interpreter or you just want to quickly try the script out this option might be interesting.
Each [release](https://github.com/phihos/python-openvpn-ldap-auth/releases) also has executables attached to it: *openvpn-ldap-auth-<distro>-<distro-version>-<arch>*. They are created via [PyInstaller](https://www.pyinstaller.org/) on the respective Linux distro, version and architecture. They might also work on other distros provided they use the same or a later libc version that the distro uses.
**Important: /tmp must not be read only.**
### From Source
Download or clone this repository, cd into it and run
```shell
pip install poetry
poetry install --no-dev
poetry build
pip install --upgrade --find-links=dist openvpn-ldap-auth
```
Exchange `pip` with `pip3` if applicable.
## Configuration
### Static Challenge
If you want users to provide a normal password combined with a one-time-password OpenVPN's
[`static-challenge`](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) parameter is what you
are looking for.
In the client configuration you need to add a line like
```
static-challenge "Enter OTP" 1 # use 0 if the OTP should not be echoed
```
When connecting you will now be prompted for your password and your OTP. By setting `authorization.static_challenge` you
can now influence how the OTP is used:
- *ignore (default)*: Just use the password for binding.
- *prepend*: Prepend the OTP to your password and use that for binding.
- *append*: Append the OTP to your password and use that for binding.
The last two options are useful if your LDAP server offers internal 2FA validation
like [oath-ldap](https://oath-ldap.stroeder.com/).
### Using `via-env`
In the server configuration the following alternative setting is also supported but discouraged:
```
auth-user-pass-verify /path/to/openvpn-ldap-auth via-env
```
OpenVPN's manpage about that topic:
*If method is set to "via-env", OpenVPN will call script with the environmental variables username and password set to
the username/password strings provided by the client. Be aware that this method is insecure on some platforms which
make the environment of a process publicly visible to other unprivileged processes.*
If you still want to use `via-env` make sure to set `script-security` to `3`.
## Running Tests
First make sure to install [Docker](https://docs.docker.com/engine/install/)
with [docker-compose](https://docs.docker.com/compose/install/)
and [tox](https://tox.readthedocs.io/en/latest/install.html). Then run
```shell
tox
```
To run a specific Python-OpenVPN combination run something like
```shell
tox -e python38-openvpn25
```
To see a full list of current environment see the `tool.tox` section in [pyproject.toml](pyproject.toml).
Raw data
{
"_id": null,
"home_page": "https://github.com/phihos/python-openvpn-ldap-auth/",
"name": "openvpn-ldap-auth",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.13,>=3.8",
"maintainer_email": null,
"keywords": "OpenVPN, LDAP",
"author": "Philipp Hossner",
"author_email": "philipph@posteo.de",
"download_url": "https://files.pythonhosted.org/packages/fe/24/2ce9382c289997e0061ad489181e7eaf768dcf7926cb474d9dd86779d0fb/openvpn_ldap_auth-0.1.8.tar.gz",
"platform": null,
"description": "# Python OpenVPN LDAP Auth\n\n[![PyPI license](https://img.shields.io/pypi/l/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)\n[![PyPI status](https://img.shields.io/pypi/status/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)\n[![PyPI version shields.io](https://img.shields.io/pypi/v/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/openvpn-ldap-auth.svg)](https://pypi.python.org/pypi/openvpn-ldap-auth/)\n![main build status](https://github.com/phihos/Python-OpenVPN-LDAP-Auth/actions/workflows/test.yml/badge.svg?branch=main)\n\nAn auth verify script for [OpenVPN](https://community.openvpn.net) to authenticate via LDAP. Each VPN login is\nforwarded to this script and the script in turn attempts a simple bind against the specified LDAP server. When the bind\nis successful the script returns exit code 0 telling OpenVPN that the credentials are valid.\n\nAlthough there already is the [openvpn-auth-ldap](https://github.com/threerings/openvpn-auth-ldap) plugin I felt the\nneed to write this auth script. First the source code is more accessible due to it being written in Python. Second it\noffers more possibilities regarding\nOpenVPN's [`static-challenge`](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) parameter (see\nbelow).\n\nThe downsides of using a script instead of a C-plugin\nare [less performance and slightly reduced security](https://openvpn.net/community-resources/using-alternative-authentication-methods/).\nIf you are fine with that go ahead.\n\n## Quickstart\n\nInstall the package via pip:\n\n```shell\npip install openvpn-ldap-auth\n```\n\nThen create `/etc/openvpn/ldap.yaml`:\n\n```yaml\nldap:\n url: 'ldaps://first.ldap.tld:636/ ldaps://second.ldap.tld:636/'\n bind_dn: 'uid=readonly,dc=example,dc=org'\n password: 'somesecurepassword'\n timeout: 5 # (optional) wait this many seconds for connection and response\nauthorization:\n base_dn: 'ou=people,dc=example,dc=org'\n search_filter: '(uid={})' # optional, {} will be replaced with the username\n static_challenge: 'ignore' # optional, other values are prepend, append \n```\n\nFind out where `openvpn-ldap-auth` lives:\n\n```shell\nwhich openvpn-ldap-auth\n```\n\nAdd the following line to your OpenVPN server configuration:\n\n```\nscript-security 2\nauth-user-pass-verify /path/to/openvpn-ldap-auth via-file\n```\n\nNow you can start your OpenVPN server and try to connect with a client.\n\n## Installation\n\n### Single Executable\n\nFor those who wish to [sacrifice a little more performance](https://pyinstaller.readthedocs.io/en/stable/operating-mode.html#how-the-one-file-program-works) for not having to install or compile a Python interpreter or you just want to quickly try the script out this option might be interesting.\nEach [release](https://github.com/phihos/python-openvpn-ldap-auth/releases) also has executables attached to it: *openvpn-ldap-auth-<distro>-<distro-version>-<arch>*. They are created via [PyInstaller](https://www.pyinstaller.org/) on the respective Linux distro, version and architecture. They might also work on other distros provided they use the same or a later libc version that the distro uses.\n\n**Important: /tmp must not be read only.**\n\n### From Source\n\nDownload or clone this repository, cd into it and run\n\n```shell\npip install poetry\npoetry install --no-dev\npoetry build\npip install --upgrade --find-links=dist openvpn-ldap-auth\n```\n\nExchange `pip` with `pip3` if applicable.\n\n## Configuration\n\n### Static Challenge\n\nIf you want users to provide a normal password combined with a one-time-password OpenVPN's\n[`static-challenge`](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) parameter is what you\nare looking for.\n\nIn the client configuration you need to add a line like\n\n```\nstatic-challenge \"Enter OTP\" 1 # use 0 if the OTP should not be echoed\n```\n\nWhen connecting you will now be prompted for your password and your OTP. By setting `authorization.static_challenge` you\ncan now influence how the OTP is used:\n\n- *ignore (default)*: Just use the password for binding.\n- *prepend*: Prepend the OTP to your password and use that for binding.\n- *append*: Append the OTP to your password and use that for binding.\n\nThe last two options are useful if your LDAP server offers internal 2FA validation \nlike [oath-ldap](https://oath-ldap.stroeder.com/).\n\n### Using `via-env`\n\nIn the server configuration the following alternative setting is also supported but discouraged:\n\n```\nauth-user-pass-verify /path/to/openvpn-ldap-auth via-env\n```\n\nOpenVPN's manpage about that topic:\n\n*If method is set to \"via-env\", OpenVPN will call script with the environmental variables username and password set to \nthe username/password strings provided by the client. Be aware that this method is insecure on some platforms which \nmake the environment of a process publicly visible to other unprivileged processes.*\n\nIf you still want to use `via-env` make sure to set `script-security` to `3`.\n\n## Running Tests\n\nFirst make sure to install [Docker](https://docs.docker.com/engine/install/)\nwith [docker-compose](https://docs.docker.com/compose/install/)\nand [tox](https://tox.readthedocs.io/en/latest/install.html). Then run\n\n```shell\ntox\n```\n\nTo run a specific Python-OpenVPN combination run something like\n\n```shell\ntox -e python38-openvpn25\n```\n\nTo see a full list of current environment see the `tool.tox` section in [pyproject.toml](pyproject.toml).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "An auth verify script for OpenVPN to authenticate via LDAP.",
"version": "0.1.8",
"project_urls": {
"Homepage": "https://github.com/phihos/python-openvpn-ldap-auth/",
"Repository": "https://github.com/phihos/python-openvpn-ldap-auth/"
},
"split_keywords": [
"openvpn",
" ldap"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "731890a738b7879e0a9982bbac99e762ab7971ba140e7612dc5da7726671f5b5",
"md5": "2e79d9bc04a662c909edaae92098ecdf",
"sha256": "ec819c6ee4f2dc78b4f8ab8dd115ea25be2b7b4c9393190e0d8ff34c8031ecaf"
},
"downloads": -1,
"filename": "openvpn_ldap_auth-0.1.8-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2e79d9bc04a662c909edaae92098ecdf",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.13,>=3.8",
"size": 7225,
"upload_time": "2024-11-22T17:09:39",
"upload_time_iso_8601": "2024-11-22T17:09:39.888696Z",
"url": "https://files.pythonhosted.org/packages/73/18/90a738b7879e0a9982bbac99e762ab7971ba140e7612dc5da7726671f5b5/openvpn_ldap_auth-0.1.8-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "fe242ce9382c289997e0061ad489181e7eaf768dcf7926cb474d9dd86779d0fb",
"md5": "18460bc2f13000d5223be2f7196a5aff",
"sha256": "13201a260e89652c65c948f97dcdad426b3740984f51291433c7e820fe403874"
},
"downloads": -1,
"filename": "openvpn_ldap_auth-0.1.8.tar.gz",
"has_sig": false,
"md5_digest": "18460bc2f13000d5223be2f7196a5aff",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.13,>=3.8",
"size": 6795,
"upload_time": "2024-11-22T17:09:40",
"upload_time_iso_8601": "2024-11-22T17:09:40.752858Z",
"url": "https://files.pythonhosted.org/packages/fe/24/2ce9382c289997e0061ad489181e7eaf768dcf7926cb474d9dd86779d0fb/openvpn_ldap_auth-0.1.8.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-22 17:09:40",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "phihos",
"github_project": "python-openvpn-ldap-auth",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "openvpn-ldap-auth"
}