Word Hunter

Word Hunter

I’m pleased to announce that Word Hunter has been released to iOS, Android and Windows Phone. 🙂

It’s written 100% in web technologies and packaged via Apache Cordova.

Go take a look, I hope you have some fun with it:

The game is made by @danielsalvagni, Gabriel Biz and me (@evohunz).

Tip of the day. We did it while reading Getting Real and Rework. Incredibly how these books affected how we dealt with the development of this project. Changed my mind for sure.

By the way, my personal highscore is 935 points.

Active Directory Authentication in Java

Doing Active Directory authentication in Java can be a nightmare. Documentation is scarse and Java APIs are usually counter-intuitive.

I’ve spent a good time to get it right (or what I guess is right), and I hope that this code sample can help others. Just use it, code is under WTFPL license.

Summary to validate if a user is in a group:

  1. Java requires the user full DN to authenticate;
  2. Authenticate to LDAP using a master user;
  3. Search user DN;
  4. Reauthenticate using user DN;
  5. Fetch all groups of user;
  6. Check if the required group is in it.
package com.tnegri.sample;

import java.util.*;

import javax.naming.*;
import javax.naming.directory.*;

public final class ActiveDirectoryFacade {

    private static final MASTER_USER_DN;
    private static final MASTER_PASSWORD;

    static {
        // Sample configuration.
        MASTER_USER_DN = "CN=masteruser,OU=Users,DC=tnegri,DC=com";
        MASTER_PASSWORD = "m4sterP4ssw0rd";
    }

    private final String ldapUrl;
    private final String searchBase;

    /**
     * @param ldapUrl LDAP URL, e.g. "ldap://10.0.0.1:389"
     * @param searchBase Base for doing user search, 
     *                   e.g. "OU=Users,DC=tnegri,DC=com"
     */
    public ActiveDirectoryFacade(String ldapUrl, String searchBase) {
        this.ldapUrl = ldapUrl;
        this.searchBase = searchBase;
    }

    public boolean hasGroup(String username, String password, 
                            String groupObjectName) 
            throws NamingException {
        List<String> allGroups = getAllGroups(username, password);
        return allGroups.contains(groupObjectName);
    }

    private List<String> getAllGroups(String username, String password)
            throws NamingException {
        List<String> result = new ArrayList<>();

        String attributeToLookup = "memberOf";

        /*
         * 1. Authenticate using master user.
         */
        DirContext ctx = authenticate();

        /*
         * 2. Searches by "sAMAccountName" to recover the full
         *    DN of the username trying to login.
         */
        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        searchControls.setReturningAttributes(
                new String[] {"distinguishedName"});
        NamingEnumeration<SearchResult> searchResults = ctx.search(
                searchBase,
                String.format("(sAMAccountName=%s)", username),
                searchControls);
        if (!searchResults.hasMore()) {
            /*
             * If can't resolve DN, the user doesn't exists.
             */
            throw new NamingException();
        }
        SearchResult searchResult = searchResults.next();
        Attributes attributes = searchResult.getAttributes();
        Attribute attribute = attributes.get("distinguishedName");
        String userObject = (String) attribute.get();

        /*
         * 3. Authenticates to LDAP with the user, will throw if
         *    password is wrong.
         */
        ctx.close();
        ctx = authenticate(userObject, password);

        /*
         * 4. Fetch all groups of user.
         */
        attributes = ctx.getAttributes(userObject, 
                                       new String[] {attributeToLookup});

        NamingEnumeration<? extends Attribute> allAttributes =
                attributes.getAll();
        while (allAttributes.hasMoreElements()) {
            attribute = allAttributes.nextElement();
            int size = attribute.size();
            for (int i = 0; i < size; i++) {
                String attributeValue = (String) attribute.get(i);
                result.add(attributeValue);
            }
        }

        ctx.close();

        return result;
    }

    private DirContext authenticate() throws NamingException {
        return authenticate(null, null);
    }

    private DirContext authenticate(String username, String password)
            throws NamingException {
        String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
        String securityAuthentication = "simple";

        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
        env.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);
        env.put(Context.PROVIDER_URL, ldapUrl);
        env.put(Context.SECURITY_PRINCIPAL,
                username != null ? username : MASTER_USER_DN);
        env.put(Context.SECURITY_CREDENTIALS,
                password != null ? password : MASTER_PASSWORD);

        DirContext ctx = new InitialDirContext(env);

        return ctx;
    }
}

JavaScript, Assumption Inversion Principle and modularity

On past posts (1, 2) I tried to described what I call Assumption Inversion Principle. Well, talk is cheap, show me the code!

I’m trying to apply AIP on a personal project without infecting (much) the global namespace and going only with raw JavaScript to avoid unnecessary dependencies on things like RequireJS.

That’s the template I have come up with so far (gist):

/*
File...: foo.js
Exports: bar, baz
Depends: spam, eggs
*/
;(function (namespace) {
 'use strict'

 namespace.foo = function (namespace) {
   /* Dependencies */
   var spam = namespace.spam
   var eggs = namespace.eggs

   function bar () {
   }

   function baz () {
   }

   /* Exports */
   namespace.bar = bar
   namespace.baz = baz
 }
}((function () {
  if (typeof window === 'undefined') {
    return module.exports
  } else {
    return window
  }
}())))

