How to Authenticate Against openLDAP Without Knowing DN Using java

In fact you can’t do it without knowing DN! There is an anonymous access in openLDAP which is enabled by default. The anonymous access let one to query(search filter) openLDAP without knowing bind username/password.

Run following command on your openLDAP server :

ldapwhoami -H ldap:// -x

If you get “anonymous” as result you are all set and your openLDAP is supporting anonymous query, otherwise this blog is not the one you are looking for!

So What’s the Deal?

Assume you know UID of the user in ldap directory but not his DN and assume the root directory hierarchy is : dc=devcrutch,dc=com . How do you want to get CN and then DN of such user in LDAP just by using UID? you might think of such query to get data out of openLDAP

uid=USERNAME,dc=devcrutch,dc=com

If you run this query, it’ll get you to nowhere.

Here Comes the Anonymous Query

First of all you have to query the whole directory for finding such user. You have to create a query similar to following:

(&(objectClass=*)(uid=USERNAME))

This query will search the entire Directory Information Tree (DIT) for such user name.

ldapsearch -x -h 127.0.0.1 -b dc=devcrutch,dc=com "(&(objectClass=*)(uid=USERNAME))"

With such query you can get the DN. Using DN and password you can authenticate against LDAP.

Well this was the idea, applying a search filter using USERNAME via anonymous identity then find the DN and finally login using the retrieved DN.

Time for Some java

Now we have the rough idea it’s time to implement it in java. For finding DN you need to query the entire LDAP directory (note: in real world searching the entire directory is not a good idea, you have to narrow your query, otherwise your query might consume all the server’s resources)

private String findDN(String user) throws Exception {
    DirContext ctx = getContext();
    String dn = null;
    String filter = "(&(objectClass=*)(uid=" + user + "))";
    NamingEnumeration answer = ctx.search("", filter, getSimpleSearchControls());
    if (answer.hasMore()) {
        SearchResult result = (SearchResult) answer.next();
        dn = result.getNameInNamespace();
    }
    answer.close();
    return dn;
}

Then after finding the correct DN you can bind your username and password

public DirContext bind(String username, String password) throws Exception {
        DirContext dirContext;
        Hashtable<String, String> env = new Hashtable<String, String>();
        String dn = findDN(username);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, dn);
        env.put(Context.SECURITY_CREDENTIALS, password);
        try {
            dirContext = getContext(env);
        } catch (javax.naming.AuthenticationException e) {
            throw new Exception(e);
        }
        return dirContext;
}

That’s it.

You can find a working source code on my github


How to use CompletableFuture in SpringBoot 2

In Spring Boot there is an annotation @Async to assist developers for developing concurrent applications. But using this feature is quite tricky. In this blog we will see how to use this feature along with CompletableFuture. I assumed you know the drill about CompletableFuture, so I won’t repeat the concept here.

First of all you need to annotate your application class with @EnableAsync, this annotation tells the Spring to look for methods that are annotated with @Async and run them in a separate executor.

@SpringBootApplication
@EnableAsync
public class App {
    RestTemplate
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

If you take a look at Spring Boot example about @Async using CompletableFuture you’ll notice the way they’re using this feature is based on a REST request, in my opinion, I beleive, it’s kinda limited, it doesn’t give you a clue of how to use such feature in other situation. For an instance if you have a long running task what would you do about it?

// Source : https://spring.io/guides/gs/async-method/
package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.CompletableFuture;

@Service
public class GitHubLookupService {

    private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);

    private final RestTemplate restTemplate;

    public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    @Async
    public CompletableFuture<User> findUser(String user) throws InterruptedException {
        logger.info("Looking up " + user);
        String url = String.format("https://api.github.com/users/%s", user);
        User results = restTemplate.getForObject(url, User.class);
        // Artificial delay of 1s for demonstration purposes
        Thread.sleep(1000L);
        return CompletableFuture.completedFuture(results);
    }

}

In FindUser(String user), it uses a synthetic delay in the main thread also the main task of this method is fetching data from github using RestTemplate, this class is a “Synchronous client to perform HTTP requests”. How about using a long running task such as calling a network function, like ping a server from your REST endpoint? In that case you need to tailor the CompletableFuture. You can’t simply call following line and carry on.

return CompletableFuture.completedFuture(results);

How to Use CompletableFuture

For using @Async in your code, your method has to return Future or CompletableFuture for more information you can refer to its document. Take a look at following example :

@Async
    public CompletableFuture<Boolean> isServerAlive(String ip) {
        CompletableFuture<Boolean> future = new CompletableFuture<Boolean>(){
            @Override
            public Boolean get() throws InterruptedException, ExecutionException {
                InetAddress address = null;
                try {
                    address = InetAddress.getByName(ip);
                    return address.isReachable(1000);
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                    return false;
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            }
        };
        return future;
}

In this example I override the get() method and return the CompletableFuture without any thread executor, in fact with this method we ask Spring to execute the @Async method in a different thread, but we don’t provide any thread executor, only body of a background-worker will suffice.

download source code from github

P.S : In this example I decided to use a network function inside Spring Boot just for the sake of argument. But it’s better to not to use network functions directly in a REST endpoint. Specially when you expect to get an immediate result out of it. The reason: network functions are blocking which means, if you call this REST endpoint. You’ll have to wait to get the result from the endpoint. It’s highly advised to use other methods such as queue or push method(e.g. websocket) for calling blocking functions.

How to install maven on Ubuntu manually with any specific version

For installing Maven on Ubuntu you have two ways  the easy way and the manual method. The easy way is just execute following command :

sudo apt-get install maven

Or if you use Ubuntu 16+ you can use following command too :

sudo apt install maven

Just remember you need to have root privileges.

The manual way

If you want to have the latest version of Maven on your Ubuntu go to the Maven website and download the latest binary package then you can extract it in /opt/  using command :

tar xvf apache-maven-3.5.2-bin.tar.gz -C /opt/

make sure you have set your JAVA_HOME if you don’t know how you can read this post

then open up your /etc/environment add following to your path

PATH=_YOUR_OLD_PATH:/opt/apache-maven-3.5.2/bin/

quit from your editor then type

source /etc/environment

to test if maven is installed type

mvn -v

 

How to install JDK on Ubuntu

Installing Java JDK is easy and straightforward in Windows and OSX but not in Ubuntu. Here is how I am installing JDK on Ubuntu.
Download the latest JDK package from Oracle website. If you don’t know which file to choose you ought to select .tar.gz files whether 32bit or 64bit depends on your requirements.
after download the right package you need to extract it using following command you can extract it :

tar xvf jdk-8u161-linux-x64.tar.gz -C /opt/

Note : In this example I am using JDK version 8 revision 161

The /opt directory is where I chose to extract my JDK.

After extracting my JDK it is time to let Ubuntu know where to look after the Java Development Kit and Java Run Time.

Suppose you want to install your java and javac and javaws executable files in /usr/bin directory :

sudo update-alternatives --install /usr/bin/java java /opt/jdk1.8.0_161/bin/java 1
sudo update-alternatives --install /usr/bin/javac javac /opt/jdk1.8.0_161/bin/javac 1
sudo update-alternatives --install /usr/bin/javaws javaws /opt/jdk1.8.0_161/bin/javaws 1

After executing update-alternatives its time to set JAVA_HOME. Open /etc/environment file and add following lines to it :

JAVA_HOME="/opt/jdk1.8.0_161/"
export JAVE_HOME

Then type

source /etc/environment

now in command line if you type

java -version

you will see the result.