{"id":24453100,"url":"https://github.com/dignajar/another-ldap-auth","last_synced_at":"2025-10-01T15:31:13.888Z","repository":{"id":45174753,"uuid":"186681514","full_name":"dignajar/another-ldap-auth","owner":"dignajar","description":"LDAP Authentication for Nginx, Nginx ingress controller (Kubernetes), and HAProxy via a subrequest.","archived":false,"fork":false,"pushed_at":"2023-05-01T22:49:51.000Z","size":95,"stargazers_count":39,"open_issues_count":7,"forks_count":19,"subscribers_count":7,"default_branch":"master","last_synced_at":"2023-05-13T12:00:48.590Z","etag":null,"topics":["authentication","docker","docker-container","kubernetes","kubernetes-ingress-controller","ldap","nginx"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dignajar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-14T18:51:38.000Z","updated_at":"2023-05-13T10:54:01.000Z","dependencies_parsed_at":"2022-09-24T20:00:19.654Z","dependency_job_id":null,"html_url":"https://github.com/dignajar/another-ldap-auth","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dignajar%2Fanother-ldap-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dignajar%2Fanother-ldap-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dignajar%2Fanother-ldap-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dignajar%2Fanother-ldap-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dignajar","download_url":"https://codeload.github.com/dignajar/another-ldap-auth/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234878799,"owners_count":18900702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","docker","docker-container","kubernetes","kubernetes-ingress-controller","ldap","nginx"],"created_at":"2025-01-21T01:18:33.532Z","updated_at":"2025-10-01T15:31:13.883Z","avatar_url":"https://github.com/dignajar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"⚠️ New version of Another LDAP via form-based here https://github.com/dignajar/another-ldap\n\n# Another LDAP authentication\n\n**LDAP Authentication** for **Nginx**, **Nginx ingress controller** (Kubernetes), **HAProxy** ([haproxy-auth-request](https://github.com/TimWolla/haproxy-auth-request)) or any webserver/reverse proxy with authorization based on the result of a subrequest.\n\n**Another LDAP Authentication** is an implementation of the `ldap-auth-daemon` services described in the official blog from Nginx in the [following article](https://www.nginx.com/blog/nginx-plus-authenticate-users/).\n\n**Another LDAP Authentication** it's prepared to run inside a Docker container, also you can run the Python script without the Docker container.\n\n[![Docker Hub](https://img.shields.io/badge/Docker-Hub-blue.svg)](https://hub.docker.com/r/dignajar/another-ldap-auth)\n[![Kubernetes YAML manifests](https://img.shields.io/badge/Kubernetes-manifests-blue.svg)](https://github.com/dignajar/another-ldap-auth/tree/master/kubernetes)\n[![codebeat badge](https://codebeat.co/badges/1d7cc634-4af0-4f26-b910-99fc98c61d11)](https://codebeat.co/projects/github-com-dignajar-another-ldap-auth-master)\n[![release](https://img.shields.io/github/v/release/dignajar/another-ldap-auth.svg)](https://github.com/dignajar/another-ldap-auth/releases)\n[![license](https://img.shields.io/badge/license-MIT-green)](https://github.com/dignajar/another-ldap-auth/blob/master/LICENSE)\n\n## Features\n- Supports `ldap` and `ldaps`.\n- Provide a cache for users and groups, you can set the cache expiration in minutes.\n- Supports validation by groups, regex in groups are supported.\n- Supports TLS via self-signed certificate.\n- Supports configuration via headers or via environment variables.\n- Supports HTTP response headers such as username and matched groups.\n- Brute force protection.\n- Log format in Plain-Text or JSON.\n\n## Diagram\n![Another LDAP Authentication](https://i.ibb.co/crJ0Xr2/diagram-1.png)\n\n## Available configurations parameters\nThe parameters can be sent via environment variables or via HTTP headers, also you can combine them.\n\nThe parameter `LDAP_SEARCH_FILTER` support variable expansion with the username, you can do something like this `(sAMAccountName={username})` and `{username}` is going to be replaced by the username typed in the login form.\n\nThe parameter `LDAP_BIND_DN` support variable expansion with the username, you can do something like this `{username}@TESTMYLDAP.com` or `UID={username},OU=PEOPLE,DC=TESTMYLDAP,DC=COM` and `{username}` is going to be replaced by the username typed in the login form.\n\nAll values type are `string`.\n\n### Environment variables\n| Key                                   | Default   | Values                           | Description                                                                            | Example                                                        |\n| ------------------------------------- | --------- | ---------------------------------| ---------------------------------------------------------------------------------------| ---------------------------------------------------------------|\n| LDAP_ENDPOINT                         |           |                                  | LDAP URL with the protocol and the port number.                                        | `ldaps://testmyldap.com:636`                                   |\n| LDAP_MANAGER_DN_USERNAME              |           |                                  | Username to bind and search in the LDAP tree.                                          | `CN=john,OU=Administrators,DC=TESTMYLDAP,DC=COM`               |\n| LDAP_MANAGER_PASSWORD                 |           |                                  | Password for the bind user.                                                            |                                                                |\n| LDAP_SEARCH_BASE                      |           |                                  |                                                                                        | `DC=TESTMYLDAP,DC=COM`                                         |\n| LDAP_SEARCH_FILTER                    |           |                                  | Filter for search, for Microsoft Active Directory usually you can use `sAMAccountName`.| `(sAMAccountName={username})`                                  |\n| LDAP_BIND_DN                          | `{username}` |                                  | Depends on your LDAP server the binding structure can change. This field support variable expansion for the username.     | `{username}@TESTMYLDAP.com` or `UID={username},OU=PEOPLE,DC=TESTMYLDAP,DC=COM` |\n| LDAP_ALLOWED_USERS **(Optional)**     |            |                                  | Support a list separated by commas.| `'diego,john,s-master'` |\n| LDAP_ALLOWED_GROUPS **(Optional)**    |           |                                  | Supports regular expressions, and support a list separated by commas.| `'DevOps production environment', 'Developers .* environment'` |\n| LDAP_ALLOWED_GROUPS_CONDITIONAL       | `and`     | `and`, `or`                      | Conditional to match all the groups in the list or just one of them.                   | `or`                                                           |\n| LDAP_ALLOWED_GROUPS_CASE_SENSITIVE    | `enabled` | `enabled`, `disabled`            | Enabled or disabled case sensitive groups matches.                                     | `disabled`                                                     |\n| LDAP_ALLOWED_GROUPS_USERS_CONDITIONAL | `or`      | `and`, `or`                      | Conditional to match user and at least one group in the list, or one of the two        | `and`                                                          |\n| CACHE_EXPIRATION                      | `5`       |                                  | Cache expiration time in minutes.                                                      | `10`                                                           |\n| LOG_LEVEL                             | `INFO`    | `INFO`, `WARNING`, `ERROR`       | Logger level.                                                                          | `DEBUG`                                                        |\n| LOG_FORMAT                            | `TEXT`    | `TEXT`, `JSON`                   | Output format of the logger.                                                           | `JSON`                                                         |\n| LDAP_HTTPS_SUPPORT                    | `disabled`| `enabled`, `disabled`            | Enabled or disabled HTTPS support with self signed certificate.                        |                                                                |\n| BRUTE_FORCE_PROTECTION                | `disabled`| `enabled`, `disabled`            | Enabled or disabled Brute force protection per IP. | |\n| BRUTE_FORCE_EXPIRATION                | `10`|                                         | Brute force expiration time in seconds per IP. | |\n| BRUTE_FORCE_FAILURES                  | `3`|                                         | Number of failures before the IP is blocked.  | |\n\n### HTTP request headers\nThe variables send via HTTP headers take precedence over environment variables.\n\n- `Ldap-Endpoint`\n- `Ldap-Manager-Dn-Username`\n- `Ldap-Manager-Password`\n- `Ldap-Bind-DN`\n- `Ldap-Search-Base`\n- `Ldap-Search-Filter`\n- `Ldap-Allowed-Users`\n- `Ldap-Allowed-Groups`\n- `Ldap-Allowed-Groups-Case-Sensitive`\n- `Ldap-Allowed-Groups-Conditional`\n\n### HTTP response headers\n- `x-username` Contains the authenticated username\n- `x-groups` Contains the username matches groups\n\n## Installation and configuration\nThe easy way to use **Another LDAP Authentication** is running as a Docker container and set the parameters via environment variables.\n\n### Step 1 - Run as a Docker container\nChange the environment variables with your setup.\n\n```\ndocker run -d \\\n    -e LDAP_ENDPOINT='ldaps://testmyldap.com:636' \\\n    -e LDAP_MANAGER_DN_USERNAME='CN=john-service-user,OU=Administrators,DC=TESTMYLDAP,DC=COM' \\\n    -e LDAP_MANAGER_PASSWORD='MasterpasswordNoHack123' \\\n    -e LDAP_BIND_DN='{username}@TESTMYLDAP.COM' \\\n    -e LDAP_SEARCH_BASE='DC=TESTMYLDAP,DC=COM' \\\n    -e LDAP_SEARCH_FILTER='(sAMAccountName={username})' \\\n    -e LOG_FORMAT='JSON' \\\n    -p 9000:9000 \\\n    --name another_ldap_auth \\\n    dignajar/another-ldap-auth:latest\n```\n\n**Another LDAP Authentication** now is running on `http://localhost:9000`.\n\nTest it via curl:\n```\ncurl -vvv http://localhost:9000 -u diego:mypassword\n```\n\nOutput from ALDAP:\n```\n{\"date\": \"2021-05-21 10:06:52\", \"level\": \"INFO\", \"objectName\": \"Cache\", \"ip\": \"192.168.0.10\", \"referrer\": null, \"message\": \"User not found in the cache.\", \"username\": \"diego\"}\n{\"date\": \"2021-05-21 10:06:52\", \"level\": \"INFO\", \"objectName\": \"Aldap\", \"ip\": \"192.168.0.10\", \"referrer\": null, \"message\": \"Authenticating user.\", \"username\": \"diego\", \"finalUsername\": \"diego\"}\n{\"date\": \"2021-05-21 10:06:53\", \"level\": \"INFO\", \"objectName\": \"Aldap\", \"ip\": \"192.168.0.10\", \"referrer\": null, \"message\": \"Authentication successful.\", \"username\": \"diego\", \"elapsedTime\": \"0.22335\"}\n{\"date\": \"2021-05-21 10:06:53\", \"level\": \"INFO\", \"objectName\": \"Cache\", \"ip\": \"192.168.0.10\", \"referrer\": null, \"message\": \"Adding user to the cache.\", \"username\": \"diego\"}\n192.168.0.10 - - [21/May/2021 10:06:53] \"GET / HTTP/1.1\" 200 -\n```\n\n\u003e Remember you can enable self-signed certificate from Flask via the environment variable `LDAP_HTTPS_SUPPORT==\"enabled\"`.\n\n### Step 2 - Nginx configuration\nNginx use the module [ngx_http_auth_request_module](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) to do the subrequest.\n\nThe following example shows how to configure Nginx that is running in the same machine as **Another LDAP Authentication**. The backend `/private/` includes the authentication request to `/another_ldap_auth`.\n\n```\nlocation /private/ {\n    auth_request /another_ldap_auth;\n    # ...\n    # Here you private site\n}\n\nlocation = /another_ldap_auth {\n    internal;\n    proxy_pass_request_body off;\n    proxy_set_header Content-Length \"\";\n    proxy_pass http://localhost:9000;\n}\n```\n\nNow you can access to your website wich is going to be something like this `http://myserver.com/private/` and Nginx will request you to write the username and password.\n\n## Deploy to Kubernetes with Nginx ingress controller\nGet the K8s manifests from the folder `/kubernetes`.\n\nThe manifests for K8s helps to deploy **Another LDAP Authentication** in the namespace `ingress-nginx` and expose the service in the cluster at the following address `https://another-ldap-auth.ingress-nginx`.\n\nPlease change the environment variables from the manifest and the secret for the bind username.\n\nAfter you have running **Another LDAP Authentication** in your Kubernetes, you can modify the ingress manifest from the application you want to protect.\n\nYou can remove the comment `#` and send headers as variables such as `Matching groups`.\n\n```\n---\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: demo-webserver\n  namespace: demo\n  annotations:\n    nginx.ingress.kubernetes.io/auth-url: https://another-ldap-auth.ingress-nginx\n\n    # nginx.ingress.kubernetes.io/auth-snippet: |\n    #   proxy_set_header Ldap-Allowed-Groups \"\u003cSOME GROUP\u003e\";\n    #   proxy_set_header Ldap-Allowed-Groups-Conditional \"or\";\nspec:\n  rules:\n  - host: demo.local\n    http:\n      paths:\n      - path: /\n        backend:\n          serviceName: demo-webserver\n          servicePort: 80\n```\n\n## Brute Force protection\nBrute force protection is blocking user IP, please read this article to know the limitations about blocking IPs\n- https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks\n\n## Known limitations\n- Parameters via headers need to be escaped, for example, you can not send parameters such as `$1` or `$test` because Nginx is applying variable expansion.\n\n## Breaking changes from v1.x to v2.x\n- `LDAP_REQUIRED_GROUPS` renamed to `LDAP_ALLOWED_USERS`\n- `LDAP_REQUIRED_GROUPS_CONDITIONAL` renamed to `LDAP_ALLOWED_GROUPS_CONDITIONAL`\n- `LDAP_REQUIRED_GROUPS_CASE_SENSITIVE` renamed to `LDAP_ALLOWED_GROUPS_CASE_SENSITIVE`\n- `LDAP_SERVER_DOMAIN` removed and replace by `LDAP_BIND_DN`\n\n## ⚠️ Warning ⚠️\nThe application accepts configuration parameters via HTTP headers, which can be exploited when used behind Nginx with the auth_request_module. Since Nginx forwards all client-sent headers to the authentication backend, malicious clients can override critical configuration settings by sending specially crafted headers. The solution can be set the configuration in the Nginx location directive to overwrite any client configuration.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdignajar%2Fanother-ldap-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdignajar%2Fanother-ldap-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdignajar%2Fanother-ldap-auth/lists"}