PJSIP and LDAP authentication


#1

Hi, is PJSIP and LDAP for authentication possible? Anyone know how?

Does PJSIP Realtime now support LDAP, or are there other means?


#2

Unless someone has a better suggestion, it seems creating a script which generates a pjsip_wizard.conf from an LDAP export is the easiest approach.

PJSIP Realtime w/ LDAP provides numerous functions I don’t need (I really only need authentication) and the documentationn is non-existent for LDAP, its only there for SQL.

Please advise if there’s a better way.


#3

I doubt PJSIP has been tested with realtime LDAP support, and there is no other support. LDAP integration is not something widely used.


#4

So I quickly made this script which creates ldap-users.conf and ldap-exts.conf configuration files. I include the former named file within pjsip_wizard.conf and the latter in extensions.conf using the #include directive of Asterisk.

I will run this script in a crontab, and it will automatically tell asterisk (which is running in docker) to reload the configuration. Not perfect, but its ok. Note that I abused the AstAccountHost attribute as a password for the user; this should be automatically generated :)… The md5 secret doesnt seem usable as it requires a valid realm or whatever, too difficult

havent tested this much yet, probably wont post final version here, but its close and should be good as inspiration at the least.

#!/usr/bin/python3
import os
import sys
import ssl
from ldap3 import Server, Connection, Tls, SUBTREE, ALL
from ldap3.utils.conv import escape_filter_chars
from string import Template
import subprocess

t_user = Template(
"""
[$username](user-template)
hint_exten = $extension
hint_application = Dial($${PJSIP_DIAL_CONTACTS($extension)})
endpoint/context = $context
inbound_auth/username = $username
inbound_auth/password = $password
aor/mailboxes = $extension@$context
""")

t_extension = Template(
"""
exten => $extension,hint,PJSIP/$username
exten => $extension,1,GotoIf($$["$${PJSIP_DIAL_CONTACTS($${EXTEN})}" = ""]?nocon)
exten => $extension,n,Dial($${PJSIP_DIAL_CONTACTS($${EXTEN})}, 30, mkt)
exten => $extension,n(nocon),Return()
""")

tls = Tls(ca_certs_file="certificate.crt",validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1 )

s = Server('ldaps://{{ ldap_hostname }}', get_info=ALL, use_ssl = True, tls = tls)
c = Connection(s, 
               user='{{asterisk_ldap_serviceaccount}}', 
               password='{{asterisk_ldap_servicepassword}}')

if not c.bind():
   print('Could not login user: ', c.result)
   exit(1)

ok = c.search("ou=people,dc=example,dc=com",
                 "(&(objectClass=AsteriskSIPUser)(userPassword=*))",
                 search_scope = SUBTREE,
                 attributes = ['uid', 'AstAccountContext', 'displayName', 'AstAccountCallerID', 'AstAccountHost']
                    )
if not ok:
    print("Unable to search for asterisk users", c.result)
    exit(2)

fusers = open("ldap-accs.conf.tmp", "w")
fexts  = open("ldap-exts.conf.tmp", "w")
for user in c.response:

    lines = t_user.substitute(
        username=str(user['attributes']['uid'][0]),
        password=str(user['attributes']['AstAccountHost'][0]),
        context=str(user['attributes']['AstAccountContext'][0]),
        extension=str(user['attributes']['AstAccountCallerId'][0]),
        name=str(user['attributes']['displayName'])
    )
    fusers.write(lines)

    lines = t_extension.substitute(
        username=str(user['attributes']['uid'][0]),
        password=str(user['attributes']['AstAccountHost'][0]),
        context=str(user['attributes']['AstAccountContext'][0]),
        extension=str(user['attributes']['AstAccountCallerId'][0]),
        name=str(user['attributes']['displayName'])
    )

    fexts.write(lines)

fusers.close()
fexts.close()

os.rename("ldap-accs.conf.tmp", "./config/pjsip_ldap_users.conf")
os.chmod('./config/pjsip_ldap_users.conf', 0o600)
os.chown('./config/pjsip_ldap_users.conf', 3001, 3001)

os.rename("ldap-exts.conf.tmp", "./config/ldap-exts.conf")
os.chmod('./config/ldap-exts.conf', 0o600)
os.chown('./config/ldap-exts.conf', 3001, 3001)

subprocess.call(["/usr/local/bin/docker-compose", "exec", "asterisk", "rasterisk", "-x", "reload"])

exit(0)