Clean up and add unit tests for AdEntity.java
Future submissions will similary improve AdAdaptor.java.
diff --git a/src/com/google/enterprise/adaptor/ad/AdEntity.java b/src/com/google/enterprise/adaptor/ad/AdEntity.java
index 3697849..143ed9a 100644
--- a/src/com/google/enterprise/adaptor/ad/AdEntity.java
+++ b/src/com/google/enterprise/adaptor/ad/AdEntity.java
@@ -1,10 +1,9 @@
package com.google.enterprise.adaptor.ad;
-import java.util.logging.Logger;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
@@ -12,6 +11,7 @@
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchResult;
+/** Representation of a single user or group from Active Directory. */
public class AdEntity {
private static final Logger log =
Logger.getLogger(AdEntity.class.getName());
@@ -26,6 +26,8 @@
private long uSNChanged;
private boolean wellKnown;
private boolean allMembershipsRetrieved;
+ private final Pattern attrMemberPattern =
+ Pattern.compile("member;range=[0-9]+-.*", Pattern.CASE_INSENSITIVE);
private Object getAttribute(Attributes attributes, String name)
throws NamingException {
@@ -39,7 +41,7 @@
private Attribute getMemberAttr(Attributes attrs) throws NamingException {
allMembershipsRetrieved = true;
- Attribute member = attrs.get(AdConstants.ATTR_MEMBER);
+ Attribute member = attrs.get("member");
if (member != null && member.size() != 0) {
return member;
}
@@ -47,7 +49,7 @@
NamingEnumeration<String> ids = attrs.getIDs();
while (ids.hasMore()) {
String id = ids.next();
- if (AdConstants.ATTR_MEMBER_PATTERN.matcher(id).matches()) {
+ if (attrMemberPattern.matcher(id).matches()) {
allMembershipsRetrieved = id.endsWith("*");
return attrs.get(id);
}
@@ -66,18 +68,15 @@
dn = searchResult.getNameInNamespace();
wellKnown = false;
Attributes attrs = searchResult.getAttributes();
- sAMAccountName =
- (String) getAttribute(attrs, AdConstants.ATTR_SAMACCOUNTNAME);
- objectGUID =
- getTextGuid((byte[]) getAttribute(attrs, AdConstants.ATTR_OBJECTGUID));
- sid = getTextSid((byte[]) getAttribute(attrs, AdConstants.ATTR_OBJECTSID));
- String s = (String) getAttribute(attrs, AdConstants.ATTR_USNCHANGED);
+ sAMAccountName = (String) getAttribute(attrs, "sAMAccountName");
+ objectGUID = getTextGuid((byte[]) getAttribute(attrs, "objectGUID;binary"));
+ sid = getTextSid((byte[]) getAttribute(attrs, "objectSid;binary"));
+ String s = (String) getAttribute(attrs, "uSNChanged");
if (s != null) {
uSNChanged = Long.parseLong(s);
}
- primaryGroupId =
- (String) getAttribute(attrs, AdConstants.ATTR_PRIMARYGROUPID);
- userPrincipalName = (String) getAttribute(attrs, AdConstants.ATTR_UPN);
+ primaryGroupId = (String) getAttribute(attrs, "primaryGroupId");
+ userPrincipalName = (String) getAttribute(attrs, "userPrincipalName");
members = new HashSet<String>();
if (isGroup()) {
@@ -106,19 +105,19 @@
}
/**
- * Appends additional memberships from search result
+ * Appends additional memberships from search result
* @param searchResult which contains additional groups
* @return number of groups found
* @throws NamingException
*/
public int appendGroups(SearchResult searchResult)
throws NamingException {
- Attribute member = getMemberAttr(searchResult.getAttributes());
+ Attribute member = getMemberAttr(searchResult.getAttributes());
if (member != null) {
for (int i = 0; i < member.size(); ++i) {
members.add(member.get(i).toString());
}
- return member.size();
+ return member.size();
} else {
return 0;
}
@@ -133,17 +132,14 @@
public String getCommonName() {
// LDAP queries return escaped commas to avoid ambiguity, find first not
// escaped comma
- int comma = dn.indexOf(AdConstants.COMMA);
- while (comma > 0 && comma < dn.length()
- && (dn.charAt(comma - 1) == AdConstants.BACKSLASH_CHAR)) {
- comma = dn.indexOf(AdConstants.COMMA, comma + 1);
+ int comma = dn.indexOf(",");
+ while (comma > 0 && comma < dn.length() - 1 &&
+ (dn.charAt(comma - 1) == '\\')) {
+ comma = dn.indexOf(",", comma + 1);
}
String tmpGroupName = dn.substring(0, comma > 0 ? comma : dn.length());
- tmpGroupName =
- tmpGroupName.substring(
- tmpGroupName.indexOf(AdConstants.EQUALS_CHAR) + 1);
- tmpGroupName =
- tmpGroupName.replace(AdConstants.BACKSLASH, AdConstants.EMPTY);
+ tmpGroupName = tmpGroupName.substring(tmpGroupName.indexOf('=') + 1);
+ tmpGroupName = tmpGroupName.replace("\\", "");
return tmpGroupName;
}
@@ -158,7 +154,7 @@
if (objectSid == null) {
return null;
}
- StringBuilder strSID = new StringBuilder(AdConstants.SID_START);
+ StringBuilder strSID = new StringBuilder("S-");
long version = objectSid[0];
strSID.append(Long.toString(version));
long authority = objectSid[4];
@@ -167,7 +163,7 @@
authority <<= 8;
authority += objectSid[4 + i] & 0xFF;
}
- strSID.append(AdConstants.HYPHEN_CHAR).append(Long.toString(authority));
+ strSID.append('-').append(Long.toString(authority));
long count = objectSid[2];
count <<= 8;
count += objectSid[1] & 0xFF;
@@ -179,34 +175,12 @@
rid <<= 8;
rid += objectSid[11 - k + (j * 4)] & 0xFF;
}
- strSID.append(AdConstants.HYPHEN_CHAR).append(Long.toString(rid));
+ strSID.append('-').append(Long.toString(rid));
}
return strSID.toString();
}
/**
- * Generate properties to be used for parameter binding in JDBC
- * @return map of names and properties of current object
- */
- public Map<String, Object> getSqlParams() {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put(AdConstants.DB_DN, dn);
- map.put(AdConstants.DB_SAMACCOUNTNAME, sAMAccountName.toLowerCase());
- map.put(AdConstants.DB_UPN, userPrincipalName);
- map.put(AdConstants.DB_PRIMARYGROUPID, primaryGroupId);
- if (sid != null) {
- map.put(AdConstants.DB_DOMAINSID,
- sid.substring(0, sid.lastIndexOf(AdConstants.HYPHEN_CHAR)));
- map.put(AdConstants.DB_RID,
- sid.substring(sid.lastIndexOf(AdConstants.HYPHEN_CHAR) + 1));
- }
- map.put(AdConstants.DB_OBJECTGUID, objectGUID);
- map.put(AdConstants.DB_USNCHANGED, uSNChanged);
- map.put(AdConstants.DB_WELLKNOWN, wellKnown ? 1 : 0);
- return map;
- }
-
- /**
* Parses the binary GUID retrieved from LDAP and converts to textual
* representation. Text version is used to avoid dealing with different
* BLOB types between databases.
@@ -214,7 +188,7 @@
* @return string containing the GUID
*/
public static String getTextGuid(byte[] binaryGuid) {
- StringBuilder sb = new StringBuilder(AdConstants.GUID_START);
+ StringBuilder sb = new StringBuilder("0x");
for (byte b : binaryGuid) {
sb.append(Integer.toHexString(b & 0xFF));
}
@@ -253,7 +227,7 @@
public boolean isGroup() {
return primaryGroupId == null;
}
-
+
public boolean isWellKnown() {
return wellKnown;
}
@@ -270,7 +244,7 @@
}
public String getPrimaryGroupSid() {
- int index = sid.lastIndexOf(AdConstants.HYPHEN_CHAR) + 1;
+ int index = sid.lastIndexOf('-') + 1;
return sid.substring(0, index) + primaryGroupId;
}
diff --git a/test/com/google/enterprise/adaptor/ad/AdEntityTest.java b/test/com/google/enterprise/adaptor/ad/AdEntityTest.java
new file mode 100644
index 0000000..cfca6d4
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/ad/AdEntityTest.java
@@ -0,0 +1,132 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.ad;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import java.util.*;
+
+import javax.naming.directory.*;
+
+/** Test cases for {@link AdEntity}. */
+public class AdEntityTest {
+ @Test
+ public void testStandardConstructor() throws Exception {
+ Attributes attrs = new BasicAttributes();
+ attrs.put("objectGUID;binary",
+ AdServerTest.hexStringToByteArray("000102030405060708090a0b0c"));
+ attrs.put("objectSid;binary", // S-1-0-0
+ AdServerTest.hexStringToByteArray("010100000000000000000000"));
+ attrs.put("uSNChanged", "12345678");
+ attrs.put("primaryGroupId", "users");
+
+ SearchResult sr = new SearchResult("SR name", attrs, attrs);
+ sr.setNameInNamespace("cn=user,ou=Users,dc=example,dc=com");
+ AdEntity adEntity = new AdEntity(sr);
+ assertEquals("user", adEntity.getCommonName());
+ assertEquals("S-1-0-0", adEntity.getSid());
+ assertEquals("cn=user,ou=Users,dc=example,dc=com", adEntity.getDn());
+ assertFalse(adEntity.isWellKnown());
+ assertEquals(0, adEntity.getMembers().size());
+ assertEquals("S-1-0-users", adEntity.getPrimaryGroupSid());
+ }
+
+ @Test
+ public void testWellKnownConstructor() throws Exception {
+ AdEntity adEntity = new AdEntity("S-1-1-1",
+ "dn=escaped\\,cn=users,ou=Users,dc=example,dc=com");
+ assertEquals("escaped,cn=users", adEntity.getCommonName());
+ assertEquals("S-1-1-1", adEntity.getSid());
+ assertEquals("dn=escaped\\,cn=users,ou=Users,dc=example,dc=com",
+ adEntity.getDn());
+ assertTrue(adEntity.isWellKnown());
+ assertEquals(0, adEntity.getMembers().size());
+ }
+
+ @Test
+ public void testWellKnownConstructorNoCommaInDN() throws Exception {
+ AdEntity adEntity = new AdEntity("NoComma", "dc=com");
+ assertEquals("com", adEntity.getCommonName());
+ assertEquals("dc=com", adEntity.getDn());
+ assertTrue(adEntity.isWellKnown());
+ }
+
+ @Test
+ public void testWellKnownConstructorTrailingComma() throws Exception {
+ AdEntity adEntity = new AdEntity("NoComma", "dc=com,");
+ assertEquals("com", adEntity.getCommonName());
+ assertEquals("dc=com,", adEntity.getDn());
+ assertTrue(adEntity.isWellKnown());
+ }
+
+ @Test
+ public void testAppendGroupsOnEmptyGroup() throws Exception {
+ AdEntity adEntity = new AdEntity("parentGroup", "dc=com");
+
+ Attributes attrs = new BasicAttributes();
+ attrs.put("objectGUID;binary",
+ AdServerTest.hexStringToByteArray("000102030405060708090a0b0c"));
+ attrs.put("objectSid;binary", // S-1-0-0
+ AdServerTest.hexStringToByteArray("010100000000000000000000"));
+ attrs.put("member", null);
+ Attribute memberAttr = attrs.get("member");
+ memberAttr.clear();
+ SearchResult sr = new SearchResult("subgroup", attrs, attrs);
+ sr.setNameInNamespace("cn=subgroup,ou=Groups,dc=example,dc=com");
+ AdEntity ae = new AdEntity(sr);
+
+ HashSet<String> expectedMembers = new HashSet<String>();
+ assertEquals(expectedMembers, ae.getMembers());
+ assertEquals(0, adEntity.appendGroups(sr));
+ }
+
+ @Test
+ public void testAppendGroupsOnRealGroup() throws Exception {
+ AdEntity adEntity = new AdEntity("parentGroup", "dc=com");
+
+ Attributes attrs = new BasicAttributes();
+ attrs.put("objectGUID;binary",
+ AdServerTest.hexStringToByteArray("000102030405060708090a0b0c"));
+ attrs.put("objectSid;binary", // S-1-0-0
+ AdServerTest.hexStringToByteArray("010100000000000000000000"));
+ List<String> members = Arrays.asList("dn_for_user_1", "dn_for_user_2");
+ attrs.put("member", null);
+ Attribute memberAttr = attrs.get("member");
+ memberAttr.clear();
+ for (String member: members) {
+ memberAttr.add(member);
+ }
+
+ SearchResult sr = new SearchResult("subgroup", attrs, attrs);
+ sr.setNameInNamespace("cn=subgroup,ou=Groups,dc=example,dc=com");
+ AdEntity ae = new AdEntity(sr);
+
+ assertEquals(new HashSet<String>(members), ae.getMembers());
+ assertEquals(2, adEntity.appendGroups(sr));
+ }
+
+ @Test
+ public void testParseForeignSecurityPrincipal() throws Exception {
+ AdEntity adEntity = new AdEntity("NoComma", "dc=com");
+ assertNull(adEntity.parseForeignSecurityPrincipal(""));
+ assertNull(adEntity.parseForeignSecurityPrincipal(
+ "cn=foreignsecurityprincipals,dc=example,dc=com"));
+ String validSid = "S-1-5-21-42";
+ assertEquals(validSid, adEntity.parseForeignSecurityPrincipal(
+ "id=" + validSid + ",cn=foreignsecurityprincipals,dc=example,dc=com"));
+ }
+}