LDAP Proxy Setup

I’m exploring the use of the LDAP proxy with PrivacyIDEA, however, it looks like the instructions on GitHub are out of date or not for my distribution of Linux. Also, keep in mind that I am not deeply experienced with Linux. I know my way around and can perform basic functions but with the errors I am getting, I’m left scratching my head. I’m running PrivacyIDEA 3.0.1 on Ubuntu Server 16.04

Based on the instructions, I did the following:

root@localhost:/home/administrator# virtualenv2 venv
No command 'virtualenv2' found, did you mean:
 Command 'virtualenv' from package 'virtualenv' (universe)
virtualenv2: command not found
root@localhost:/home/administrator# virtualenv venv
Running virtualenv with interpreter /usr/bin/python2
New python executable in /home/administrator/venv/bin/python2
Also creating executable in /home/administrator/venv/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.
root@localhost:/home/administrator# . ./venv/bin/activate
nano requirements.txt

Copied contents of requirements.txt from GitHub into requirements.txt in Linux.

pip install -r requirements.txt

At this point a lot of things happen but then an error occurs that is larger than the buffer so I can’t see exactly where the failure is. At the bottom of the fail, the following appears:

  running build_ext
  x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c conftest.c -o conftest.o
  unable to execute 'x86_64-linux-gnu-gcc': No such file or directory
  building 'twisted.test.raiser' extension
  creating build/temp.linux-x86_64-2.7
  creating build/temp.linux-x86_64-2.7/src
  creating build/temp.linux-x86_64-2.7/src/twisted
  creating build/temp.linux-x86_64-2.7/src/twisted/test
  x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c src/twisted/test/raiser.c -o build/temp.linux-x86_64-2.7/src/twisted/test/raiser.o
  unable to execute 'x86_64-linux-gnu-gcc': No such file or directory
  error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for Twisted

It then runs the following and errors out again, filling a significant portion of the buffer.

  Running setup.py clean for Twisted
Failed to build pycrypto Twisted
Installing collected packages: asn1crypto, appdirs, attrs, pycparser, cffi, configobj, constantly, enum34, idna, six, ipaddress, cryptography, incremental, pyOpenSSL, zope.interface, Twisted, pycrypto, pyparsing, ldaptor, packaging, pyasn1, pyasn1-modules, service-identity, wheel
  Running setup.py install for Twisted ... error

This is what is at the end of the error

    x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c conftest.c -o conftest.o
    unable to execute 'x86_64-linux-gnu-gcc': No such file or directory
    building 'twisted.test.raiser' extension
    creating build/temp.linux-x86_64-2.7
    creating build/temp.linux-x86_64-2.7/src
    creating build/temp.linux-x86_64-2.7/src/twisted
    creating build/temp.linux-x86_64-2.7/src/twisted/test
    x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c src/twisted/test/raiser.c -o build/temp.linux-x86_64-2.7/src/twisted/test/raiser.o
    unable to execute 'x86_64-linux-gnu-gcc': No such file or directory
    error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /home/administrator/venv/bin/python2 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-_Fsfr1/Twisted/setup.py'"'"'; __file__='"'"'/tmp/pip-install-_Fsfr1/Twisted/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-vrDFac/install-record.txt --single-version-externally-managed --compile --install-headers /home/administrator/venv/include/site/python2.7/Twisted Check the logs for full command output.

At this point I believe it’s because I didn’t install twisted first, so I try to install twisted and get the following:

root@localhost:/home/administrator# apt-get install python-twisted
Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 python-twisted : Depends: python-twisted-core (>= 16.0.0-1ubuntu0.2) but it is not going to be installed
E: Unable to correct problems, you have held broken packages.

Running apt-mark showhold doesn’t show any held packages and no matter how far down the line I seem to go trying to install package dependencies, I get the same kind of error…x package requires y dependency but will not be installed

Where am I going wrong here???

I’ve done the following and gotten a little closer:

apt-get install python-pip3
virtualenv venv
. ./venv/bin/activate
pip3 install Twisted
pip3 install -r requirements.txt
pip3 install .
ERROR: Directory '.' is not installable. Neither 'setup.py' nor 'pyproject.toml' found.

Hi wwalker,