The file can be used by the browser or as a NodeJS module. At the browser it will register an initialization function on “window” and as a NodeJS module it exports the initialization function.

How to use it? Just include every module and use each initialization function to populate your namespace:

/*
 * Namespace of our app.
 */
var myApp = {}

/* 
 * Initialize 'fooDeps' module
 * e.g. registers 'spam' and 'eggs' on namespace
 */
fooDeps(myApp)

/* 
 * Initialize 'foo' module
 * Uses 'spam' and 'eggs' and registers 'foo' and 'bar'
 */
foo(myApp)

And what do I gain with it? Well, I can treat modules as first-class citizens. Instead of bloating the code with objects and pretty patterns as singletons and factories, each module code knows how to initialize itself, so they are pretty straight forward. As they only use assumptions about their dependencies, the module code easy adapts to other environments. Classic example on single project: production code uses the real dependencies and test code uses mocks or simples objects. On multiple projects, the implementation of each dependency can be selected on whatever reason.

The particular project I’m working on is a Word Finder style game. We use a word dictionary and a random letter generator to populate the board. The random letter generator uses the ratio of frequency of each letter at the dictionary to select the random letters with the same ratio (gist):

;(function (namespace) {
  'use strict'

  namespace.randomlettergenerator = function (namespace) {
    var total = 0
    var lettersArray = []

    /*
     * Populates "lettersArray" and computes "total".
     */
    ;(function () {
      var letters = {}
      namespace.dictionaries.forEach(function (word) {
        var i, len, letter
        for (i = 0, len = word.length; i &lt; len; i++) {
          letter = word[i]
          if (typeof letters[letter] === 'undefined') {
            letters[letter] = { letter: letter, count: 1 }
            lettersArray.push(letters[letter])
          } else {
            letters[letter].count += 1
          }
          total += 1
        }
      })
    }())

    /*
     * Sorts by descending letter frequency
     */
    lettersArray.sort(function (a, b) {
      if (a.count > b.count) {
        return -1
      }
      if (a.count < b.count) {
        return 1
      }
      return 0
    })

    /**
     * Random letter generator.
     */
    function RandomLetterGenerator () {
      this.lastIx = -1
    }

    /**
     * Returns a random letter.
     *
     * @return Random letter.
     */
    RandomLetterGenerator.prototype.next = function () {
      var i = this.lastIx
      var len = lettersArray.length
      var count = Math.random() * total

      while (count > 0) {
        i++
        if (i >= len) {
          i = 0
        }
        count -= lettersArray[i].count
      }

      this.lastIx = i
      return lettersArray[i].letter
    }

    namespace.RandomLetterGenerator = RandomLetterGenerator
  }
}((function () {
  if (typeof window === 'undefined') {
    return module.exports
  } else {
    return window
  }
}())))

Notice the module initialization code, it is possible to mock out or use multiple dictionaries to initialize different namespaces with different versions of RandomLetterGenerator class. The same effect is possible using pure OO factory pattern.

Other modules are responsible for finding words and checking board properties. The dictionaries are always an assumption, so the code is easily testable, even without objectifying everything.

I’m currently feeling good with the code. Not sure how it will scale.

Impostor Syndrome

I like to know how to name psychological effects, and I just learned a new one: Impostor syndrome.

This one adds to two others I like: Dunning-Kruger effect and the Bystander effect.

The impostor syndrome is kind of funny, tough. If you recognize that you had passed by an episode of it, then you understand either that:

  1. You are a high-achiever, so you deserve it, so you are cured from the impostor syndrome; or
  2. You projected a false high-expectation from others towards yourself, so you are not a high-achiever, but noone was expecting that anyway; or
  3. You are a fraud.

The only way to figure it out is to really put you up the test. Too bad when you miss an opportunity to burn that feeling.

Priority of Constituencies

An awesome paragraph from W3C’s HTML Design Principles:

3.2. Priority of Constituencies

In case of conflict, consider users over authors over implementors over specifiers over theoretical purity. In other words costs or difficulties to the user should be given more weight than costs to authors; which in turn should be given more weight than costs to implementors; which should be given more weight than costs to authors of the spec itself, which should be given more weight than those proposing changes for theoretical reasons alone. Of course, it is preferred to make things better for multiple constituencies at once.

Book: Code Simplicity

I just read the book “Code Simplicity: The Fundamentals of Software“.

The author tries to build up a sciente of software development. There are about 90 pages that discuss important details of this engineering without touching a single line of code.

Among the issues cited by the author, the one that impressed me most was the formula for the cost of a change in software.

This formula, when applied to time, makes it clear that the future value plus the cost of maintenance of a change will have a much higher weight than the immediate cost and value. As time goes by, the effort put into maintaining a feature far outweighs the initial effort to code it. I’ll not go into too much detail, if you are curious: go read the book.

It was a very enjoyable read. I’m sad that I got into this book by chance, no one pointed it to me. I feel that I could have avoided a good amount of frustration that I had as a developer. The author’s ideas seems to fit with all the insights I had developing and maintaining code.

I leave here my statement for all who work in the software field: you need to read this book! Regardless of writing code or not, you will have a much better basis for making decisions that affect your product.

If you’ve read, leave your comments about what you think.