2

We are trying to setup Azkaban with LDAP authentication in our production environment. Any leads on how to do this? Documentation says it can be done by adding plugin jar file by extending UserManager class . I am a newbie to azkaban , looking for some example code for this

Harsha
  • 31
  • 4

2 Answers2

2

You will need to install a custom "user manager" plugin. It can be found on github: https://github.com/researchgate/azkaban-ldap-usermanager

The instructions on how to configure the user manager plugin can be found on the front page of the github repo.

In essence you will need to:

  1. Download and build the plugin
  2. Copy the .jar file that you built into the ./extlib directory of your Azkaban installation
  3. Edit azkaban.properties file, specifying user.manager.class and a number of user.manager.ldap properties.
CodeMonkey
  • 21
  • 1
1

We also wanted to setup an LDAP authentication in azkaban - but the open source project mentioned in first answer has very limited capabilities and doesn't allow to start TLS negotiation after the connection to LDAP server is established.

We have written a completely new java class to take care of the following scenarios:

  • Establish a LDAP connection unsecurely (on port 389)
  • Start TLS Response and TLS negotiate
  • And then athenticate the user credentials.

With this approach we also dont have to create a service user in LDAP only for azkaban.

Take a look in the sample code block

@Override
public User getUser(String username, String password) throws UserManagerException {
    if (username == null || username.trim().isEmpty()) {
        throw new UserManagerException("Username is empty.");
    } else if (password == null || password.trim().isEmpty()) {
        throw new UserManagerException("Password is empty.");
    }

    String email = null;
    String groups = null;
    StringBuilder url = new StringBuilder("ldap://").append(ldapHost).append(":").append(ldapPort);

    Hashtable<String, String> env = new Hashtable<String, String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, url.toString());

    try {
        // Create initial context
        LdapContext ctx = new InitialLdapContext(env, null);
        // Start TLS
        StartTlsResponse tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
        SSLSession sess = tls.negotiate();

        // Adding username and password to environment
        StringBuilder sb = new StringBuilder("uid=").append(username).append(",").append(ldapUserBase);
        ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
        ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, sb.toString());
        ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);

        // Search the user in a LDAP directory
        final LdapCtx x = (LdapCtx) ctx.lookup(sb.toString());

        // Lookup is successful - creating an Azkaban user
        User user = new User(username);

        // Searching LDAP directory to get email and group
        SearchControls ctls = new SearchControls();
        String[] attributes = { "cn", "memberOf", "mail" };
        ctls.setReturningAttributes(attributes);

        NamingEnumeration<?> answer = ctx.search(ldapUserBase, "(uid=" + username + ")", ctls);

        Boolean isAdmin = false;
        // Search user email and groups
        while (answer.hasMore()) {
            SearchResult rslt = (SearchResult) answer.next();
            Attributes attrs = rslt.getAttributes();
            groups = attrs.get("memberof").toString().split(":")[1].trim();
            if (attrs.get("memberof") != null && attrs.get("memberof").toString().split(":").length > 0) {
                groups = attrs.get("memberof").toString().split(":")[1].trim();
                for (String group : groups.split(",")) {
                    if (ldapAdminGroups.contains(group))
                        isAdmin = true;
                }
            }
            if (attrs.get("mail") != null) {
                email = attrs.get("mail").toString().split(":")[1].trim();
                user.setEmail(email);
            }
        }

        // Assign the correct role
        if (isAdmin)
            user.addRole("admin");
        else
            user.addRole("read");
        ctx.close();
        return user;
    } catch (NamingException e) {
        throw new UserManagerException("LDAP error: " + e.getMessage(), e);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        throw new UserManagerException("IO error", e);
    }
}

Note: I haven't done lot of exception handling in this - you need to do it as per your needs.

How to make it make it work in Azkaban:

  • Build a maven or gradle project.
  • No additional library is required (except Azkaban - i.e. com.linkedin.azkaban)
  • Have a new class which will inherit 'azkaban.user.UserManager'
  • Build and copy the jar in azkaban/extlibs
  • In azkaban.properties - set "user.manager.class=" and also all required properties like host, port and ldap userbase (ou=Users,dc=stackoverflow,dc=com) details.

And you should be good to authenticate users via LDAP.

Happy Coding !!

Thanks, Hussain Bohra

Hussain Bohra
  • 985
  • 9
  • 15