sorry, the documentation is a bit sparse at the moment.
Please note that the LDAP proxy does not currently support Python 3. Hence, you need to be careful to create a virtualenv based on Python 2.7. I am also not sure why you encounter “Directory ‘.’ is not installable” – are you running the commands inside the git checkout of the LDAP proxy? If you do, the current directory should contain a setup.py.

Ok, so I went back and performed the following:

cd /etc/privacyidea
virtualenv ldap_proxy
. ./ldap_proxy/bin/activate
pip wheel -r requirements.txt

The below error is what I get, looks like pycrypto is looking for a file that doesn’t exist??

Building wheels for collected packages: pycrypto, Twisted
  Building wheel for pycrypto (setup.py) ... error
  ERROR: Command errored out with exit status 1:
   command: /etc/privacyidea/ldap_proxy/bin/python2 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-wheel-oQv3pU/pycrypto/setup.py'"'"'; __file__='"'"'/tmp/pip-wheel-oQv3pU/pycrypto/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-Qsol2i
       cwd: /tmp/pip-wheel-oQv3pU/pycrypto/
  Complete output (211 lines):
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib.linux-x86_64-2.7
  creating build/lib.linux-x86_64-2.7/Crypto
  copying lib/Crypto/pct_warnings.py -> build/lib.linux-x86_64-2.7/Crypto
  copying lib/Crypto/__init__.py -> build/lib.linux-x86_64-2.7/Crypto
  creating build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/MD5.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/SHA224.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/MD2.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/MD4.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/SHA.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/SHA384.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/hashalgo.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/RIPEMD.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/SHA256.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/SHA512.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  copying lib/Crypto/Hash/HMAC.py -> build/lib.linux-x86_64-2.7/Crypto/Hash
  creating build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/ARC2.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/DES.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/AES.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/XOR.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/PKCS1_v1_5.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/Blowfish.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/DES3.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/PKCS1_OAEP.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/CAST.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/ARC4.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  copying lib/Crypto/Cipher/blockalgo.py -> build/lib.linux-x86_64-2.7/Crypto/Cipher
  creating build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/RFC1751.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/randpool.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/number.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/asn1.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/_number_new.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/py3compat.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/winrandom.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/py21compat.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  copying lib/Crypto/Util/Counter.py -> build/lib.linux-x86_64-2.7/Crypto/Util
  creating build/lib.linux-x86_64-2.7/Crypto/Random
  copying lib/Crypto/Random/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Random
  copying lib/Crypto/Random/_UserFriendlyRNG.py -> build/lib.linux-x86_64-2.7/Crypto/Random
  copying lib/Crypto/Random/random.py -> build/lib.linux-x86_64-2.7/Crypto/Random
  creating build/lib.linux-x86_64-2.7/Crypto/Random/Fortuna
  copying lib/Crypto/Random/Fortuna/SHAd256.py -> build/lib.linux-x86_64-2.7/Crypto/Random/Fortuna
  copying lib/Crypto/Random/Fortuna/FortunaGenerator.py -> build/lib.linux-x86_64-2.7/Crypto/Random/Fortuna
  copying lib/Crypto/Random/Fortuna/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Random/Fortuna
  copying lib/Crypto/Random/Fortuna/FortunaAccumulator.py -> build/lib.linux-x86_64-2.7/Crypto/Random/Fortuna
  creating build/lib.linux-x86_64-2.7/Crypto/Random/OSRNG
  copying lib/Crypto/Random/OSRNG/nt.py -> build/lib.linux-x86_64-2.7/Crypto/Random/OSRNG
  copying lib/Crypto/Random/OSRNG/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Random/OSRNG
  copying lib/Crypto/Random/OSRNG/fallback.py -> build/lib.linux-x86_64-2.7/Crypto/Random/OSRNG
  copying lib/Crypto/Random/OSRNG/rng_base.py -> build/lib.linux-x86_64-2.7/Crypto/Random/OSRNG
  copying lib/Crypto/Random/OSRNG/posix.py -> build/lib.linux-x86_64-2.7/Crypto/Random/OSRNG
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest
  copying lib/Crypto/SelfTest/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest
  copying lib/Crypto/SelfTest/st_common.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_CAST.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_XOR.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_ARC4.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/common.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_DES3.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_ARC2.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_Blowfish.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_AES.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  copying lib/Crypto/SelfTest/Cipher/test_DES.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Cipher
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_SHA224.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_MD4.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_RIPEMD.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_SHA384.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_HMAC.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_MD2.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/common.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_SHA512.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_SHA256.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_SHA.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  copying lib/Crypto/SelfTest/Hash/test_MD5.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Hash
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Protocol
  copying lib/Crypto/SelfTest/Protocol/test_rfc1751.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Protocol
  copying lib/Crypto/SelfTest/Protocol/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Protocol
  copying lib/Crypto/SelfTest/Protocol/test_KDF.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Protocol
  copying lib/Crypto/SelfTest/Protocol/test_AllOrNothing.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Protocol
  copying lib/Crypto/SelfTest/Protocol/test_chaffing.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Protocol
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/PublicKey
  copying lib/Crypto/SelfTest/PublicKey/test_importKey.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/PublicKey
  copying lib/Crypto/SelfTest/PublicKey/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/PublicKey
  copying lib/Crypto/SelfTest/PublicKey/test_ElGamal.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/PublicKey
  copying lib/Crypto/SelfTest/PublicKey/test_RSA.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/PublicKey
  copying lib/Crypto/SelfTest/PublicKey/test_DSA.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/PublicKey
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random
  copying lib/Crypto/SelfTest/Random/test_rpoolcompat.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random
  copying lib/Crypto/SelfTest/Random/test__UserFriendlyRNG.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random
  copying lib/Crypto/SelfTest/Random/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random
  copying lib/Crypto/SelfTest/Random/test_random.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/Fortuna
  copying lib/Crypto/SelfTest/Random/Fortuna/test_FortunaAccumulator.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/Fortuna
  copying lib/Crypto/SelfTest/Random/Fortuna/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/Fortuna
  copying lib/Crypto/SelfTest/Random/Fortuna/test_SHAd256.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/Fortuna
  copying lib/Crypto/SelfTest/Random/Fortuna/test_FortunaGenerator.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/Fortuna
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  copying lib/Crypto/SelfTest/Random/OSRNG/test_posix.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  copying lib/Crypto/SelfTest/Random/OSRNG/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  copying lib/Crypto/SelfTest/Random/OSRNG/test_winrandom.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  copying lib/Crypto/SelfTest/Random/OSRNG/test_generic.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  copying lib/Crypto/SelfTest/Random/OSRNG/test_nt.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  copying lib/Crypto/SelfTest/Random/OSRNG/test_fallback.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Random/OSRNG
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Util
  copying lib/Crypto/SelfTest/Util/test_asn1.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Util
  copying lib/Crypto/SelfTest/Util/test_number.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Util
  copying lib/Crypto/SelfTest/Util/test_Counter.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Util
  copying lib/Crypto/SelfTest/Util/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Util
  copying lib/Crypto/SelfTest/Util/test_winrandom.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Util
  creating build/lib.linux-x86_64-2.7/Crypto/SelfTest/Signature
  copying lib/Crypto/SelfTest/Signature/test_pkcs1_pss.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Signature
  copying lib/Crypto/SelfTest/Signature/test_pkcs1_15.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Signature
  copying lib/Crypto/SelfTest/Signature/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/SelfTest/Signature
  creating build/lib.linux-x86_64-2.7/Crypto/Protocol
  copying lib/Crypto/Protocol/KDF.py -> build/lib.linux-x86_64-2.7/Crypto/Protocol
  copying lib/Crypto/Protocol/Chaffing.py -> build/lib.linux-x86_64-2.7/Crypto/Protocol
  copying lib/Crypto/Protocol/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Protocol
  copying lib/Crypto/Protocol/AllOrNothing.py -> build/lib.linux-x86_64-2.7/Crypto/Protocol
  creating build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/pubkey.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/RSA.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/DSA.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/_DSA.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/_slowmath.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/_RSA.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  copying lib/Crypto/PublicKey/ElGamal.py -> build/lib.linux-x86_64-2.7/Crypto/PublicKey
  creating build/lib.linux-x86_64-2.7/Crypto/Signature
  copying lib/Crypto/Signature/PKCS1_v1_5.py -> build/lib.linux-x86_64-2.7/Crypto/Signature
  copying lib/Crypto/Signature/__init__.py -> build/lib.linux-x86_64-2.7/Crypto/Signature
  copying lib/Crypto/Signature/PKCS1_PSS.py -> build/lib.linux-x86_64-2.7/Crypto/Signature
  running build_ext
  running build_configure
  checking for gcc... gcc
  checking whether the C compiler works... yes
  checking for C compiler default output file name... a.out
  checking for suffix of executables...
  checking whether we are cross compiling... no
  checking for suffix of object files... o
  checking whether we are using the GNU C compiler... yes
  checking whether gcc accepts -g... yes
  checking for gcc option to accept ISO C89... none needed
  checking for __gmpz_init in -lgmp... no
  checking for __gmpz_init in -lmpir... no
  checking whether mpz_powm is declared... no
  checking whether mpz_powm_sec is declared... no
  checking how to run the C preprocessor... gcc -E
  checking for grep that handles long lines and -e... /bin/grep
  checking for egrep... /bin/grep -E
  checking for ANSI C header files... yes
  checking for sys/types.h... yes
  checking for sys/stat.h... yes
  checking for stdlib.h... yes
  checking for string.h... yes
  checking for memory.h... yes
  checking for strings.h... yes
  checking for inttypes.h... yes
  checking for stdint.h... yes
  checking for unistd.h... yes
  checking for inttypes.h... (cached) yes
  checking limits.h usability... yes
  checking limits.h presence... yes
  checking for limits.h... yes
  checking stddef.h usability... yes
  checking stddef.h presence... yes
  checking for stddef.h... yes
  checking for stdint.h... (cached) yes
  checking for stdlib.h... (cached) yes
  checking for string.h... (cached) yes
  checking wchar.h usability... yes
  checking wchar.h presence... yes
  checking for wchar.h... yes
  checking for inline... inline
  checking for int16_t... yes
  checking for int32_t... yes
  checking for int64_t... yes
  checking for int8_t... yes
  checking for size_t... yes
  checking for uint16_t... yes
  checking for uint32_t... yes
  checking for uint64_t... yes
  checking for uint8_t... yes
  checking for stdlib.h... (cached) yes
  checking for GNU libc compatible malloc... yes
  checking for memmove... yes
  checking for memset... yes
  configure: creating ./config.status
  config.status: creating src/config.h
  warning: GMP or MPIR library not found; Not building Crypto.PublicKey._fastmath.
  building 'Crypto.Hash._MD2' extension
  creating build/temp.linux-x86_64-2.7
  creating build/temp.linux-x86_64-2.7/src
  x86_64-linux-gnu-gcc -pthread -fwrapv -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -fstack-protector-strong -Wformat -Werror=format-security -fPIC -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.7 -c src/MD2.c -o build/temp.linux-x86_64-2.7/src/MD2.o
  src/MD2.c:31:20: fatal error: Python.h: No such file or directory
  compilation terminated.
  error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for pycrypto

