Implementing Basic Auth for a servlet in an OSGI environment

You will first need to get a reference to the OSGI HTTP Service. You can do this through a declarative service. This post will concentrate on steps after getting a reference to the HTTP Service.

Note: The complete class for this post is located here

When registering a servlet through the OSGI HTTP Service, it provides you with an option to provide an implementation of HTTPContext.


httpService.registerServlet(alias, new MyServlet(), initParams, null);

When we implement the HTTPContext interface we can implement three methods. Out of these three (3) handleSecurity will be called before serving a request to ermmm… check for security.


public class BasicAuthSecuredContext implements HttpContext{
    @Override
    public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
        return false;
    }

    @Override
    public URL getResource(String s) {
        return null;  
    }

    @Override
    public String getMimeType(String s) {
        return null;
    }
}

So, when implementing this, I’m borrowing a lot of content from the OSGI HTTPContext documentation and the HTTP Authentication spec. They are a must read, if you are interested in learning a lot, diving into details, etc. or you can just read the rest of this post.

First, it is a big no-no to do basic auth unless https is used. If it’s not there we let the user know it’s forbidden territory. Let’s go ahead and do that.

if (!request.getScheme().equals("https")) {
    response.sendError(HttpServletResponse.SC_FORBIDDEN);
    return false;
}

Next, let’s check for the Authorization header. If that’s not there we let them know, they need that shit to be there. Or we just say they’re unauthorized. Let’s do that now.

if (request.getHeader("Authorization") == null) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
}

Ok, two tests passed. Now, we do some real work. Let’s extract the header decode it, and do “not so proper” authentication.

    protected boolean authenticated(HttpServletRequest request) {
        String authzHeader = request.getHeader("Authorization");
        String usernameAndPassword = new String(Base64.decodeBase64(authzHeader.substring(6).getBytes()));

        int userNameIndex = usernameAndPassword.indexOf(":");
        String username = usernameAndPassword.substring(0, userNameIndex);
        String password = usernameAndPassword.substring(userNameIndex + 1);
        // Now, do the authentication against in the way you want, ex: ldap, db stored uname/pw
        // Here I will do lame hard coded credential check. HIGHLY NOT RECOMMENDED! 
        return ((username.equals("username") && password.equals("password"));
    }

Let’s integrate this method, into the handleSecurity method. Notice how a meaningful error message is set to the response (line 14) when the security fails. This prevents the user from guessing, and they knows what exactly went wrong. Ermm, at least, if they know HTTP error codes they would know exactly what went wrong.

    @Override
    public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (!request.getScheme().equals("https")) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }
        if (request.getHeader("Authorization") == null) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        if (authenticated(request)) {
            return true;
        } else {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
    }

That’s it. Now, pass this object when registering the servlet,

httpService.registerServlet(alias, new MyServlet(), initParams, new BasicAuthSecuredContext());

…and behold the power of basic auth in OSGI servlets!

Using Google collections’ MapMaker to quickly build a cache

Building a cache is standard practice in most programs to reduce the overhead of re-creating expensive objects. Using a concurrent Hash Map to build a thread safe cache is a widely user practice.

Even though each method call of concurrent Hash Map is thread safe, it is cumbersome to re-do the necessary operations. Let me list these down:

  • Compound operations of checking and inserting data into a HashMap – This can result in duplicate objects being created. You may have to use extensive checks using putIfAbsent to avoid these sort of situations.
  • Cache expiry – Getting a scheduled thread to clear the cache
  • Look at whether you want strong or weak references, strong or weak keys
  • Limit as to how many concurrent updates are allowd

Let me introduce MapMaker, a very convenient Factory object present in the Google Collections library. It lets me do everything mentioned in the above list in a single object initialization.

ConcurrentMap<Key, HeavyObject> graphs = new MapMaker()
 .concurrencyLevel(10)
 .softKeys()
 .weakValues()
 .expiration(15, TimeUnit.MINUTES)
 .makeComputingMap( new Function<Key, HeavyObject>() { 
 public Graph apply(Key key) { 
 return createHeavyObject(key); 

});

Now, all you have to do to use the cache is do a call to the get method:

graphs.get(someKey);

This will create the object, making sure other threads are blocked until the Heavy Object is created properly and the same object is returned for the specific key to any other thread as well.

Note: Make sure you implement the equals() and hashCode() methods if your Key is a complex object.

Hope you find it useful in your Java code.

Using maven3 with vim

Vim’s ability to execute commands from vim itself adds a great deal of productivity. Although, it’s debatable that it’s the best editor for Java, I made an attempt to work with maven3 inside vim and integrate it with vim’s quick fix list. Disclaimer: I’m not a vim expert, just an enthusiast. Please drop a comment as this tip is in need of improvements.

First, change make to work with maven. I’ve added -q so that only errors will reach the console.

set makeprg=mvn\ compile\ -q\ -f\ pom.xml

Change the error format to match maven3 output. Disclaimer: This is not perfect, but it manages to pick up the maven3 errors.

 set errorformat=[ERROR]\ %f:[%l%.%c]%m

Change your working directory to the root of the maven project with :cd

Execute make with :make

Here’s the output I get.

Now, if you have errors it should show in the quick fix list as depicted below (Use :copen to open the quick fix list)

Now navigate and fix with :cn and :cp. Cheers!

No power of operation in Java

Just found out that the usual power of (^) operation is not available in Java.

This wasted an hour of my time. So for anyone else who’s about to try, please use Math.pow instead of this operator. And no, it doesn’t give a compilation error either.
Instead of : 2 ^ 3, use Math.pow(2, 3).. tada, how convenient, NOT!