Add support for LDAP now that Auth is required

now that auth is mandatory i think LDAP needs to be a priority. since i run quite a few services, it can be very hard to get the family on board sometimes. LDAP makes this much easier as the family only needs to remember 1 login. i typically wont use any services that i cannot connect to LDAP and i think all self-hosted solutions should include it. now there will be some grumbling around the house that we have a new login or i will have to manually add all my ldap users and sync the passwords myself. please consider adding this as a provider.

+1 from me on this; LDAP would be a great addition in our Household too.

2 Likes

Maybe something more abstract than just LDAP, like an external authentication facility. Where LDAP, Azure AD, Microsoft graph, Facebook, Google, etc can be used?

1 Like

+1 for LDAP here with nested group support as well. I use PAM authentication so either one would be HIGHLY welcome. This could be made even cooler by having custom fields for security codes that LDAP could pull for use with an alarm control panel!

I’ve played around with the example auth provider of HASS and I’ve been able to make an LDAP provider which uses the python-ldap library. It actually works (even with Duo) and I can disable the legacy API password and the default HASS auth provider however the documentation of HASS at https://developers.home-assistant.io/docs/en/auth_auth_provider.html mentions that external auth providers might be supported in the future but are not at the moment. As such, I doubt a PR would be accepted. I might have to open an issue and ask about it. For now I’m testing it in my Dev instance of HASS and plan on injecting it into my docker image.

I personally think LDAP is seen as a low priority however for me it was the reason to actually upgrade from 0.65.5 because I need LDAP and RBAC so that I can give other access to HASS and control what can be accessed. With LDAP I’m already half way there :smile:

Any one interested in giving it a shot?

1 Like

Yes please - Need LDAP.

If not, I’ll end up having to use external auth with apache ldap.

Hi,

In case you’re still interested in LDAP authentication, I created a pull request to add an universal command line auth provider which can also be used to authenticate against LDAP. There isn’t full consensus about the API yet, but here is the PR, in case someone wants to try it out.

https://github.com/home-assistant/home-assistant/pull/19985

I also created a reusable script to be used for LDAP authentication, which is here: https://github.com/efficiosoft/ldap-auth-sh

Best regards
Robert

2 Likes

Awesome work! Just upgraded to 88.0 and got ldap working. I was planning on trying this sooner but was moving some services over to docker, but after playing around with the config i got it working pretty fast and painless. Thanks!

@budbay Just out of interest, are you using the script for LDAP auth linked in the docs? Was setting it up straightforward for you?

@roschi Yes i used the scripts linked in the docs and from the examples folder. The examples really helped me out but did have minor issues, mostly from not reading everything thoroughly enough. I didnt find it obvious at first i should use two scripts and modified the main one at first and caused some issues for myself, even though it did state not to call it directly. I also found that in order to pass the username to homeassistant you have to set up the additional custom search or it wont get the “cn” to pass on and auth fails. But the debug log made that quick to find, so i set it to check for posixAccount and then everything worked.

Ok, thanks for the feedback. I restructured things a bit in the script:

  1. Script can no longer be called directly (removed shebang line and exec permissions).
  2. Renamed ldap-auth.sh to ldap-auth.inc.

Regarding the usage of ATTRS without searching enabled, that should result in an error straight away when the script starts, didn’t it?

Hmm, I think it would be even better to have a traditional config file approach where you pass the config file as argument. Will be less confusing to most users. I changed this now.

Yes the ATTRS without searching did create the error quickly, i just brought it up thinking it would be good to document that they rely on each other. Config file approach does seem like a good idea.

Agreed. I added a note to the HA sample config.

@budbay
do you know this porblem:
I have installed the script and the config file to my HA. If I execute the ldap-auth.sh direct on the console (added Password and Username directly in the script, as a test) it works perfectly.
But if I try do log in through the HA login mask, I get a “failed to authenticate”.
Even my LDAP server doesn’t get any request. I monitoring them by tcpdump.

For those missing LDAP support - I was able to derive it from these instructions.

The result looks like this:

/config/ldap-auth.py ← must be executable

#!/usr/bin/env python3

# SETTINGS
SERVER = "ldap.example.com"
USERDN = "cn={},ou=users,dc=ldap,dc=example,dc=com"
BASEDN = USERDN
FILTER = "(&(objectClass=user)(memberOf=cn=users,ou=groups,dc=ldap,dc=example,dc=com))"
NAME_ATTR="name"
ATTRS=[NAME_ATTR]


# CODE
import os
import pip

def install(package):
    if hasattr(pip, 'main'):
        pip.main(['install', package])
    else:
        pip._internal.main(['install', package])

try:
    from ldap3 import Server, Connection, ALL, core
except:
    install('ldap3')
    from ldap3 import Server, Connection, ALL, core

# XXX: Update these with settings apropriate to your environment:
#      (I use FreeIPA and an homeassistant group assignment)


if 'username' not in os.environ and 'password' not in os.environ:
    print("Need username and password environment variables!")
    exit()

USERDN = USERDN.format(os.environ['username'])
BASEDN = BASEDN.format(os.environ['username'])

server = Server(SERVER, get_info=ALL)
try:
    conn = Connection(server, USERDN, password=os.environ['password'], auto_bind=True)
    #print("whoami: {}".format(conn.extend.standard.who_am_i()))
    search = conn.search(BASEDN, FILTER, attributes=ATTRS)
    if search:
        #print("Search success: {}".format(conn.entries))
        print(f"name=%s"%(conn.entries[0][NAME_ATTR]))
        exit(0)
    else:
        print("LDAP bind succeded, but search yielded empty result")
        exit(1)
except core.exceptions.LDAPBindError as e:
    print(e)
    exit(1)

and in configuration.yaml

homeassistant:
  < other settings>
  auth_providers:
  - type: command_line
    command: /config/ldap-auth.py
    meta: true

Login via LDAP is nice, but is a legacy method. Most users will not have the desire or ability to run an LDAP device/service.

Alternatively, while the owner account should remain local to HA, adding support for modern authentication via OAUTH and OIDC (using a Google account, or a MS Account) would strongly support adoption for non technical users so they (as stated above) don’t have to remember multiple passwords.

The downside to this of course is it becomes a cloud dependency, but depending on the use case, would still serve as a nice additional feature.