After some research, it looks like there’s another dependency for this, python-dev. Blew away the whole virtual environment again and performed the following:

apt-get install virtualenv
apt-get install python-dev
virtualenv ldap_proxy
. ./ldap_proxy/bin/activate
cd ./ldap_proxy
nano requirements.txt
pip install -r requirements.txt

Everything works great so far…then this:

(ldap_proxy) root@localhost:/etc/privacyidea/ldap_proxy# pip install .
ERROR: Directory '.' is not installable. Neither 'setup.py' nor 'pyproject.toml' found.

Running find . setup.py turns up No such file or directory. Is there something else that must be done first? A file I need to copy from somewhere or some other pre-requisite package?

ugh…assumptions are made about the user’s knowledge of Linux. This got the plugin installed and running for me.

#Install pre-requisites, unsure of need for python-dev
apt-get install virtualenv python-dev

#Create virtual environment for plugin
virtualenv ldap_proxy

#Change directory to virtual environment, download plugin, and decompress to current location.
cd ./ldap_proxy
wget https://github.com/privacyidea/privacyidea-ldap-proxy/archive/v0.6.1.tar.gz
tar xvzf v0.6.1.tar.gz

#Activate virtual environment
. ./bin/activate

#Python installation of pre-requisites
pip install -r requirements.txt

