From e8119ec9336e7fc9522c1da0be6b690c98b86d73 Mon Sep 17 00:00:00 2001 From: c-a-m Date: Fri, 14 Nov 2014 15:43:14 -0700 Subject: [PATCH] LDAP: Changed AD group lookup to include nested groups This expands the ActiveDirectoryConnectionFactory to lookup nested groups, in a non standard way. Fixes https://github.com/elasticsearch/elasticsearch-shield/issues/286 Original commit: elastic/x-pack-elasticsearch@7a3c5643f61c20e534bfa6d82db7ce79b935f6a8 --- .../shield/authc/ldap/ADGroups.java | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/test/java/org/elasticsearch/shield/authc/ldap/ADGroups.java diff --git a/src/test/java/org/elasticsearch/shield/authc/ldap/ADGroups.java b/src/test/java/org/elasticsearch/shield/authc/ldap/ADGroups.java new file mode 100644 index 00000000000..fc3b3ba36e8 --- /dev/null +++ b/src/test/java/org/elasticsearch/shield/authc/ldap/ADGroups.java @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.shield.authc.ldap; + +import org.elasticsearch.common.settings.ImmutableSettings; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.naming.ldap.InitialLdapContext; +import javax.naming.ldap.LdapContext; +import java.io.File; +import java.net.URISyntaxException; +import java.util.Hashtable; + +public class ADGroups { + public static void main (String[] args) throws URISyntaxException { + LdapSslSocketFactory.init(ImmutableSettings.builder() + .put("shield.authc.ldap.truststore", new File(LdapConnectionTests.class.getResource("ldaptrust.jks").toURI())) + .build()); + + Hashtable env = new Hashtable(); + String adminName = "CN=Tony Stark,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; + String adminPassword = "NickFuryHeartsES"; + String ldapURL = "ldaps://ad.test.elasticsearch.com:636"; + //set security credentials, note using simple cleartext authentication + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, adminName); + env.put(Context.SECURITY_CREDENTIALS, adminPassword); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put("java.naming.ldap.factory.socket", LdapSslSocketFactory.class.getName()); + + //connect to my domain controller + env.put(Context.PROVIDER_URL, ldapURL); + //specify attributes to be returned in binary format + env.put("java.naming.ldap.attributes.binary", "tokenGroups"); + + + try { + //Create the initial directory context + LdapContext ctx = new InitialLdapContext(env,null); + + //Create the search controls + SearchControls userSearchCtls = new SearchControls(); + + //Specify the search scope + userSearchCtls.setSearchScope(SearchControls.OBJECT_SCOPE); + + //specify the LDAP search filter to find the user in question + String userSearchFilter = "(objectClass=user)"; + + //paceholder for an LDAP filter that will store SIDs of the groups the user belongs to + StringBuffer groupsSearchFilter = new StringBuffer(); + groupsSearchFilter.append("(|"); + + //Specify the Base for the search + String userSearchBase = "CN=Tony Stark,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; + + //Specify the attributes to return + String userReturnedAtts[] = { "tokenGroups", "CN" }; + userSearchCtls.setReturningAttributes(userReturnedAtts); + + //Search for objects using the filter + NamingEnumeration userAnswer = ctx.search(userSearchBase, userSearchFilter, userSearchCtls); + + //Loop through the search results + while (userAnswer.hasMoreElements()) { + + SearchResult sr = (SearchResult)userAnswer.next(); + Attributes attrs = sr.getAttributes(); + + if (attrs != null) { + try { + for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) { + Attribute attr = (Attribute)ae.next(); + for (NamingEnumeration e = attr.getAll();e.hasMore();) { + + byte[] sid = (byte[])e.next(); + groupsSearchFilter.append("(objectSid=" + binarySidToStringSid(sid) + ")"); + + } + groupsSearchFilter.append(")"); + } + + } + catch (NamingException e) { + System.err.println("Problem listing membership: " + e); + } + } + } + + + // Search for groups the user belongs to in order to get their names + //Create the search controls + SearchControls groupsSearchCtls = new SearchControls(); + + //Specify the search scope + groupsSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); + + //Specify the Base for the search + String groupsSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com"; + + //Specify the attributes to return + String groupsReturnedAtts[]={}; + groupsSearchCtls.setReturningAttributes(groupsReturnedAtts); + + //Search for objects using the filter + NamingEnumeration groupsAnswer = ctx.search(groupsSearchBase, groupsSearchFilter.toString(), groupsSearchCtls); + + //Loop through the search results + while (groupsAnswer.hasMoreElements()) { + SearchResult sr = (SearchResult)groupsAnswer.next(); + System.out.println(sr.getNameInNamespace()); + } + + ctx.close(); + + } + + catch (NamingException e) { + System.err.println("Problem searching directory: " + e); + } + } + + + public static final String binarySidToStringSid( byte[] SID ) { + + String strSID = ""; + + //convert the SID into string format + + long version; + long authority; + long count; + long rid; + + strSID = "S"; + version = SID[0]; + strSID = strSID + "-" + Long.toString(version); + authority = SID[4]; + + for (int i = 0;i<4;i++) { + authority <<= 8; + authority += SID[4+i] & 0xFF; + } + + strSID = strSID + "-" + Long.toString(authority); + count = SID[2]; + count <<= 8; + count += SID[1] & 0xFF; + for (int j=0;j