Giter Club home page Giter Club logo

Comments (10)

MarcJHuber avatar MarcJHuber commented on July 17, 2024

Hi,

the LDAP query Perl scripts don't come with a custom TLS implementation, so the default is whatever the underlying Perl module thinks it's best. Could you check whether

setenv TLS_OPTIONS = "sslversion => 'tlsv1_2'"

in module context makes a difference?

Thanks,

Marc

from event-driven-servers.

naciohr avatar naciohr commented on July 17, 2024

from event-driven-servers.

MarcJHuber avatar MarcJHuber commented on July 17, 2024

Hi,

I'm sorry, but I can't help you with that. That "openssl s_client" failure seems to imply a local issue.

Cheers,

Marc

from event-driven-servers.

naciohr avatar naciohr commented on July 17, 2024

from event-driven-servers.

naciohr avatar naciohr commented on July 17, 2024

Hi Marc,

The problem appears to be with openssl indeed openssl/openssl#19518. I tried to compile tac_plus-ng with openssl 1.1.1 but it requires 3.0. Is there a chance to use 1.1.1?

BR,

from event-driven-servers.

MarcJHuber avatar MarcJHuber commented on July 17, 2024

Hi,

TLS support for tac_plus-ng is experimental, and while standardization is in progress I'd expect it to take quite some time before actual network devices support it. tac_plus-ng can easily be built without TLS support (e.g. using "./configure --minimum tac_plus-ng").

Regarding a Python module implementation: Well, yes, that's certainly a possibility. I could commit a module for importing the constants (I've never bothered to release that -- I'm just not familiar enough with Python to support it).

The "protocol" between the "external" module and back-end scripts is pretty simple: script receives a series of

\n

lines, followed by a single

=\n

on stdin. It then does its task and returns the updated

\n

list, followed by a

=\n

to stdout. Typical values are 0 (final result available) and 16 (try next module). The perl back-ends should give some insights about the attribute-value pairs that may be used.

Just to make sure that your configuration is correct: Your LDAP_HOSTS variable looks like "ldaps://:636" and USE_TLS is not set? The latter would trigger START_TLS, and that's obviously not available for a native LDAPS server.

Cheers,

Marc

from event-driven-servers.

naciohr avatar naciohr commented on July 17, 2024

Hello,

Thank-you. I was able to make the python module work! Just managed the stdin and stdout as you commented. The perl script appears to translate AV constant strings into numbers before prompting, but using the numbers directly allows python to interact correctly.

I will clean the code a bit and will leave a sample here.

Regarding the configuration, that's correct. I use ldaps with port 636 and USE_TLS is not declared. That config on openssl 3.0 is not working; it does for openssl 1.1.1 and gnutls that python implements.

Best regards,

from event-driven-servers.

MarcJHuber avatar MarcJHuber commented on July 17, 2024

Hi,

ok, thanks. I'm curious when this will work again ...

I've just pushed some of the Python sample code I've played with a couple of weeks ago. Worked for me, but my Python background is quite limited.

Cheers,

Marc

from event-driven-servers.

naciohr avatar naciohr commented on July 17, 2024

Hello,

I had a look to the code you published. It was really helpful as I realised the tacacs may interact several times with the module rather than just pass all AVs at once.

I built this code that works for me against a microsoft ldaps. It's based on python-ldap. The logger can be used to log stuff to a file to help out the debugging when the tacacs is running.

This is subject to improvements such as object implementation, but it works for me anyway.

import ldap, os, sys, logging, re
from datetime import datetime

# Import AV constants
import mavis

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatLogger = logging.Formatter("{asctime} {message}", style = "{")
fileLogger = logging.FileHandler("ldappy.log", mode = "w", encoding='utf-8')
fileLogger.setFormatter(formatLogger)
logger.addHandler(fileLogger)

ldapHosts = os.environ.get('LDAP_HOSTS') or "ldaps://<server>"
ldapPass = os.environ.get('LDAP_PASSWD') or "<pass>"
ldapBase = os.environ.get('LDAP_BASE') or "<DN>"
ldapDomain = os.environ.get('LDAP_DOMAIN') or "<domain>"
ldapUser = "{}@{}".format(os.environ.get('LDAP_USER'), os.environ.get('LDAP_DOMAIN')) or "<user>"
ldapFilter = "(&(objectclass=user)(sAMAccountName={}))"

def parseStdin():
    avPairs = dict()
    for line in sys.stdin:
        #logger.info(line.rstrip())
        if line.rstrip() != "=":
            avPairs[int(line.split()[0])] = line.split()[1]
        else:
            return avPairs

def writeStdout(avPairs, result):
    for key in sorted(avPairs):
        sys.stdout.write("%d %s\n" % (int(key), avPairs[key]))
    sys.stdout.write("=%d\n" % result)

logger.info("start")
avDict = parseStdin()
result = mavis.MAVIS_DEFERRED
flagFinish = False
try:
    # ldapConnection = ldap.initialize(ldapHosts, trace_level=0)
    ldapConnection = ldap.ldapobject.ReconnectLDAPObject(ldapHosts, trace_level=0, retry_max=5, retry_delay=10.0)
    ldapConnection.set_option(ldap.OPT_DEFBASE, ldapBase)
    #ldapConnection.set_option(ldap.OPT_DEBUG_LEVEL,9)
except:
    avDict[mavis.AV_A_USER_RESPONSE] = "Unable to connect to the server."
    result = mavis.MAVIS_FINAL
    flagFinish = True

if not flagFinish and (avDict[mavis.AV_A_TYPE] != mavis.AV_V_TYPE_TACPLUS):
    result = mavis.MAVIS_DOWN
    flagFinish = True

if not flagFinish and (not mavis.AV_A_USER in avDict):
    avDict[mavis.AV_A_USER_RESPONSE] = "User not set."
    avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_ERROR
    result = mavis.MAVIS_FINAL
    flagFinish = True
else:
    ldapFilter = ldapFilter.format(avDict[mavis.AV_A_USER])

if not flagFinish and (re.match('\(|\)|,|\||&|\*', avDict[mavis.AV_A_USER])):
    avDict[mavis.AV_A_USER_RESPONSE] = "Username not valid."
    avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_ERROR;
    result = mavis.MAVIS_FINAL
    flagFinish = True

if not flagFinish and (avDict[mavis.AV_A_TACTYPE] == mavis.AV_V_TACTYPE_AUTH and not mavis.AV_A_PASSWORD in avDict):
    avDict[mavis.AV_A_USER_RESPONSE] = "Password not set."
    avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_ERROR;
    result = mavis.MAVIS_FINAL
    flagFinish = True

if not flagFinish and not mavis.AV_A_PASSWORD in avDict:
    ldapConnection.simple_bind_s(ldapUser, ldapPass)
    try:
        userData = ldapConnection.search_ext_s(ldapBase, ldap.SCOPE_SUBTREE, filterstr = ldapFilter)
        #logger.info("user data type {} with {}".format(type(userData), userData))
        if userData is not None and len(userData) != 0:
            avDict[mavis.AV_A_USER_RESPONSE] = "Authorization passed."
            avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_OK
            result = mavis.MAVIS_FINAL
        else:
            avDict[mavis.AV_A_USER_RESPONSE] = "User not found."
            avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_NOTFOUND
            result = mavis.MAVIS_DOWN
    except ldap.TIMEOUT as lto:
        #logger.info("timeout {}".format(lto))
        avDict[mavis.AV_A_USER_RESPONSE] = "Time out looking up the user."
        avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_ERROR
        result = mavis.MAVIS_TIMEOUT
    finally:
        ldapConnection.unbind_s()
        flagFinish = True

if not flagFinish and mavis.AV_A_PASSWORD in avDict:
    ldapConnection = ldap.ldapobject.ReconnectLDAPObject(ldapHosts, trace_level=0, retry_max=5, retry_delay=10.0)
    ldapConnection.set_option(ldap.OPT_DEFBASE, ldapBase)
    try:
        #logger.info("av received {}".format(avDict))
        #logger.info("mypass {}".format(avDict[mavis.AV_A_PASSWORD]))
        ldapConnection.simple_bind_s("{}@{}".format(avDict[mavis.AV_A_USER], ldapDomain), avDict[mavis.AV_A_PASSWORD])
        #logger.info("ok")
        userData = ldapConnection.search_ext_s(ldapBase, ldap.SCOPE_SUBTREE, filterstr = ldapFilter)
        #logger.info("user data type {} with {}".format(type(userData), userData))
        avDict[mavis.AV_A_DBPASSWORD] = avDict[mavis.AV_A_PASSWORD]
        avDict[mavis.AV_A_DN] = userData[0][0]
        avDict[mavis.AV_A_MEMBEROF] = '"{}"'.format(userData[0][1]['memberOf'][0].decode('UTF-8'))
        avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_OK
        result = mavis.MAVIS_FINAL
    except ldap.INVALID_CREDENTIALS as lic:
        #logger.info("invalid credentials {}".format(lic))
        avDict[mavis.AV_A_RESULT] = mavis.AV_V_RESULT_FAIL
        result = mavis.MAVIS_DOWN
    finally:
        flagFinish = True
        ldapConnection.unbind_s()

writeStdout(avDict, result)

Again, many thanks for your help and your time.

BR,

from event-driven-servers.

MarcJHuber avatar MarcJHuber commented on July 17, 2024

Hi,

pretty nice, thanks for sharing this code!

I'll be closing this issue then.

Cheers,

Marc

from event-driven-servers.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.