#Plugin Installation
pip install .

A couple further questions

  1. What’s a good way of testing the plugin?
  2. What’s the secret order look like, AD password+Pin+OTP?

I have verified that the plugin is listening on the designated port and can connect via LDAP but fail to bind when using the built-in Windows utility, Ldp. Looking at the plugin output, it says “Invalid Credentials”, so I’m not sure what it wants.

Glad to hear you got it working!

You need to tell the LDAP proxy where your privacyIDEA server and the LDAP “backend” are located, and how DNs of incoming bind requests should be resolved to privacyIDEA login names. The example proxy.ini contains some documentation.

The LDAP proxy simply forwards the password received in a bind request to privacyIDEA. Hence, the interpretation of the password depends on the configuration of privacyIDEA: By default, this would be PIN+OTP.

I’d like to emphasize that the LDAP proxy will only be useful for a very narrow set of use cases. In other words, it is very likely that there is a better way to integrate 2FA in an application. What kind of application are you considering?

Yes, I have a config file setup as below (sensitive info modified). I currently have allow-search and connection reset set to true so that Windows LDP tool would function, not sure of their need when going through PrivacyIDEA. We are looking at Cisco ASA VPN integration using LDAP so that the ASA can apply policy based on a user’s group membership in AD.

[privacyidea]
instance = https://FQDN.of.server
verify = True

