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@7a3c5643f6
This commit is contained in:
parent
852529bf53
commit
e8119ec933
|
@ -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<count;j++) {
|
||||||
|
rid = SID[11 + (j*4)] & 0xFF;
|
||||||
|
for (int k=1;k<4;k++) {
|
||||||
|
rid <<= 8;
|
||||||
|
rid += SID[11-k + (j*4)] & 0xFF;
|
||||||
|
}
|
||||||
|
strSID = strSID + "-" + Long.toString(rid);
|
||||||
|
}
|
||||||
|
return strSID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue