Saturday, October 30. 2021
Java ldappasswd implementation for the password modify extended operation
A quick entry this time to present a java implementation of the ldappasswd command tool. The ldap protocol by default performs a password change just sending the modification of the userPassword attribute, just like any other attribute. This behavior was considered not safe and an extended operation was standardized via rfc3062 soon. The extension allows to incorporate the typical requirements to the password change: ensure that it is done under adequate security conditions; allow sending the old password to validate it at modification time; generate a random password and return it to implement a reset... The final name of the extension is LDAP Password Modify Extended Operation (oid 1.3.6.1.4.1.4203.1.11.1) and nowadays it is supported by the majority of the servers. But the JNDI client does not include this extension and, although there are several implementations out there, I decided to implement it along with an ldappasswd counterpart just using plain JavaSE. This entry is the result of that adventure.
The post is not going to comment the java implementation in detail. The code consists in two classes for the standardized request and response (basically the management of the ASN.1 for the fields needed in both parts) and another one for the command. To use the extensions just create an LdapContext normally and call the extendedOperation method passing the initialized request. The LdapPasswd main class executes the same to perform the password change, so you can also check it if you want an example.
LdapContext ctx = new InitialLdapContext(env, null);
PasswordModifyExtendedRequest passwordModifyRequest = new PasswordModifyExtendedRequest(
"uid=ricky,ou=People,dc=sample,dc=com", "old-password", "new-password");
PasswordModifyExtendedResponse passwordModifyResponse =
(PasswordModifyExtendedResponse) ctx.extendedOperation(passwordModifyRequest);
The complete maven project can be downloaded from here and the usage for the main class is more or less the same than the one used in the UNIX package.
unzip ldappasswd.zip
cd ldappasswd
mvn clean package
java -jar target/ldappasswd-1.0.0-SNAPSHOT.jar -h
Exception in thread "main" java.lang.IllegalArgumentException:
USAGE: java -jar ldappasswd.jar [-H ldapuri] [-D binddn] [-W] [-w passwd] [-A] [-a oldPasswd] [-S] [-s newPasswd] [-Z] [user]
OPTIONS:
-H <ldapuri>: DN of the admin user to connect with (default: "ldap://localhost:389")
-D <binddn>: DN of the admin user to connect with (ex: "cn=Directory Manager")
-W: Promp for the password of the admin user to connect with
-w <passwd>: Password of the admin user to connect with
-A: Promp for the old password
-a <oldPasswd>: Old password of the user
-S: Promp for the new password
-s <newPasswd>: New password of the user
-k: insecure connection (accepts any certificate)
-Z: StartTLS before connecting.
-h: Prints this help.
ARGUMENTS:
[user]: DN of the user to change the password (if none it will be changed to the connected user)
Once the tool is ready it is time for the ldap server. This time the 389 Directory Server implementation is going to be used. This ldap software is also a derivative of the old netscape server and it is available in all linux distributions. I decided to install a Debian 11.1 in a VM and quickly setup the package. The installation and configuration is easy.
apt-get install 389-ds
dscreate interactive
Selinux support will be disabled, continue? Yes
Enter system hostname [debian11]:
Enter the instance name [debian11]:
Enter port number [389]:
Create self-signed certificate database [yes]:
Enter secure port number [636]:
Enter Directory Manager DN [cn=Directory Manager]:
Enter the Directory Manager password: password
Confirm the Directory Manager Password: password
Enter the database suffix (or enter "none" to skip) [dc=debian11]: dc=sample,dc=com
Create sample entries in the suffix [no]:
Create just the top suffix entry [no]: yes
Do you want to start the instance after the installation? [yes]:
Are you ready to install? [no]: yes
The software is installed and one instance is created using the default ports and a self-signed certificate. Then a user is added in order to perform the tests with it.
ldapmodify -h localhost -p 389 -D "cn=Directory Manager" -W
dn: ou=People,dc=sample,dc=com
changetype: add
objectclass: organizationalUnit
ou: People
adding new entry "ou=People,dc=sample,dc=com"
dn: uid=ricky,ou=People,dc=sample,dc=com
changetype: add
objectclass: inetorgperson
uid: ricky
sn: ricky
cn: ricky
userpassword: passsword
adding new entry "uid=ricky,ou=People,dc=sample,dc=com"
Now the server is congured to allow users to change their own passwords. An ACL is needed, which should be added to the tree.
ldapmodify -h localhost -p 389 -D "cn=Directory Manager" -W
dn: dc=sample,dc=com
changetype: modify
add: aci
aci: (targetattr = "userPassword") (version 3.0; acl "allow userpassword self modification"; allow (write) userdn = "ldap:///self";)
One more command is presented to show that 389-ds supports the password modify extension.
ldapsearch -h localhost -p 389 -D "cn=Directory Manager" -W -s base -b "" supportedExtension | grep 1.3.6.1.4.1.4203.1.11.1
supportedExtension: 1.3.6.1.4.1.4203.1.11.1
Finally the certificate used by the server was obtained and saved in debian11.p12 trust-store with password changeit. Time to start showing the ldappasswd command with different arguments.
Auto change the password for the same user passing the previous and new password:
java -Djavax.net.ssl.trustStore=debian11.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar target/ldappasswd-1.0.0-SNAPSHOT.jar -H ldaps://debian11:636 -D "uid=ricky,ou=People,dc=sample,dc=com" -w password -a password -s new-password # Using LDAP url ldaps://debian11:636... # Connecting as user uid=ricky,ou=People,dc=sample,dc=com... # Performing password change...
Auto change the password with previous password but generating the new one:
java -Djavax.net.ssl.trustStore=debian11.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar target/ldappasswd-1.0.0-SNAPSHOT.jar -H ldaps://debian11:636 -D "uid=ricky,ou=People,dc=sample,dc=com" -w password -a password # Using LDAP url ldaps://debian11:636... # Connecting as user uid=ricky,ou=People,dc=sample,dc=com... # Performing password change... # generated passwd: n02TRMuu
Using an administrator and only sending the new password:
java -Djavax.net.ssl.trustStore=debian11.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar target/ldappasswd-1.0.0-SNAPSHOT.jar -H ldaps://debian11:636 -D "cn=Directory Manager" -w password -s new-password uid=ricky,ou=People,dc=sample,dc=com # Using LDAP url ldaps://debian11:636... # Connecting as user cn=Directory Manager... # Performing password change...
Using an admin user but performing a start SSL over the port 389.
java -Djavax.net.ssl.trustStore=debian11.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar target/ldappasswd-1.0.0-SNAPSHOT.jar -H ldap://debian11 -Z -D "cn=Directory Manager" -w password -s new-password uid=ricky,ou=People,dc=sample,dc=com # Using LDAP url ldap://debian11... # Performing the StartTLS with user cn=Directory Manager... # Performing password change...
The operation cannot be done without TLS. This is enforced by the server.
java -Djavax.net.ssl.trustStore=debian11.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar target/ldappasswd-1.0.0-SNAPSHOT.jar -H ldap://debian11 -D "cn=Directory Manager" -w password -s new-password uid=ricky,ou=People,dc=sample,dc=com # Using LDAP url ldap://debian11... # Connecting as user cn=Directory Manager... # Performing password change... Exception in thread "main" javax.naming.AuthenticationNotSupportedException: [LDAP: error code 13 - Operation requires a secure connection. ]; remaining name '' at ...
Please note that other servers can act differently. For example the attached maven project performs some tests using apache-ds and it does not generate any password in the response. Therefore with the apache software the new password is compulsory (-s or -S options in the command). As the RFC mentions, the server can not recognize or support the combination of the provided fields (user-dn, old and new password), in that case it should not proceed with the password change and return an error.
That is all for today. If, for whatever reason, you need the ldap modify password extension in a Java project, here you have an example that requires nothing except JavaSE. Feel free to re-use or extend the code as you need.
Extended regards!
Sunday, March 3. 2019
Emulating the AD range attribute retrieval feature
Another quick entry today, I have been involved in a keycloak problem with windows AD. The issue can be summarized in the idea that the Active Directory, when an entry has a lot of values in one attribute (usually a group entry with a lot of users inside member), not all of them are returned by default. There is a MaxValRange limit that controls when the AD starts to omit values and return the values in ranges. Microsoft documents this feature in this note Searching Using Range Retrieval with some useful examples.
Configuring the limit to its lower value (30) in one of my demo envs the results in my tests were the following:
Retrieving the members from a group with 31 users activates the limit, and only 0-29 values are returned.
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* member dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=0-29: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM member;range=0-29: CN=aduser4 aduser4,CN=Users,DC=SAMPLE,DC=COM ... member;range=0-29: CN=Administrator,CN=Users,DC=SAMPLE,DC=COM
The missing entry can be obtained requesting more data from 30 to the end (* means the the last attribute value):
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=30-*" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=30-*: CN=aduser6 aduser6,CN=Users,DC=SAMPLE,DC=COM
You can also request just a specific range of the attribute (for example entries 28-29):
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=28-29" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=28-29: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM member;range=28-29: CN=aduser4 aduser4,CN=Users,DC=SAMPLE,DC=COM
If the upper limit is greater than the current number of values in the attribute * is returned to mark that the last value was reached:
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=29-40" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=29-*: CN=aduser6 aduser6,CN=Users,DC=SAMPLE,DC=COM member;range=29-*: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM
What happens if the upper range requested is wrong or less than the start range? Just one element is returned.
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=29-10" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=29-29: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM
And if the start position is wrong? An error is returned.
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=50-*" Operations error (1) Additional information: 00002121: SvcErr: DSID-031206B8, problem 5012 (DIR_ERROR), data 8995
So the range retrieval is easy to use and understand but my main problem was that I needed to test this feature inside keycloak. The basic tests use the apache directory server embedded inside the same java code to test everything with maven. This range retrieval feature is very AD specific (I do not know any other LDAP directory that performs the same) so the Apache implementation does not do the same by default. But the project lets you implement your own interceptors. And, no sooner said than done, I implemented a ranged interceptor to emulate AD behavior. My implementation is very easy, it only applies to one attribute that should be specified, but range attribute value retrieval can be emulated in an embedded LDAP server for it, so I can write some tests to check if the implementation is working smoothly.
The entry's goal is just saving my interceptor here. It is just one class and some easy junit tests that check everything is working, but better if the class is saved here. The maven project can be downloaded from here.
Best regards!
Saturday, September 27. 2014
Secure Login in LDAP
The main security constraint about the LDAP protocol is that passwords (in the common scenario) travel through the network in clear. If we keep in mind that this protocol is used mainly to authenticate users, the risk is even greater. This entry is going to show briefly the typical solutions for this security problem and exemplify how applications should interact with those solutions (Java examples).
Some time ago a previous entry about LDAP was presented, in that occasion the post talked about password policies. Nevertheless a simple Bind class was presented that checked the password for a user. This class used a tricky reconnect to retrieve the controls returned by the Bind, but now the solution is going to be improved in order to perform all the steps without re-login (you know, learn something new everyday). The class will be slightly modified for each different solution presented throughout the entry. In the server part two different LDAP servers will be used: OpenLDAP (default debian package working in standard ports 389 and 636) and the old OpenDS (installed apart in ports 1389 and 1636).
SASL / DIGEST-MD5
The Simple Authentication Security Layer (SASL) is a kind of wrapper that permit applications to authenticate using different security mechanisms in a generic way. SASL defines several mechanisms like Kerberos (an old friend inside the blog) or DIGEST-MD5. This time, the later is the first technique presented in the entry to avoid clear text passwords.
DIGEST-MD5 is a mechanism to negotiate the credentials invented long ago for web servers (although it can be used in any other server type). The idea is quite simple: the client sends that it wants to login using SASL/DIGEST-MD5 in the BIND; the server responds with a nonce (a random number generated by the server) and the realm (a name for the place we want to login); the client with that information, username and password performs a MD5 hash (using the nonce produces a unique hash), and sends it to the server; the server recomputes the same hash and checks if both are the same. The advantage of this algorithm is clear, the password is never sent in a clear way, but there is also a disadvantage, the server needs to know the real password of the user (it should be stored with a reversible cryptographic method).
OpenLDAP supports DIGEST-MD5 but it has two restrictions: the user password should be in clear text (not reversible but plain) and a mapping is needed between username and DNs. I followed this entry from sbahloul blog in order to configure everything properly. Nevertheless Debian now does not use slapd.conf file and you need to configure the mapping performing ldap commands against the configuration branch. The following command creates a mapping to match the username sent in DIGEST-MD5 against the entry with that username set as uid attribute:
# ldapmodify -Y EXTERNAL -H ldapi:/// dn: cn=config changetype: modify add: olcAuthzRegexp olcAuthzRegexp: uid=([^,]*),cn=digest-md5,cn=auth ldap:///dc=example,dc=com??sub?(uid=$1)
Then the password of a user was assigned in clear text:
$ ldapmodify -h localhost -p 389 -D "cn=admin,dc=example,dc=com" -W dn: uid=ricky,ou=people,dc=example,dc=com changetype: modify replace: userpassword userpassword: XXXXXXXX
Finally the following ldapsearch command performs a SASL/DIGEST-MD5 bind against OpenLDAP:
$ ldapsearch -LLL -Y DIGEST-MD5 -h localhost -p 389 -b "dc=example,dc=com" -Q -U "ricky" -w XXXXXXXX uid=ricky dn dn: uid=ricky,ou=People,dc=example,dc=com
In this command the -Y option forces DIGEST-MD5 and now the username is specified with the -U option (instead of the common -D with the full DN of the user only the username is sent, the previous mapping locates the entry with the password for that uid).
In OpenDS the configuration is very similar and with similar steps. But OpenDS just needs a reversible encryption for the password (it can be AES, 3DES, Blowfish, Clear, Base64,...), for example I setup AES as the default storage mechanism for the default policy.
./dsconfig set-password-policy-prop -h localhost -p 4444 -D "cn=Directory Manager" \ -w XXXXXXXX -X -n --policy-name "Default Password Policy" \ --set default-password-storage-scheme:AES
It is clearly a more secure solution, but the key should be accessible by the server and, in the case of OpenDS, it is stored under a special branch cn=admin data of the server (under this branch the OpenDS software stores all the different keys it uses). If that key is obtained the passwords are equally compromised.
OpenDS also uses a mapping to locate the user password from the username, the default mapping is exactly the one that was implemented in OpenLDAP (the DIGEST-MD5 mechanism uses the mapping defined in the entry cn=Exact Match,cn=Identity Mappers,cn=config which maps the username with the uid). So the same ldapsearch presented before works with OpenDS (attacking to the 1389 port instead default 389).
Finally the file DigestMD5Bind.java is the class to login using DIGEST-MD5 in Java. The main characteristic is that a new property Context.SECURITY_AUTHENTICATION is set to DIGEST-MD5 in the environment to specify that this mechanism will be used. As I commented before, the new class is different to the one presented in the previous entry because now no re-bind is done. The context is created without username and password (the connection is established but no BIND is sent) and then that information is added to the context and the reconnect executed (the real BIND is sent to the server, letting us recover controls). Using DIGEST-MD5 the Context.SECURITY_PRINCIPAL should be the username (uid mapping) and not the complete DN of the user as in a common login. The representative code is presented below.
Hashtableenv = new Hashtable (); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, args[0]); LdapContext ctx = null; try { System.out.print("Using LDAP url " + args[0] + "... "); ctx = new InitialLdapContext(env, null); System.out.println("OK"); ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, args[1]); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, args[2]); ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5"); System.out.print("Connecting as " + args[1] + "... "); ctx.reconnect(null); System.out.println("OK"); }
And it can be executed with the following command (first argument is the LDAP URL, second the username and finally the password).
$ java -cp . DigestMD5Bind ldap://penance:389 ricky XXXXXXXX Using LDAP url ldap://penance:389... OK Connecting as ricky... OK
TLS
The previous login mechanism (DIGEST-MD5) avoids showing the clear password over the wire but compromises the solution storing user passwords in clear or with a reversible encryption algorithm. Those mechanisms were thought as a secondary option but never to replace the real and proper solution for this problem: TLS or SSL. The Transport Layer Security is a protocol to cryptographically secure any other TCP/IP protocol based on certificates and asymmetric keys.
In this first example the TLS mechanism will secure a previous non-secure connection. In this scenario the client opens a non-secure ldap connection and then it requests explicitly to start a TLS communication, in that moment the typical steps for securing the protocol are executed (certificate exchange, cipher selection,...). This way the application uses the same non-secure port (389 in OpenLDAP and 1389 in OpenDS) but, when the client explicitly requests it, the same socket (same port) starts a TLS session. This method avoids using a new port but the client should request explicitly the TLS connection.
In order to use TLS/SSL in OpenLDAP and OpenDS a new self-signed certificate was created (inside /etc/ldap directory).
# cd /etc/ldap # openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -subj "/C=ES/O=localhost/CN=penance" -keyout localhost.key -out localhost.crt
And the cn=config branch is modified in OpenLDAP to specify the new key and certificate file (debian instructions were followed) :
# ldapmodify -Y EXTERNAL -H ldapi:/// dn: cn=config changetype: modify add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ldap/localhost.key - add: olcTLSCertificateFile olcTLSCertificateFile: /etc/ldap/localhost.crt
Besides the startup command should be changed, in Debian the file /etc/default/slapd is modified to include the secure port 636 in the variable SLAPD_SERVICES (that variable is used as the -h option in the slapd daemon startup, this way the process start listening in the secure port too, the new port will be used in the next scenario).
SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"
Once the server is restarted the TLS can be tested using the following ldapsearch command in linux:
$ LDAPTLS_CACERT=/etc/ldap/localhost.crt \ ldapsearch -LLL -ZZ -H ldap://penance:389 -s base -b "dc=example,dc=com" \ -D "uid=ricky,ou=people,dc=example,dc=com" -w XXXXXXXX objectclass=* dn
The self-signed certificate is specified in the env variable LDAPTLS_CACERT as a trusted CA (PEM format) and then the option -ZZ is specified to force TLS in the communication.
Configuring OpenDS to use a certificate is even easier, it can be done at startup and this way the TLS/SSL is available at startup. The same ldapsearch presented before should work now for OpenDS in the port 1389.
Using Java the TLS should be started sending the StartTlsRequest as a extended operation (see this wonderful forum entry fro more information). The sample TlsBind.java is used to perform a TLS login, the context is again created without login (just establishing the connection), then the TLS request is executed and, finally, the login/BIND is executed. This way the BIND is performed once the secure connection is in place, so the password is sent in a secure way.
Hashtableenv = new Hashtable (); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, args[0]); LdapContext ctx = null; StartTlsResponse tls = null; try{ // create a context empty and then negotiate System.out.print("Using LDAP url " + args[0] + "... "); ctx = new InitialLdapContext(env, null); System.out.println("OK"); ExtendedRequest tlsRequest = new StartTlsRequest(); ExtendedResponse tlsResponse = ctx.extendedOperation(tlsRequest); tls = (StartTlsResponse)tlsResponse; System.out.print("Negotiating TLS... "); tls.negotiate(); System.out.println("OK"); // perform the login now that TLS is ready ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple"); ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, args[1]); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, args[2]); System.out.print("Connecting as " + args[1] + "... "); ctx.reconnect(null); System.out.println("OK"); // do not send more operations the connection is closed by the ldap server }
And the previous class can be executed in a similar way to the previous digest command:
$ java -Djavax.net.ssl.trustStore=penance.jks TlsBind ldap://penance:389 uid=ricky,ou=people,dc=example,dc=com XXXXXXXX Using LDAP url ldap://penance:1389... OK Negotiating TLS... OK Connecting as uid=ricky,ou=people,dc=example,dc=com... OK
Only two tips are remarkable. First, the javax.net.ssl.trustStore should be set to add the self-signed certificate as trusted for the Java execution. Second, in all the documentation I have read (for example the previous forum entry or the official Java documentation) it is commented that the previous connection can be re-used once the TLS session is closed. Nevertheless I have checked that the connection is always closed by the server (both, OpenLDAP and OpenDS) as soon as the client closes the TLS request. I suppose that TLS standard admits this behavior, so please take this in mind, once the TLS connection is established you should continue using it until the end, you cannot come back to the non-secure connection.
SSL
The final solution is just using the SSL port (default ldaps port 636 in OpenLDAP and 1636 in OpenDS). With this configuration all the communication is directly encrypted and therefore nothing is sent in plain. SSL was already configured in the previous point for both servers. In order to test the secure port a new ldapsearch command can be executed.
$ LDAPTLS_CACERT=/etc/ldap/localhost.crt \ ldapsearch -LLL -H ldaps://penance:636 -s base -b "dc=example,dc=com" \ -D "uid=ricky,ou=people,dc=example,dc=com" -w XXXXXXXX objectclass=* dn
The new Bind.java is very similar to the presented in the previous entry (this solution represents almost zero code change). Now only the Context.SECURITY_PROTOCOL is modified (it should be ssl for ldaps and plain to non-secure ldap), I just guessed the value depending the URL of the connection (it will be ssl if the URL starts with ldaps://, plain if not) and the same code works for secure and non-secure situations.
Hashtableenv = new Hashtable (); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, args[0]); env.put(Context.SECURITY_PROTOCOL, args[0].startsWith("ldaps://")? "ssl" : "plain"); LdapContext ctx = null; try { System.out.print("Using LDAP url " + args[0] + "... "); ctx = new InitialLdapContext(env, null); System.out.println("OK"); ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, args[1]); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, args[2]); System.out.print("Connecting as user " + args[1] + "... "); ctx.reconnect(null); System.out.println("OK"); }
The main class file is executed this way:
$ java -Djavax.net.ssl.trustStore=penance.jks -cp . Bind ldaps://localhost uid=ricky,ou=people,dc=example,dc=com XXXXXXXX Using LDAP url ldaps://localhost... OK Connecting as user uid=ricky,ou=people,dc=example,dc=com... OK
Again the javax.net.ssl.trustStore system property should be specified in order to trust in the self-signed certificate configured in both servers.
Today's entry is simple and direct, LDAP servers usually authenticate users receiving passwords in clear over the network, the post has commented three common techniques to encrypt them. The first method used DIGEST-MD5 which avoids clear passwords without using TLS/SSL. This algorithm needs the server to know the password of the user (that means passwords should be stored in clear or, at least, in a reversible cryptographic algorithm inside the server). Nevertheless the definitive solution for this problem is using ldaps (ldap over SSL/TLS). The entry has exemplified two situations: starting TLS over non-secure connection and using directly a secure SSL port. Obviously the second option is the recommended cos it is easier to develop inside pre-existing applications but both are equally secure.
Cheerio!
Comments