[ldap-backend]
endpoint = tcp:host=FQDN.of.DomainController:port=389
test-connection = true

[service-account]
dn = "domain\serviceaccount"
password = 

[ldap-proxy]
endpoint = tcp:port=1389
#We do not want to allow passthrough binds, but setting is required.
passthrough-binds = "dc=test,dc=local"
bind-service-account = false
allow-search = true
allow-connection-reuse = true
ignore-search-result-references = false
forward-anonymous-binds = false

[user-mapping]
strategy = lookup
attribute = sAMAccountName

[realm-mapping]
strategy = static
realm =

[bind-cache]
enabled = false
timeout = 3

[app-cache]
enabled = false

Having issues getting this to function properly, any ideas @fredreichbier.

I have the following config file setup.

[privacyidea]
instance = https://mfa.example.com
verify = True

[ldap-backend]
endpoint = tcp:host=dc.example.com:port=389
test-connection = true

[service-account]
dn =
password =

[ldap-proxy]
endpoint = tcp:port=389
passthrough-binds = "CN=Service\, PrivacyIDEA,OU=Users,DC=example,DC=com"
bind-service-account = true
allow-search = true
allow-connection-reuse = true
ignore-search-result-references = true
forward-anonymous-binds = false

[user-mapping]
#strategy = lookup
#attribute = sAMAccountName
strategy = match
pattern = "(?i)example\\(.+)"

[realm-mapping]
strategy = static
realm = example

[bind-cache]
enabled = false
timeout = 3

[app-cache]
enabled = false

When testing connectivity using ldp, I connect to mfa.example.com fine and get the RootDSE output. When performing a bind, I have three options:

Bind as currently logged on user: This doesn’t work. Expected it to fail as it tries to use an AD account password

Bind with Credentials: This doesn’t work. This has three fields; username, password, domain. Expected this to work as I can specify my pin+otp in the password field, I get the below output in ldp when attempting this method, I get nothing on the proxy std out.

0 = ldap_set_option(ld, LDAP_OPT_ENCRYPT, 0)
res = ldap_bind_s(ld, NULL, &NtAuthIdentity, NEGOTIATE (1158)); // v.3
	{NtAuthIdentity: User='testuser'; Pwd=<unavailable>; domain = 'example'}
Error <49>: ldap_bind_s() failed: Invalid Credentials.
Server error: <empty>

Simple Bind: This works, kind of. I have two fields here, username and password. Specifying domain\testuser in the username field and my pin+otp in the password field gets me the below outputs. Why does it say I’m authenticated as anonymous?

ldp output

res = ldap_simple_bind_s(ld, 'example\testuser', <unavailable>); // v.3
Authenticated as: 'NT AUTHORITY\ANONYMOUS LOGON'.

proxy std out

2019-09-25T15:29:51-0500 [pi_ldapproxy.proxy#info] BindRequest for 'example\\testuser' received ...
2019-09-25T15:29:51-0500 [pi_ldapproxy.proxy#info] Resolved 'example\\testuser' to 'testuser'@'example' ('example')
2019-09-25T15:29:51-0500 [twisted.web.client._HTTP11ClientFactory#info] Starting factory <twisted.web.client._HTTP11ClientFactory instance at 0x7f1a7723aab8>
2019-09-25T15:29:52-0500 [pi_ldapproxy.proxy#info] Successful authentication, authenticating as service user ...
2019-09-25T15:29:52-0500 [pi_ldapproxy.proxy#info] Binding service account ...
2019-09-25T15:29:52-0500 [twisted.web.client._HTTP11ClientFactory#info] Stopping factory <twisted.web.client._HTTP11ClientFactory instance at 0x7f1a7723aab8>
2019-09-25T15:29:52-0500 [pi_ldapproxy.proxy#info] Sending BindResponse "success"

I say that kind of works because any further activities, like browsing the directory tree presents the below error in ldp, no activity is shown in the proxy std out.

Expanding base 'DC=example,DC=com'...
ldap_get_next_page_s failed: 1
Server error: 000004DC: LdapErr: DSID-0C09075A, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1
Error 0x4DC The operation being requested was not performed because the user has not been authenticated.
Result <1>: 000004DC: LdapErr: DSID-0C09075A, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1
Getting 0 entries:

The only way I can get ldp to work properly is to set forward-anonymous-binds to true in the ldap proxy config file.

I also tried Rapid 7’s InsightVM application. This application offers LDAP/AD integration for user authentication. I configured an LDAP connection as shown below:
image
When I attempt to login with username testuser and pin+otp for the password field, I get a login failure with the below error output on the ldap proxy

2019-09-25T15:49:50-0500 [twisted.internet.endpoints.OneShotFactory#info] Starting factory <twisted.internet.endpoints.OneShotFactory instance at 0x7fbe054058c0>
2019-09-25T15:49:50-0500 [TwoFactorAuthenticationProxy,2,192.168.1.138] Unhandled Error
        Traceback (most recent call last):
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/python/log.py", line 103, in callWithLogger
            return callWithContext({"system": lp}, func, *args, **kw)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/python/log.py", line 86, in callWithContext
            return context.call({ILogContext: newCtx}, func, *args, **kw)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
            return self.currentContext().callWithContext(ctx, func, *args, **kw)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
            return func(*args,**kw)
        --- <exception caught here> ---
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
            why = selectable.doRead()
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 208, in doRead
            return self._dataReceived(data)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 214, in _dataReceived
            rval = self.protocol.dataReceived(data)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/ldaptor/protocols/ldap/ldapserver.py", line 49, in dataReceived
            self.berdecoder, self.buffer)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/ldaptor/protocols/pureber.py", line 373, in berDecodeObject
            berdecoder=inh)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/ldaptor/protocols/pureldap.py", line 57, in fromBER
            l = berDecodeMultiple(content, berdecoder)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/ldaptor/protocols/pureber.py", line 392, in berDecodeMultiple
            n, bytes = berDecodeObject(berdecoder, content)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/ldaptor/protocols/pureber.py", line 373, in berDecodeObject
            berdecoder=inh)
          File "/etc/privacyidea/ldap_proxy/local/lib/python2.7/site-packages/ldaptor/protocols/pureldap.py", line 136, in fromBER
            auth = (l[2][0].value, l[2][1].value)
          File "/usr/lib/python2.7/UserList.py", line 31, in __getitem__
            def __getitem__(self, i): return self.data[i]
        exceptions.IndexError: list index out of range

2019-09-25T15:49:50-0500 [pi_ldapproxy.proxy#info] Client has disconnected already, closing connection to LDAP backend ...
2019-09-25T15:49:50-0500 [twisted.internet.endpoints.OneShotFactory#info] Stopping factory <twisted.internet.endpoints.OneShotFactory instance at 0x7fbe054058c0>

However, if I use the user’s AD password only, the same error as above is thrown, BUT I authenticate into the application!

I assume this is because I have the service account in the application configured as the passthrough-binds. If this is the case, then how do I configure applications that require a service account? How do I get this plugin to work?