Navigation

    Netgate Discussion Forum
    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search

    [solved] FreeRADIUS 3.x package LDAP/OTP problem

    pfSense Packages
    2
    4
    952
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • W
      waterstorm last edited by

      Hi folks,

      I just updated to the new pfsense 2.4 and my freeradius suddenly stopped working. I couldn't even start it, telling me "ssl version mismatch".
      After a bit of fiddling, I figured I'd try freeradius 3 instead.

      It installed successfully and it also started up just fine. However our setup from before did not work at all.
      We seem to have a pretty "uncommon" setup here. We're using OpenLDAP + Gauth. As this was not working with freerad2 out of the box we used a pam plugin to do ldap + gauth. Somewhat similar to this old post:
      http://www.supertechguy.com/help/security/freeradius-google-auth

      So I "googled around" noticing that gauth made it into the auth options of pfsense, this is just great. However, I can't figure out how to use it with LDAP auth. Seems I can not use both at the same time. Is this possible at all?

      I just tried setting up the LDAP Login, which is easy and works just fine. But then I do not have a list of users, so I can't define the gauth secrets for them.
      I used to have one folder where all of the secrets were listed for each user and the folder was chosen based on the user login name.
      I could try to adjust the python script, but I'd really love to have this function purely from the GUI so I won't have to modify stuff each update (which I always had to using freerad2)

      Any ideas from you guys?

      1 Reply Last reply Reply Quote 0
      • W
        waterstorm last edited by

        Is anyone using LDAP + OTP and could give me a hint?  :-\

        EDIT: Never mind :-) I wrote my own python script and replaced the gauth one.
        If anyone has the same problem let me know and I'm happy to share it

        A 1 Reply Last reply Reply Quote 0
        • A
          avs262 @waterstorm last edited by

          Can you share your python script with me?

          W 1 Reply Last reply Reply Quote 0
          • W
            waterstorm @avs262 last edited by waterstorm

            @avs262 Sorry I did not get any notification from the forum, so I've only seen it now.
            Of course I can ☺ . This is what I came up with.

            I added the following packages:

            pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/py27-setuptools-36.5.0.txz
            pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/py27-pyasn1-0.3.7.txz
            pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/py27-pyasn1-modules-0.1.5.txz
            pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/py27-ldap-2.4.45.txz
            

            Then I changed the googleauth plugin of FreeRADIUS to use my custom script:

            exec googleauth {
                wait = yes
                #program = "/usr/local/etc/raddb/scripts/googleauth.py %{request:User-Name} %{reply:MOTP-Init-Secret} %{reply:MOTP-PIN} %{request:User-Password}"
                program = "/usr/local/etc/raddb/scripts/googleauth-ldap.py %{request:User-Name} %{reply:MOTP-Init-Secret} %{request:User-Password}"
            }
            

            Finally the script itself, located in /usr/local/etc/raddb/scripts/googleauth-ldap.py

            #!/usr/local/bin/python2.7
            
            # Copyright of the original script: www.brool.com (http://www.brool.com/post/using-google-authenticator-for-your-website/)
            # License: CC0 1.0 Universal License
            
            import sys
            import time
            import struct
            import hmac
            import hashlib
            import base64
            import syslog
            import ldap
            
            def check_credentials(username, password, ldap_server="ldap://ldapserverurl:389"):
                ldap_server_failover = "ldap://urloffailoverldapserver:389"
                base_dn = 'dc=whatever'
                user_dn = "uid="+username+",ou=People,"+base_dn
                ldap_filter = 'uid=%s' % username
                try:
                    ldap_client = ldap.initialize(ldap_server)
                    ldap_client.start_tls_s()
                    ldap_client.set_option(ldap.OPT_REFERRALS,0)
                    ldap_client.set_option(ldap.OPT_X_TLS,1)
                    ldap_client.set_option(ldap.OPT_X_TLS_CACERTDIR, "/usr/local/etc/raddb/certs/ca_ldap1_cert.pem")
                    ldap_client.set_option(ldap.OPT_X_TLS_CACERTFILE, "/usr/local/etc/raddb/certs/")
                    ldap_client.simple_bind_s(user_dn, password)
                except ldap.INVALID_CREDENTIALS:
                    ldap_client.unbind()
                    syslog.syslog(syslog.LOG_ERR, 'Wrong username or password')
                    return False
                except ldap.SERVER_DOWN:
                    if ldap_server != ldap_server_failover:
                        syslog.syslog(syslog.LOG_ERR, 'Main LDAP server not available - Trying Failover')
                        return check_credentials(username, password, ldap_server_failover)
                    else:
                        syslog.syslog(syslog.LOG_ERR, 'Both LDAP servers not available')
                        return False
                except Exception, error:
                    syslog.syslog(syslog.LOG_ERR, error)
                    return False
                ldap_client.unbind()
                syslog.syslog(syslog.LOG_NOTICE, "freeRADIUS: LDAP Authenticator - Password validation successful for user: " + username)
                return True
            
            def authenticate(username, secretkey, code_attempt):
                #split 6 digitas from the end -> code
                password = code_attempt[:len(code_attempt)-6]
            
                if check_credentials(username, password) == False:
                    syslog.syslog(syslog.LOG_ERR, "freeRADIUS: Google Authenticator - Authentication failed. User: " + username + ", Reason: Wrong Password")
                    return False
            
                code_attempt = code_attempt[len(code_attempt)-6:]
                tm = int(time.time() / 30)
            
                secretkey = base64.b32decode(secretkey)
            
                # try 30 seconds behind and ahead as well
                for ix in [-1, 0, 1]:
                    # convert timestamp to raw bytes
                    b = struct.pack(">q", tm + ix)
            
                    # generate HMAC-SHA1 from timestamp based on secret key
                    hm = hmac.HMAC(secretkey, b, hashlib.sha1).digest()
            
                    # extract 4 bytes from digest based on LSB
                    offset = ord(hm[-1]) & 0x0F
                    truncatedHash = hm[offset:offset+4]
            
                    # get the code from it
                    code = struct.unpack(">L", truncatedHash)[0]
                    code &= 0x7FFFFFFF;
                    code %= 1000000;
            
                    if ("%06d" % code) == str(code_attempt):
                        syslog.syslog(syslog.LOG_NOTICE, "freeRADIUS: Google Authenticator - Authentication successful for user: " + username)
                        return True
            
                syslog.syslog(syslog.LOG_ERR, "freeRADIUS: Google Authenticator - Authentication failed. User: " + username + ", Reason: wrong tokencode")
                return False
            
            # Check the length of the parameters
            if len(sys.argv) != 4:
                syslog.syslog(syslog.LOG_ERR, "freeRADIUS: Google Authenticator - wrong syntax - USAGE: googleauth.py Username, Secret-Key, Auth-Attempt")
                exit(1)
            
            auth = authenticate(sys.argv[1], sys.argv[2], sys.argv[3])
            
            if auth == True:
                exit(0)
            
            exit(1)
            

            Of course you need to adapt the URL(s) of the ldap server and the dns to fit your environment.
            It works pretty well in our setup, but as always suggestions or improvements are welcome :)

            Reminder: After upgrading pfsense both files will get overwritten! So be sure you create a backup before and restore it after upgrading ;-)

            1 Reply Last reply Reply Quote 0
            • First post
              Last post