| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.authorization.dseecompat; |
| | | |
| | | import org.opends.server.DirectoryServerTestCase; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.TestErrorLogger; |
| | | import org.opends.server.types.LDIFImportConfig; |
| | | import org.opends.server.types.LDIFExportConfig; |
| | | import org.opends.server.tools.LDAPModify; |
| | | import org.opends.server.tools.LDIFModify; |
| | | import org.opends.server.tools.LDAPSearch; |
| | | import org.opends.server.tools.LDIFDiff; |
| | | import org.testng.annotations.Test; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.BeforeMethod; |
| | | import org.testng.annotations.BeforeClass; |
| | | import static org.testng.Assert.assertEquals; |
| | | import org.testng.Assert; |
| | | import static org.opends.server.util.ServerConstants.EOL; |
| | | import org.opends.server.util.LDIFReader; |
| | | import org.opends.server.util.LDIFWriter; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.StringReader; |
| | | import java.io.PrintStream; |
| | | import java.io.FileOutputStream; |
| | | import java.io.FileNotFoundException; |
| | | import java.util.List; |
| | | import java.util.ArrayList; |
| | | import java.util.Map; |
| | | import java.util.HashMap; |
| | | import java.util.Collections; |
| | | import java.util.Arrays; |
| | | import java.util.Calendar; |
| | | import java.util.Set; |
| | | import java.util.HashSet; |
| | | import java.util.Date; |
| | | import java.util.GregorianCalendar; |
| | | import java.util.regex.Pattern; |
| | | import java.text.SimpleDateFormat; |
| | | |
| | | /** |
| | | * These are more functional tests than unit tests. They go directly over |
| | | * LDAP for all of their operations. We use the builtin LDAPModify, |
| | | * LDAPSearch, etc. tools to do this, as well as the ones that can |
| | | * do similar operations directly on LDIF (e.g. LDIFDiff). This is |
| | | * probably the easiest way to test the code, and it makes it easy to test |
| | | * failures outside of the unit test by just running the ldif code |
| | | * directly. |
| | | * <br> |
| | | * Most of the complexity is in the DataProviders because they try to |
| | | * squeeze everything they can out of what we have. We've scaled some of this |
| | | * back to make the tests run a little bit faster. If the tests fail quietly, |
| | | * then there is likely a problem in a DataProvider (e.g. a RuntimeException). |
| | | * In this case, running with -Dorg.opends.test.suppressOutput=false should |
| | | * help to diagnose the problem. |
| | | * <br> |
| | | * Most of the redundancy and error-prone-ness has also been factored out. |
| | | * For instance, in general the code doesn't craft the ACIs directly; instead |
| | | * they are built by buildAciValue, so that we are less likely to screw up |
| | | * the syntax. |
| | | */ |
| | | public class AciTests extends DirectoryServerTestCase { |
| | | // TODO: test modify use cases |
| | | // TODO: test searches where we expect a subset of attributes and entries |
| | | // TODO: test compare |
| | | // TODO: test delete |
| | | // TODO: test more combinations of attributes |
| | | // TODO: test multiple permission bind rules in the same ACI |
| | | // TODO: test groupdn and roledn |
| | | // TODO: test more invalid filters. We should have at least one for each concept in the spec. |
| | | // TODO: test more with network addresses once this is working |
| | | // TODO: test ipv6 |
| | | // TODO: test stuff happening in parallel! |
| | | // TODO: test ACI evaluation on adding, replacing, and with other operations |
| | | // TODO: check bypass-acl and modify-acl |
| | | // TODO: should we check that we get an error message on failures? |
| | | // TODO: test that the target has to be a subordinate |
| | | // TODO: test aci's with funky spacing |
| | | // TODO: Test anonymous access, i.e. all vs anyone |
| | | // TODO: Test ldap:///parent |
| | | // TODO: Test userattr |
| | | |
| | | // Tests are disabled this way because a class-level @Test(enabled=false) |
| | | // doesn't appear to work and the aci code itself isn't checked in yet. |
| | | private static final boolean TESTS_ARE_DISABLED = true; |
| | | |
| | | |
| | | // This is used to lookup the day of the week from the calendar field. |
| | | // The calendar field is 1 based and starts with sun. We make [0] point |
| | | // to 'sat' instead of a bogus value since we need to be able to find the set of days without a |
| | | // specific day. It needs to be at the top since it's used by other |
| | | // static initialization. |
| | | private static final String[] DAYS_OF_WEEK = |
| | | {"sat", "sun", "mon", "tue", "wed", "thu", "fri", "sat"}; |
| | | |
| | | private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HHmm"); |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // USERS |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | private static final String DIR_MGR_DN = "cn=Directory Manager"; |
| | | private static final String DIR_MGR_PW = "password"; |
| | | |
| | | private static final String ADMIN_DN = "cn=aci admin,dc=example,dc=com"; |
| | | private static final String ADMIN_PW = "PASSWORD"; |
| | | private static final String ADMIN_DN_LDAP_URL = "ldap:///" + ADMIN_DN; |
| | | |
| | | private static final String USER_DN = "cn=some user,dc=example,dc=com"; |
| | | private static final String USER_PW = "userPass"; |
| | | |
| | | private static final String ANNONYMOUS_DN = "<<anonymous>>"; |
| | | private static final String ANNONYMOUS_PW = "<<no password>>"; |
| | | |
| | | private static final Map<String,String> DN_TO_PW; |
| | | static { |
| | | Map<String,String> dnToPw = new HashMap<String,String>(); |
| | | dnToPw.put(DIR_MGR_DN, DIR_MGR_PW); |
| | | dnToPw.put(ADMIN_DN, ADMIN_PW); |
| | | dnToPw.put(ANNONYMOUS_DN, ANNONYMOUS_PW); |
| | | DN_TO_PW = Collections.unmodifiableMap(dnToPw); |
| | | } |
| | | |
| | | private static final String OBJECTCLASS_STAR = "(objectclass=*)"; |
| | | |
| | | private static final String SCOPE_BASE = "base"; |
| | | private static final String SCOPE_ONE = "one"; |
| | | private static final String SCOPE_SUB = "sub"; |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | private static final String OU_BASE_DN = "ou=acitest,dc=example,dc=com"; |
| | | private static final String LDAP_URL_OU_BASE = "ldap:///" + OU_BASE_DN; |
| | | |
| | | private static final String OU_INNER_DN = "ou=inner," + OU_BASE_DN; |
| | | private static final String LDAP_URL_OU_INNER = "ldap:///" + OU_INNER_DN; |
| | | |
| | | private static final String OU_LEAF_DN = "ou=leaf," + OU_INNER_DN; |
| | | private static final String LDAP_URL_OU_LEAF = "ldap:///" + OU_LEAF_DN; |
| | | |
| | | private static final String LEVEL_1_USER_DN = "cn=level1 user," + OU_BASE_DN; |
| | | private static final String LEVEL_2_USER_DN = "cn=level2 user," + OU_INNER_DN; |
| | | private static final String LEVEL_3_USER_DN = "cn=level3 user," + OU_LEAF_DN; |
| | | |
| | | // We need to delete all of these between each test. This list needs to be |
| | | // bottom up so that it can be handed to LDAPDelete. |
| | | private static final String[] ALL_TEST_ENTRY_DNS_BOTTOM_UP = { |
| | | LEVEL_3_USER_DN, |
| | | LEVEL_2_USER_DN, |
| | | LEVEL_1_USER_DN, |
| | | OU_LEAF_DN, |
| | | OU_INNER_DN, |
| | | OU_BASE_DN, |
| | | ADMIN_DN, |
| | | USER_DN |
| | | }; |
| | | |
| | | private static final String BIND_RULE_USERDN_SELF = "userdn=\"ldap:///self\""; |
| | | private static final String BIND_RULE_USERDN_ALL = "userdn=\"ldap:///all\""; |
| | | private static final String BIND_RULE_USERDN_ADMIN = "userdn=\"ldap:///" + ADMIN_DN + "\""; |
| | | private static final String BIND_RULE_USERDN_ANYONE = "userdn=\"ldap:///anyone\""; |
| | | private static final String BIND_RULE_USERDN_PARENT = "userdn=\"ldap:///parent\""; |
| | | private static final String BIND_RULE_USERDN_CN_RDN = "userdn=\"ldap:///CN=*,dc=example,dc=com\""; |
| | | private static final String BIND_RULE_USERDN_NOT_UID_RDN = "userdn!=\"ldap:///uid=*,dc=example,dc=com\""; |
| | | private static final String BIND_RULE_USERDN_UID_OR_CN_RDN = "userdn=\"ldap:///uid=*,dc=example,dc=com || ldap:///cn=*,dc=example,dc=com\""; |
| | | private static final String BIND_RULE_USERDN_ALL_CN_ADMINS = "userdn=\"ldap:///dc=example,dc=com??sub?(cn=*admin*)\""; |
| | | private static final String BIND_RULE_USERDN_TOP_LEVEL_CN_ADMINS = "userdn=\"ldap:///dc=example,dc=com??one?(cn=*admin*)\""; // TODO: this might be invalid? |
| | | |
| | | private static final String BIND_RULE_IP_LOCALHOST = "ip=\"127.0.0.1\""; |
| | | private static final String BIND_RULE_IP_LOCALHOST_WITH_MASK = "ip=\"127.0.0.1+255.255.255.254\""; |
| | | private static final String BIND_RULE_IP_LOCALHOST_SUBNET = "ip=\"127.0.0.*\""; |
| | | private static final String BIND_RULE_IP_LOCALHOST_SUBNET_WITH_MASK = "ip=\"127.0.0.*+255.255.255.254\""; |
| | | private static final String BIND_RULE_IP_NOT_LOCALHOST = "ip!=\"127.0.0.1\""; |
| | | private static final String BIND_RULE_IP_MISC_AND_LOCALHOST = "ip=\"72.5.124.61,127.0.0.1\""; |
| | | private static final String BIND_RULE_IP_NOT_MISC_AND_LOCALHOST = "ip!=\"72.5.124.61,127.0.0.1\""; |
| | | private static final String BIND_RULE_DNS_LOCALHOST = "dns=\"localhost\""; |
| | | private static final String BIND_RULE_DNS_NOT_LOCALHOST = "dns!=\"localhost\""; |
| | | |
| | | private static final String BIND_RULE_THIS_HOUR = getTimeOfDayRuleNextHour(); |
| | | private static final String BIND_RULE_PREVIOUS_HOUR = getTimeOfDayRulePreviousHour(); |
| | | |
| | | private static final String BIND_RULE_AUTHMETHOD_SIMPLE = "authmethod=\"simple\""; |
| | | private static final String BIND_RULE_AUTHMETHOD_SSL = "authmethod=\"ssl\""; |
| | | private static final String BIND_RULE_AUTHMETHOD_SASL = "authmethod=\"sasl\""; |
| | | |
| | | // Admin, but not anonymous |
| | | private static final String BIND_RULE_USERDN_NOT_ADMIN = and(not(BIND_RULE_USERDN_ADMIN), BIND_RULE_AUTHMETHOD_SIMPLE); |
| | | |
| | | private static final String BIND_RULE_TODAY = "dayofweek=\"" + getThisDayOfWeek() + "\""; |
| | | private static final String BIND_RULE_TODAY_AND_TOMORROW = "dayofweek=\"" + getThisDayOfWeek() + "," + getTomorrowDayOfWeek() + "\""; |
| | | private static final String BIND_RULE_NOT_TODAY = "dayofweek=\"" + getNotThisDayOfWeek() + "\""; |
| | | |
| | | private static final String BIND_RULE_USERDN_ADMIN_AND_SSL = and(BIND_RULE_USERDN_ADMIN, BIND_RULE_AUTHMETHOD_SSL); |
| | | private static final String BIND_RULE_IP_NOT_LOCALHOST_OR_USERDN_ADMIN = or(BIND_RULE_IP_NOT_LOCALHOST, BIND_RULE_USERDN_ADMIN); |
| | | |
| | | private static final String BIND_RULE_ADMIN_AND_LOCALHOST_OR_SSL = and(BIND_RULE_USERDN_ADMIN, or(BIND_RULE_AUTHMETHOD_SSL, BIND_RULE_DNS_LOCALHOST)); |
| | | |
| | | |
| | | // This are made up |
| | | private static final String BIND_RULE_GROUPDN_1 = "groupdn=\"ldap:///cn=SomeGroup,dc=example,dc=com\""; |
| | | private static final String BIND_RULE_GROUPDN_2 = "groupdn=\"ldap:///cn=SomeGroup,dc=example,dc=com || ldap:///cn=SomeOtherGroup,dc=example,dc=com\""; |
| | | private static final String BIND_RULE_GROUPDN_3 = "groupdn=\"ldap:///cn=SomeGroup,dc=example,dc=com || ldap:///cn=SomeOtherGroup,dc=example,dc=com || ldap:///cn=SomeThirdGroup,dc=example,dc=com\""; |
| | | private static final String BIND_RULE_USERDN_FILTER = "userdn=\"ldap:///dc=example,dc=com??one?(|(ou=eng)(ou=acct))\""; |
| | | |
| | | private static final String BIND_RULE_INVALID_DAY = "dayofweek=\"sumday\""; |
| | | |
| | | private static final String BIND_RULE_ONLY_AT_NOON = "timeofday=\"1200\""; |
| | | private static final String BIND_RULE_NOT_AT_NOON = "timeofday!=\"1200\""; |
| | | private static final String BIND_RULE_AFTERNOON = "timeofday>\"1200\""; |
| | | private static final String BIND_RULE_NOON_AND_AFTER = "timeofday>=\"1200\""; |
| | | private static final String BIND_RULE_BEFORE_NOON = "timeofday<\"1200\""; |
| | | private static final String BIND_RULE_NOON_AND_BEFORE = "timeofday<=\"1200\""; |
| | | |
| | | private static final String SELF_MODIFY_ACI = "aci: (targetattr=\"*\")(version 3.0; acl \"self modify\";allow(all) userdn=\"userdn=\"ldap:///self\";)"; |
| | | |
| | | private static final String ALLOW_ALL_TO_ALL = |
| | | buildAciValue("name", "allow all", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String ALLOW_ALL_TO_ADMIN = |
| | | buildAciValue("name", "allow all to admin", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_ADMIN); |
| | | |
| | | private static final String ALLOW_ALL_TO_ANYONE = |
| | | buildAciValue("name", "allow all to anyone", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_ANYONE); |
| | | |
| | | private static final String ALLOW_SEARCH_TO_ADMIN = |
| | | buildAciValue("name", "allow search to admin", "targetattr", "*", "allow(search)", BIND_RULE_USERDN_ADMIN); |
| | | |
| | | private static final String DENY_ALL_TO_ALL = |
| | | buildAciValue("name", "deny all", "targetattr", "*", "deny(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_READ_TO_ALL = |
| | | buildAciValue("name", "deny read", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_SEARCH_TO_ALL = |
| | | buildAciValue("name", "deny search", "targetattr", "*", "deny(search)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String ALLOW_SEARCH_TO_ALL = |
| | | buildAciValue("name", "allow search", "targetattr", "*", "allow(search)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String ALLOW_READ_TO_ALL = |
| | | buildAciValue("name", "allow read", "targetattr", "*", "allow(read)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_ALL_TO_ADMIN = |
| | | buildAciValue("name", "deny to admin", "targetattr", "*", "deny(all)", BIND_RULE_USERDN_ADMIN); |
| | | |
| | | private static final String DENY_PERSON_OU_TO_ALL = |
| | | buildAciValue("name", "deny person, ou to all", "targetfilter", "(|(objectclass=person)(objectclass=*))", "deny(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_ALL_OU_INNER = |
| | | buildAciValue("name", "deny inner to all", "target", LDAP_URL_OU_INNER, "deny(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_ALL_REAL_ATTRS_VALUE = |
| | | buildAciValue("name", "deny all attrs but 'bogus'", "targetattr!=", "bogusAttr", "deny(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_READ_REAL_ATTRS_VALUE = |
| | | buildAciValue("name", "deny read attrs but 'bogus'", "targetattr!=", "bogusAttr", "deny(read)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES = |
| | | buildAciValue("name", "allow all to non ou person", "targetattr", "*", "targetfilter", "(!(|(objectclass=organizationalunit)(objectclass=person)))", "allow(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_ALT = |
| | | buildAciValue("name", "allow all to non ou person", "targetattr", "*", "targetfilter!=", "(|(objectclass=organizationalunit)(objectclass=person))", "allow(all)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String ALLOW_WRITE_DELETE_SEARCH_TO_ALL = |
| | | buildAciValue("name", "allow write, delete, and search,", "targetattr", "*", "allow(write, delete, search)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_WRITE_DELETE_READ_TO_ALL = |
| | | buildAciValue("name", "deny write delete read to all", "targetattr", "*", "deny(write, delete, read)", BIND_RULE_USERDN_ALL); |
| | | |
| | | private static final String DENY_READ_TO_CN_RDN_USERS = |
| | | buildAciValue("name", "deny read to cn rdn", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_CN_RDN); |
| | | |
| | | private static final String DENY_READ_TO_UID_OR_CN_RDN_USERS = |
| | | buildAciValue("name", "deny read to uid or cn rdn", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_UID_OR_CN_RDN); |
| | | |
| | | private static final String DENY_READ_TO_NON_UID_RDN_USERS = |
| | | buildAciValue("name", "deny read to non uid rdn users", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_NOT_UID_RDN); |
| | | |
| | | private static final String DENY_READ_TO_CN_ADMINS = |
| | | buildAciValue("name", "deny read to users with 'admin' in their cn", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_ALL_CN_ADMINS); |
| | | |
| | | private static final String ALLOW_SEARCH_TO_CN_ADMINS = |
| | | buildAciValue("name", "allow search to users with 'admin' in their cn", "targetattr", "*", "allow(search)", BIND_RULE_USERDN_ALL_CN_ADMINS); |
| | | |
| | | private static final String DENY_READ_TO_TOP_LEVEL_CN_ADMINS = |
| | | buildAciValue("name", "deny read to users with 'admin' in their cn", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_TOP_LEVEL_CN_ADMINS); |
| | | |
| | | private static final String DENY_ALL_TO_LOCALHOST = |
| | | buildAciValue("name", "deny all to localhost", "targetattr", "*", "deny(all)", BIND_RULE_IP_LOCALHOST); |
| | | |
| | | private static final String DENY_ALL_TO_LOCALHOST_WITH_MASK = |
| | | buildAciValue("name", "deny all to localhost with mask", "targetattr", "*", "deny(all)", BIND_RULE_IP_LOCALHOST_WITH_MASK); |
| | | |
| | | private static final String DENY_ALL_TO_LOCALHOST_SUBNET = |
| | | buildAciValue("name", "deny all to localhost subnet", "targetattr", "*", "deny(all)", BIND_RULE_IP_LOCALHOST_SUBNET); |
| | | |
| | | private static final String DENY_ALL_TO_LOCALHOST_SUBNET_WITH_MASK = |
| | | buildAciValue("name", "deny all to localhost subnet", "targetattr", "*", "deny(all)", BIND_RULE_IP_LOCALHOST_SUBNET_WITH_MASK); |
| | | |
| | | private static final String DENY_ALL_TO_MISC_AND_LOCALHOST = |
| | | buildAciValue("name", "deny all to misc and localhost", "targetattr", "*", "deny(all)", BIND_RULE_IP_MISC_AND_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_TO_NON_LOCALHOST = |
| | | buildAciValue("name", "allow all to non-localhost", "targetattr", "*", "allow(all)", BIND_RULE_IP_NOT_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_TO_NON_MISC_AND_LOCALHOST = |
| | | buildAciValue("name", "allow all to non misc and localhost", "targetattr", "*", "allow(all)", BIND_RULE_IP_NOT_MISC_AND_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_TO_NON_DNS_LOCALHOST = |
| | | buildAciValue("name", "allow all to non localhost", "targetattr", "*", "allow(all)", BIND_RULE_DNS_NOT_LOCALHOST); |
| | | |
| | | private static final String DENY_ALL_TO_DNS_LOCALHOST = |
| | | buildAciValue("name", "deny all to localhost", "targetattr", "*", "deny(all)", BIND_RULE_DNS_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_TO_SSL = |
| | | buildAciValue("name", "allow all to ssl", "targetattr", "*", "allow(all)", BIND_RULE_AUTHMETHOD_SSL); |
| | | |
| | | private static final String DENY_ALL_TO_SIMPLE = |
| | | buildAciValue("name", "deny all to simple", "targetattr", "*", "deny(all)", BIND_RULE_AUTHMETHOD_SIMPLE); |
| | | |
| | | private static final String ALLOW_ALL_TO_SIMPLE = |
| | | buildAciValue("name", "allow all to simple", "targetattr", "*", "allow(all)", BIND_RULE_AUTHMETHOD_SIMPLE); |
| | | |
| | | private static final String DENY_ALL_TODAY = |
| | | buildAciValue("name", "deny all today", "targetattr", "*", "deny(all)", BIND_RULE_TODAY); |
| | | |
| | | private static final String ALLOW_ALL_TODAY = |
| | | buildAciValue("name", "allow all today", "targetattr", "*", "allow(all)", BIND_RULE_TODAY); |
| | | |
| | | private static final String DENY_ALL_TODAY_AND_TOMORROW = |
| | | buildAciValue("name", "deny all today and tomorrow", "targetattr", "*", "deny(all)", BIND_RULE_TODAY_AND_TOMORROW); |
| | | |
| | | private static final String ALLOW_ALL_NOT_TODAY = |
| | | buildAciValue("name", "allow all not today", "targetattr", "*", "allow(all)", BIND_RULE_NOT_TODAY); |
| | | |
| | | private static final String DENY_ALL_THIS_HOUR = |
| | | buildAciValue("name", "deny this hour", "targetattr", "*", "deny(all)", BIND_RULE_THIS_HOUR); |
| | | |
| | | private static final String ALLOW_ALL_THIS_HOUR = |
| | | buildAciValue("name", "allow this hour", "targetattr", "*", "allow(all)", BIND_RULE_THIS_HOUR); |
| | | |
| | | private static final String ALLOW_ALL_PREVIOUS_HOUR = |
| | | buildAciValue("name", "allow previous hour", "targetattr", "*", "allow(all)", BIND_RULE_PREVIOUS_HOUR); |
| | | |
| | | private static final String ALLOW_ALL_ADMIN_AND_SSL = |
| | | buildAciValue("name", "allow if admin and ssl", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_ADMIN_AND_SSL); |
| | | |
| | | private static final String DENY_ALL_NOT_LOCALHOST_OR_ADMIN = |
| | | buildAciValue("name", "deny if not localhost or admin", "targetattr", "*", "deny(all)", BIND_RULE_IP_NOT_LOCALHOST_OR_USERDN_ADMIN); |
| | | |
| | | // This makes more sense as an allow all. |
| | | private static final String DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL = |
| | | buildAciValue("name", "deny if admin and localhost or ssl", "targetattr", "*", "deny(all)", BIND_RULE_ADMIN_AND_LOCALHOST_OR_SSL); |
| | | |
| | | private static final String ALLOW_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL = |
| | | buildAciValue("name", "allow if admin and localhost or ssl", "targetattr", "*", "allow(all)", BIND_RULE_ADMIN_AND_LOCALHOST_OR_SSL); |
| | | |
| | | private static final String ALLOW_ALL_NOT_ADMIN = |
| | | buildAciValue("name", "allow not admin", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_NOT_ADMIN); |
| | | |
| | | private static final String ALLOW_SEARCH_TO_LOCALHOST = |
| | | buildAciValue("name", "allow search to localhost", "targetattr", "*", "allow(search)", BIND_RULE_IP_LOCALHOST); |
| | | |
| | | private static final String ALLOW_SEARCH_REALATTRS_TO_LOCALHOST = |
| | | buildAciValue("name", "allow search to localhost", "targetattr!=", "bogusAttr", "allow(search)", BIND_RULE_IP_LOCALHOST); |
| | | |
| | | private static final String ALLOW_SEARCH_OUR_ATTRS_TO_ADMIN = |
| | | buildAciValue("name", "allow search to our attributes to admin", "targetattr", "objectclass||ou||cn||sn||givenname", "target", LDAP_URL_OU_INNER, "allow(search)", BIND_RULE_USERDN_ADMIN); |
| | | |
| | | private static final String ALLOW_SEARCH_TARGET_INNER_TO_LOCALHOST = |
| | | buildAciValue("name", "allow search inner to localhost", "targetattr", "*", "target", LDAP_URL_OU_INNER, "allow(search)", BIND_RULE_IP_LOCALHOST); |
| | | |
| | | private static final String ALLOW_SEARCH_OU_AND_PERSON_TO_SIMPLE = |
| | | buildAciValue("name", "allow search ou and person to localhost", "targetattr", "*", "targetfilter", "(|(objectclass=organizationalunit)(objectclass=person))", "allow(search)", BIND_RULE_AUTHMETHOD_SIMPLE); |
| | | |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // ----------------------------------------------------------------------------- |
| | | // |
| | | // S E T U P |
| | | // |
| | | // ----------------------------------------------------------------------------- |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | |
| | | @BeforeClass |
| | | public void setupClass() throws Exception { |
| | | TestCaseUtils.startServer(); |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | } |
| | | |
| | | @BeforeMethod |
| | | public void clearBackend() throws Exception { |
| | | deleteAllTestEntries(); |
| | | } |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // ----------------------------------------------------------------------------- |
| | | // |
| | | // T E S T S |
| | | // |
| | | // ----------------------------------------------------------------------------- |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // VALID AND INVALID ACIS |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | private static final String ADMIN_LDIF_VALIDITY_TESTS = TestCaseUtils.makeLdif( |
| | | "dn: " + ADMIN_DN, |
| | | "objectclass: person", |
| | | "cn: aci admin", |
| | | "sn: admin", |
| | | "userpassword: " + ADMIN_PW, |
| | | "ds-privilege-name: modify-acl" ); |
| | | |
| | | // By default aci admin can do anything! |
| | | private static final String OU_LDIF_VALDITY_TESTS = TestCaseUtils.makeLdif( |
| | | "dn: " + OU_BASE_DN, |
| | | "objectclass: organizationalunit", |
| | | "ou: acitest", |
| | | "aci: (targetattr=\"*\")(version 3.0; acl \"test\";allow(all) userdn=\"" + ADMIN_DN_LDAP_URL + "\";)" |
| | | ); |
| | | |
| | | private static final String VALIDITY_TESTS_DIT = ADMIN_LDIF_VALIDITY_TESTS + OU_LDIF_VALDITY_TESTS; |
| | | |
| | | |
| | | private static final String[] VALID_ACIS = { |
| | | // Test each feature in isolation. |
| | | // <PASSES> |
| | | // // TARGETS |
| | | buildAciValue("name", "self mod", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ target", "target", LDAP_URL_OU_INNER, "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ 1 targetattr", "targetattr", "cn", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ 2 targetattr", "targetattr", "cn || sn", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ 3 targetattr", "targetattr", "cn || sn || uid", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ * targetattr", "targetattr", "*", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ non-existing attr", "targetattr", "notanattr", "allow (write)", BIND_RULE_USERDN_SELF), // DS 5.2p4 accepts this so we should too. |
| | | buildAciValue("name", "w/ non-existing attr", "targetattr", "cn || notanattr", "allow (write)", BIND_RULE_USERDN_SELF), // DS 5.2p4 accepts this so we should too. |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(sn=admin)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(objectclass=*)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(objectclass=inetorgperson)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(cn;lang-en=Jonathan Smith)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(cn=\\4Aohn*)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(title~=tattoos)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(labeledUri=http://opends.org/john)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(cn>=J)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(2.5.4.4=Smith)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter", "(sn:caseExactMatch:=Smith)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetScope", "targetScope", "base", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetScope", "targetScope", "onelevel", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetScope", "targetScope", "subtree", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ !target", "target!=", LDAP_URL_OU_INNER, "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ 1 !targetattr", "targetattr!=", "cn", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ 2 !targetattr", "targetattr!=", "cn || sn", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "w/ targetfilter", "targetfilter!=", "(sn=admin)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | // </PASSES> |
| | | |
| | | // <FAILS> |
| | | // These aren't supported yet. We should open an issue. |
| | | // buildAciValue("name", "w/ targetattrfilters", "targetattrfilters", "add=cn:(!(cn=superAdmin))", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | // buildAciValue("name", "w/ targetattrfilters", "targetattrfilters", "add=cn:(!(cn=superAdmin)) && telephoneNumber:(telephoneNumber=123*)", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | // </FAILS> |
| | | |
| | | // <PASSES> |
| | | buildAciValue("name", "read", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "write", "targetattr", "*", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "add", "targetattr", "*", "allow (add)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "delete", "targetattr", "*", "allow (delete)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "search", "targetattr", "*", "allow (search)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "compare", "targetattr", "*", "allow (compare)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "selfwrite", "targetattr", "*", "allow (selfwrite)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "all", "targetattr", "*", "allow (all)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "proxy", "targetattr", "*", "allow (proxy)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read|write", "targetattr", "*", "allow (read, write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read|write", "targetattr", "*", "allow (read, write, add)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read|write", "targetattr", "*", "allow (read, write, add, delete, search, compare, selfwrite, all, proxy)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read", "targetattr", "*", "deny (read)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "write", "targetattr", "*", "deny (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "add", "targetattr", "*", "deny (add)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "delete", "targetattr", "*", "deny (delete)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "search", "targetattr", "*", "deny (search)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "compare", "targetattr", "*", "deny (compare)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "selfwrite", "targetattr", "*", "deny (selfwrite)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "all", "targetattr", "*", "deny (all)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "proxy", "targetattr", "*", "deny (proxy)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read|write", "targetattr", "*", "deny (read, write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read|write|add", "targetattr", "*", "deny (read, write, add)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "all", "targetattr", "*", "deny (read, write, add, delete, search, compare, selfwrite, all, proxy)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "read all", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_ALL), |
| | | buildAciValue("name", "read anyone", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_ANYONE), |
| | | buildAciValue("name", "read filter", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_FILTER), |
| | | buildAciValue("name", "read parent", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_PARENT), |
| | | // <FAIL> |
| | | // These aren't supported yet. We should open an issue. |
| | | // buildAciValue("name", "read group dn 1", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_1), |
| | | // buildAciValue("name", "read group dn 2", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_2), |
| | | // buildAciValue("name", "read group dn 3", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_3), |
| | | // </FAIL> |
| | | buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", "userattr=\"manager#USERDN\""), |
| | | buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", "userattr=\"ldap:///dc=example,dc=com?owner#USERDN\""), |
| | | buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", "userattr=\"cn#LDAPURL\""), |
| | | |
| | | // BUG! These work with DS 5.2p4, but not with OpenDS. |
| | | // <FAIL> |
| | | // DENY_ALL_TO_LOCALHOST_SUBNET, |
| | | // ALLOW_ALL_TO_NON_MISC_AND_LOCALHOST, |
| | | // DENY_ALL_TO_LOCALHOST_WITH_MASK, |
| | | // DENY_ALL_TO_LOCALHOST_SUBNET_WITH_MASK, |
| | | // </FAIL> |
| | | |
| | | ALLOW_ALL_TO_NON_DNS_LOCALHOST, |
| | | DENY_ALL_TO_DNS_LOCALHOST, |
| | | buildAciValue("name", "deny all to example.com", "targetattr", "*", "deny(all)", "dns=\"*.example.com\""), |
| | | ALLOW_ALL_TO_SSL, |
| | | DENY_ALL_TO_SIMPLE, |
| | | DENY_ALL_TODAY, |
| | | DENY_ALL_TODAY_AND_TOMORROW, |
| | | ALLOW_ALL_NOT_TODAY, |
| | | |
| | | buildAciValue("name", "allow at noon", "targetattr", "*", "allow(all)", BIND_RULE_ONLY_AT_NOON), |
| | | buildAciValue("name", "allow at non-noon", "targetattr", "*", "allow(all)", BIND_RULE_NOT_AT_NOON), |
| | | buildAciValue("name", "allow at afternoon", "targetattr", "*", "allow(all)", BIND_RULE_AFTERNOON), |
| | | buildAciValue("name", "allow at noon and after", "targetattr", "*", "allow(all)", BIND_RULE_NOON_AND_AFTER), |
| | | buildAciValue("name", "allow at before noon", "targetattr", "*", "allow(all)", BIND_RULE_BEFORE_NOON), |
| | | buildAciValue("name", "allow at noon and before", "targetattr", "*", "allow(all)", BIND_RULE_NOON_AND_BEFORE), |
| | | buildAciValue("name", "allow at next hour", "targetattr", "*", "allow(all)", BIND_RULE_THIS_HOUR), |
| | | buildAciValue("name", "allow at next hour", "targetattr", "*", "allow(all)", BIND_RULE_PREVIOUS_HOUR), |
| | | |
| | | ALLOW_ALL_ADMIN_AND_SSL, |
| | | DENY_ALL_NOT_LOCALHOST_OR_ADMIN, |
| | | DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL, |
| | | ALLOW_ALL_NOT_ADMIN |
| | | |
| | | |
| | | // <FAIL> |
| | | // These aren't supported yet. We should open an issue. |
| | | // buildAciValue("name", "userattr 1", "targetattr", "*", "allow (read)", "userattr=\"owner#GROUPDN\""), |
| | | // buildAciValue("name", "userattr 1", "targetattr", "*", "allow (read)", "userattr=\"ldap:///dc=example,dc=com?owner#GROUPDN\""), |
| | | // </FAIL> |
| | | // </PASSES> |
| | | // TODO: bind rules for 'ip', 'dns', 'dayofweek', 'timeofday', 'authmethod' |
| | | // TODO: combinations of these things, including multiple bind rules. |
| | | // TODO: need to test wild cards! |
| | | }; |
| | | |
| | | private static final String[] INVALID_ACIS = { |
| | | // Test each feature in isolation. |
| | | // <PASSES> |
| | | "aci: ", |
| | | buildAciValue("allow (write)", BIND_RULE_USERDN_SELF), // No name |
| | | buildAciValue("name", "invalid", "target", "ldap:///", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "target", "ldap:///not a DN", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "target", "ldap:///cn=", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "targetattr", "", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "targetattr", "not an attr", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "targetattr", "cn ||", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "targetattr", "not/an/attr", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | buildAciValue("name", "invalid", "targetattr", "cn", "allow (write)", BIND_RULE_INVALID_DAY), |
| | | |
| | | // <FAIL> |
| | | // Attributes can't have '_' right?, but DS 5.2p4 accepts this, so should we? |
| | | // buildAciValue("name", "invalid", "targetattr", "not_an_attr", "allow (write)", BIND_RULE_USERDN_SELF), |
| | | // </FAIL> |
| | | |
| | | // </PASSES> |
| | | }; |
| | | |
| | | // This is a little bit confusing. The first element of each array of two elements contains |
| | | // the aci that is valid but becomes invalid if any single character is removed. |
| | | // There has to be a lot of redundancy between the two arrays because of what |
| | | // it takes for an aci to be minimally valid, and hence we end up doing a lot of |
| | | // work twice. This takes time and also reports some identical failures. |
| | | // Therefore, we also provide a mask in the second element in the array |
| | | // But since the aci has \" characters that are single characters, taking up |
| | | // the space of two, we have to use another "two-column" character in the mask. |
| | | // By convention, a character is removed if the corresponding mask character |
| | | // is a - or a \" characer. X and \' imply that it was previously tested and |
| | | // does not need to be tested again. |
| | | private static final String[][] INVALID_ACIS_IF_ANY_CHAR_REMOVED = |
| | | { |
| | | // TODO: this generates some failures. |
| | | // {"(version3.0;acl\"\";deny(all)ip=\"1.1.1.1\";)", |
| | | // "---------------\"\"-------------\"-------\"--"}, |
| | | |
| | | // TODO: this generates some failures. |
| | | // {"(version3.0;acl\"\";allow(read,write,add,delete,search,compare,selfwrite,all,proxy)userdn=\"ldap:///self\";)", |
| | | // "XXXXXXXXXXXXXXX\'\'X----------------------------------------------------------------------\"-----XX-----\"XX"}, |
| | | |
| | | // TODO: this generates some failures. |
| | | // {"(version3.0;acl\"\";allow(read)userdn=\"ldap:///o=b\";)", |
| | | // "XXXXXXXXXXXXXXX\'\'XXXXXXX----XXXXXXXX\'XXXXXXX---\'XX"}, |
| | | |
| | | // TODO: this generates some failures. |
| | | // {"(version3.0;acl\"\";allow(read)userdn=\"ldap:///o=*,o=b\";)", |
| | | // "XXXXXXXXXXXXXXX\'\'XXXXXXXXXXXXXXXXXXX\'XXXXXXXX-------\'XX"}, |
| | | |
| | | // I don't know what's wrong with this one, but OpenDS thinks the unmodified filter is not valid. |
| | | // {"(version3.0;acl\"\";deny(all)ip=\"1.1.1.1+1.1.1.0\";)", |
| | | // "XXXXXXXXXXXXXXX\'\'XXXXXXXXXXXXX\"---------------\"XX"}, |
| | | |
| | | {"(version3.0;acl\"\";deny(all)dns=\"a\";)", |
| | | "XXXXXXXXXXXXXXX\'\'XXXXXXXXXX----\"-\"XX"}, |
| | | |
| | | {"(version3.0;acl\"\";deny(all)timeofday>\"2300\";)", |
| | | "XXXXXXXXXXXXXXX\'\'XXXXXXXXXX----------\"----\"XX"}, |
| | | |
| | | {"(version3.0;acl\"\";deny(all)authmethod=\"simple\";)", |
| | | "XXXXXXXXXXXXXXX\'\'XXXXXXXXXX-----------\"------\"XX"}, |
| | | |
| | | {"(version3.0;acl\"\";deny(all)not authmethod=\"simple\";)", |
| | | "XXXXXXXXXXXXXXX\'\'XXXXXXXXXX----XXXXXXXXXXX\'XXXXXX\'XX"}, |
| | | |
| | | {"(version3.0;acl\"\";deny(all)not authmethod=\"simple\"and not authmethod=\"ssl\";)", |
| | | "XXXXXXXXXXXXXXX\'\'XXXXXXXXXXXXXXXXXXXXXXXXX\'XXXXXX\'--------XXXXXXXXXXX\'XXX\'XX"}, |
| | | |
| | | {"(version3.0;acl\"\";deny(all)dayofweek=\"sun\";)", |
| | | "XXXXXXXXXXXXXXX\'\'XXXXXXXXXX----------\"---\"XX"}, |
| | | |
| | | {"(targetattr=\"*\")(version3.0;acl\"\";deny(all)dns=\"a\";)", |
| | | "------------\"-\"-XXXXXXXXXXXXXXX\'\'XXXXXXXXXXXXXX\'X\'XX"}, |
| | | |
| | | }; |
| | | |
| | | @DataProvider |
| | | public Object[][] validBasisOfValidityTests() throws Exception { |
| | | TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass. |
| | | |
| | | List<String> acis = new ArrayList<String>(); |
| | | for (String[] aciAndMask: INVALID_ACIS_IF_ANY_CHAR_REMOVED) { |
| | | acis.add("aci: " + aciAndMask[0]); |
| | | } |
| | | return buildAciValidationParams(acis, false /*test once per aci*/); |
| | | } |
| | | |
| | | // This makes sure that all of the acis in the INVALID_ACIS_IF_ANY_CHAR_REMOVED |
| | | // tests are valid acis. |
| | | @Test(dataProvider = "validBasisOfValidityTests") |
| | | public void testBasisOfInvalidityTestsAreValid(String modifierDn, String modifierPw, String aciModLdif) throws Throwable { |
| | | if (TESTS_ARE_DISABLED) { // This is a hack to make sure we can disable the tests. |
| | | return; |
| | | } |
| | | testValidAcisHelper(modifierDn, modifierPw, aciModLdif); |
| | | } |
| | | |
| | | @DataProvider |
| | | public Object[][] validAcis() throws Exception { |
| | | TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass. |
| | | |
| | | return buildAciValidationParams(Arrays.asList(VALID_ACIS), false /*test once per aci*/); |
| | | } |
| | | |
| | | @DataProvider |
| | | public Object[][] invalidAcis() throws Exception { |
| | | TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass. |
| | | |
| | | List<String> invalid = new ArrayList<String>(); |
| | | invalid.addAll(Arrays.asList(INVALID_ACIS)); |
| | | for (String[] aciAndMask: INVALID_ACIS_IF_ANY_CHAR_REMOVED) { |
| | | invalid.addAll(getAciMissingCharCombos(aciAndMask[0], aciAndMask[1])); |
| | | } |
| | | return buildAciValidationParams(invalid, false /*test once per aci*/); |
| | | } |
| | | |
| | | // We use this with acis that are crafted in such a way so that they are |
| | | // invalid if any character is removed. By convention, the character |
| | | // is only removed if the corresponding mask character is a - or \" |
| | | public List<String> getAciMissingCharCombos(String aci, String mask) { |
| | | List <String> acisMissingOneChar = new ArrayList<String>(); |
| | | for (int i = 0; i < aci.length(); i++) { |
| | | // Add this test only if the mask tells us we haven't seen it before. |
| | | // Also guard against ArrayIndexOutOfBoundsExceptions in case the |
| | | // mask isn't long enough. |
| | | if ((i < mask.length()) && |
| | | ((mask.charAt(i) == '-') || (mask.charAt(i) == '\"'))) { |
| | | acisMissingOneChar.add("aci: " + aci.substring(0, i) + aci.substring(i + 1, aci.length())); |
| | | } |
| | | } |
| | | return acisMissingOneChar; |
| | | } |
| | | |
| | | |
| | | |
| | | // Common between validAcis and invalidAcis |
| | | public Object[][] buildAciValidationParams(List<String> acis, boolean testMultipleCombos) { |
| | | List<String[]> paramsList = new ArrayList<String[]>(); |
| | | |
| | | for (String aci: acis) { |
| | | List<String> aciLdifs = new ArrayList<String>(); |
| | | |
| | | // aci set in Add |
| | | aciLdifs.add(TestCaseUtils.makeLdif( |
| | | "dn: " + OU_INNER_DN, |
| | | "changetype: add", |
| | | "objectclass: organizationalunit", |
| | | "ou: inner", |
| | | aci)); |
| | | |
| | | if (testMultipleCombos) { |
| | | String ouLdif = TestCaseUtils.makeLdif( |
| | | "dn: " + OU_INNER_DN, |
| | | "changetype: add", |
| | | "objectclass: organizationalunit", |
| | | "ou: inner"); |
| | | |
| | | // aci set in modify via add |
| | | aciLdifs.add(ouLdif + |
| | | TestCaseUtils.makeLdif( |
| | | "dn: " + OU_INNER_DN, |
| | | "changetype: modify", |
| | | "add: aci", |
| | | aci)); |
| | | |
| | | // aci set in modify via replace |
| | | aciLdifs.add(ouLdif + |
| | | TestCaseUtils.makeLdif( |
| | | "dn: " + OU_INNER_DN, |
| | | "changetype: modify", |
| | | "replace: aci", |
| | | aci)); |
| | | } |
| | | |
| | | // Test each one with a user where ACI's aren't enforced and one where they are. |
| | | // This is in particularly useful for invalid acis. |
| | | for (String aciLdif: aciLdifs) { |
| | | if (testMultipleCombos) { |
| | | paramsList.add(new String[]{DIR_MGR_DN, DIR_MGR_PW, aciLdif}); |
| | | } |
| | | paramsList.add(new String[]{ADMIN_DN, ADMIN_PW, aciLdif}); |
| | | } |
| | | } |
| | | |
| | | return (Object[][]) paramsList.toArray(new Object[][]{}); |
| | | } |
| | | |
| | | @Test(dataProvider = "validAcis") |
| | | public void testValidAcis(String modifierDn, String modifierPw, String aciModLdif) throws Throwable { |
| | | if (TESTS_ARE_DISABLED) { // This is a hack to make sure we can disable the tests. |
| | | return; |
| | | } |
| | | testValidAcisHelper(modifierDn, modifierPw, aciModLdif); |
| | | } |
| | | |
| | | public void testValidAcisHelper(String modifierDn, String modifierPw, String aciModLdif) throws Throwable { |
| | | try { |
| | | // Setup the basic DIT |
| | | addEntries(VALIDITY_TESTS_DIT, DIR_MGR_DN, DIR_MGR_PW); |
| | | |
| | | // Test that we can add entries with valid ACIs as well as set valid ACIs on a an entry |
| | | modEntries(aciModLdif, modifierDn, modifierPw); |
| | | } catch (Throwable e) { |
| | | System.err.println("Started with dit:\nldapmodify -a -D \"cn=Directory Manager\" -w etegrity -p 13324\n" + VALIDITY_TESTS_DIT + |
| | | "and as '" + modifierDn + "' failed to perform these modifications:\n" + |
| | | "ldapmodify -D \"" + modifierDn + "\" -w " + modifierPw + " -p 13324\n" + |
| | | aciModLdif); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | // I'd like to make this dependsOnMethods = {"testBasisOfInvalidityTestsAreValid(String,String,String)"} |
| | | // but I can't figure out how. |
| | | @Test(dataProvider = "invalidAcis") |
| | | public void testInvalidAcis(String modifierDn, String modifierPw, String aciModLdif) throws Throwable { |
| | | if (TESTS_ARE_DISABLED) { // This is a hack to make sure we can disable the tests. |
| | | return; |
| | | } |
| | | try { |
| | | // Setup the basic DIT |
| | | addEntries(VALIDITY_TESTS_DIT, DIR_MGR_DN, DIR_MGR_PW); |
| | | |
| | | // Test that we can add entries with valid ACIs as well as set valid ACIs on a an entry |
| | | modEntriesExpectFailure(aciModLdif, modifierDn, modifierPw); |
| | | } catch (Throwable e) { |
| | | System.err.println("Started with dit:\nldapmodify -a -D \"cn=Directory Manager\" -w etegrity -p 13324\n" + VALIDITY_TESTS_DIT + |
| | | "and as '" + modifierDn + "' successfully added an invalid aci:\n" + |
| | | "ldapmodify -D \"" + modifierDn + "\" -w " + modifierPw + " -p 13324\n" + |
| | | aciModLdif); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | @DataProvider |
| | | public Object[][] invalidAcisMultiCombos() throws Exception { |
| | | TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass. |
| | | |
| | | List<String> invalid = new ArrayList<String>(); |
| | | invalid.add(INVALID_ACIS[0]); |
| | | invalid.add(INVALID_ACIS[1]); |
| | | |
| | | return buildAciValidationParams(invalid, true /*test multiple combos*/); |
| | | } |
| | | |
| | | /** Runs invalidity checks as DirectoryManager and by setting them |
| | | * different ways. We don't check as many this way since the combinations |
| | | * get expensive, and if these detect any problem, then they will all probably be okay. */ |
| | | @Test(dataProvider = "invalidAcisMultiCombos") |
| | | public void testInvalidAcisXX(String modifierDn, String modifierPw, String aciModLdif) throws Throwable { |
| | | if (TESTS_ARE_DISABLED) { // This is a hack to make sure we can disable the tests. |
| | | return; |
| | | } |
| | | testInvalidAcis(modifierDn, modifierPw, aciModLdif); |
| | | } |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // SEARCHING |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | |
| | | private static final String BASE_OU_LDIF__SEARCH_TESTS = makeOuLdif(OU_BASE_DN, "acitest"); |
| | | private static final String INNER_OU_LDIF__SEARCH_TESTS = makeOuLdif(OU_INNER_DN, "inner"); |
| | | private static final String LEAF_OU_LDIF__SEARCH_TESTS = makeOuLdif(OU_LEAF_DN, "leaf"); |
| | | |
| | | private static final String ADMIN_LDIF__SEARCH_TESTS = makeUserLdif(ADMIN_DN, "aci", "admin", ADMIN_PW); |
| | | private static final String USER_LDIF__SEARCH_TESTS = makeUserLdif(USER_DN, "some", "user", USER_PW); |
| | | private static final String LEVEL_1_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_1_USER_DN, "level1", "user", "pa$$word"); |
| | | private static final String LEVEL_2_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_2_USER_DN, "level2", "user", "pa$$word"); |
| | | private static final String LEVEL_3_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_3_USER_DN, "level3", "user", "pa$$word"); |
| | | |
| | | // TODO: need some groups and nested groups here eventually. |
| | | |
| | | // ou=leaf,ou=inner,ou=acitest,dc=example,dc=com and everything under it |
| | | private static final String LEAF_OU_FULL_LDIF__SEARCH_TESTS = |
| | | LEAF_OU_LDIF__SEARCH_TESTS + |
| | | LEVEL_3_USER_LDIF__SEARCH_TESTS; |
| | | |
| | | // ou=inner,ou=acitest,dc=example,dc=com and everything under it |
| | | private static final String INNER_OU_FULL_LDIF__SEARCH_TESTS = |
| | | INNER_OU_LDIF__SEARCH_TESTS + |
| | | LEVEL_2_USER_LDIF__SEARCH_TESTS + |
| | | LEAF_OU_FULL_LDIF__SEARCH_TESTS; |
| | | |
| | | // ou=acitest,dc=example,dc=com and everything under it |
| | | private static final String BASE_OU_FULL_LDIF__SEARCH_TESTS = |
| | | BASE_OU_LDIF__SEARCH_TESTS + |
| | | LEVEL_1_USER_LDIF__SEARCH_TESTS + |
| | | INNER_OU_FULL_LDIF__SEARCH_TESTS; |
| | | |
| | | private static final String BASIC_LDIF__SEARCH_TESTS = |
| | | ADMIN_LDIF__SEARCH_TESTS + |
| | | USER_LDIF__SEARCH_TESTS + |
| | | BASE_OU_FULL_LDIF__SEARCH_TESTS; |
| | | |
| | | private static final String NO_ACIS_LDIF = ""; |
| | | |
| | | // ------------------------------------------------------------ |
| | | // THESE ALL WILL RETURN NO RESULTS FOR ADMINS AND ANONYMOUS |
| | | // ------------------------------------------------------------ |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_BASE_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_READ_BASE_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_READ_TO_ALL); |
| | | |
| | | private static final String ALLOW_READ_BASE_DENY_ALL_BASE_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_READ_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_READ_BASE_DENY_ALL_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_READ_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_READ_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_READ_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_SEARCH_BASE_DENY_ALL_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_SEARCH_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_ALL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ADMIN_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_ADMIN); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_OU_PERSON_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_PERSON_OU_TO_ALL); |
| | | |
| | | private static final String DENY_ADMIN_BASE_ALLOW_ALL_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_TO_ADMIN) + |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_ALL_TO_ALL); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_OU_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_OU_INNER); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_BASE_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_OU_INNER); |
| | | |
| | | private static final String ALL0W_SEARCH_BASE_DENY_READ_BASE_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_READ_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_OU_INNER); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_ALL_REAL_ATTRS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_READ_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_REAL_ATTRS_VALUE); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_REAL_ATTRS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_READ_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_READ_REAL_ATTRS_VALUE); |
| | | |
| | | private static final String ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_BASE_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES); |
| | | |
| | | private static final String ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_BASE_LDIF_ALT = |
| | | makeAddAciLdif(OU_BASE_DN, ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_ALT); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_WRITE_DELETE_READ_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_WRITE_DELETE_READ_TO_ALL); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_TO_CN_RDN_USERS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_READ_TO_CN_RDN_USERS); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_TO_UID_OR_CN_RDN_USERS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_READ_TO_UID_OR_CN_RDN_USERS); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_TO_NON_UID_RDN_USERS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_READ_TO_NON_UID_RDN_USERS); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_TO_CN_ADMINS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_READ_TO_CN_ADMINS); |
| | | |
| | | private static final String ALL0W_ALL_BASE_DENY_READ_TO_TOP_LEVEL_CN_ADMINS_INNER_LDIF = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_READ_TO_TOP_LEVEL_CN_ADMINS); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_TO_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_NON_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_NON_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_MISC_AND_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_TO_MISC_AND_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_NON_MISC_AND_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_NON_MISC_AND_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_MISC_AND_LOCALHOST_SUBNET = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_LOCALHOST_SUBNET); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST_WITH_MASK = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_LOCALHOST_WITH_MASK); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST_SUBNET_WITH_MASK = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_LOCALHOST_SUBNET_WITH_MASK); |
| | | |
| | | private static final String ALLOW_ALL_BASE_TO_NON_DNS_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_NON_DNS_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_BASE_TO_SSL_AUTH = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_SSL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_SIMPLE_AUTH = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TO_SIMPLE); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TODAY = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TODAY); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TODAY_AND_TOMORROW = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_TODAY_AND_TOMORROW); |
| | | |
| | | private static final String ALLOW_ALL_BASE_NOT_TODAY = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_NOT_TODAY); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_THIS_HOUR = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_INNER_DN, DENY_ALL_THIS_HOUR); |
| | | |
| | | private static final String ALLOW_ALL_BASE_PREVIOUS_HOUR = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_NOT_TODAY); |
| | | |
| | | private static final String ALLOW_ALL_BASE_ADMIN_AND_SSL = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_ADMIN_AND_SSL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_NOT_LOCALHOST_OR_ADMIN = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_NOT_LOCALHOST_OR_ADMIN); |
| | | |
| | | private static final String ALLOW_ALL_BASE_DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL) + |
| | | makeAddAciLdif(OU_BASE_DN, DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL); |
| | | |
| | | private static final String ALLOW_ALL_BASE_NOT_ADMIN = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_NOT_ADMIN); |
| | | |
| | | // ----------------------------------------------------------------- |
| | | // THESE ALL WILL RETURN EVERYTHING IN AT LEAST OU=INNER FOR ADMINS |
| | | // ----------------------------------------------------------------- |
| | | |
| | | private static final String ALLOW_ALL_BASE_TO_ADMIN = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ADMIN); |
| | | |
| | | private static final String ALLOW_ALL_BASE_TO_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_TO_LOCALHOST); |
| | | |
| | | private static final String ALLOW_ALL_BASE_TO_ANYONE = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ANYONE); |
| | | |
| | | private static final String ALLOW_ALL_BASE_TO_ALL = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_ALL); |
| | | |
| | | private static final String ALL0W_SEARCH_INNER_TO_ADMIN = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_SEARCH_TO_ADMIN); |
| | | |
| | | private static final String ALL0W_WRITE_DELETE_SEARCH_INNER_TO_ALL = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_WRITE_DELETE_SEARCH_TO_ALL); |
| | | |
| | | private static final String ALLOW_INNER_SEARCH_TO_CN_ADMINS = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_SEARCH_TO_CN_ADMINS); |
| | | |
| | | private static final String ALLOW_INNER_ALL_TO_SIMPLE = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_ALL_TO_SIMPLE); |
| | | |
| | | private static final String ALLOW_INNER_ALL_TODAY = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_ALL_TODAY); |
| | | |
| | | private static final String ALLOW_INNER_ALL_THIS_HOUR = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_ALL_THIS_HOUR); |
| | | |
| | | private static final String ALLOW_INNER_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL = |
| | | makeAddAciLdif(OU_INNER_DN, ALLOW_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL); |
| | | |
| | | private static final String ALLOW_INNER_SEARCH_FROM_BASE_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_TARGET_INNER_TO_LOCALHOST); |
| | | |
| | | private static final String ALLOW_BASE_SEARCH_REALATTRS_TO_LOCALHOST = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_REALATTRS_TO_LOCALHOST); |
| | | |
| | | private static final String ALLOW_BASE_SEARCH_OUR_ATTRS_TO_ADMIN = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_OUR_ATTRS_TO_ADMIN); |
| | | |
| | | private static final String ALLOW_BASE_SEARCH_OU_AND_PERSON_TO_SIMPLE = |
| | | makeAddAciLdif(OU_BASE_DN, ALLOW_SEARCH_OU_AND_PERSON_TO_SIMPLE); |
| | | |
| | | // ------------------------------------------------------------ |
| | | // |
| | | // ------------------------------------------------------------ |
| | | |
| | | private static final String NO_SEARCH_RESULTS = ""; |
| | | |
| | | |
| | | |
| | | // Potential dimensions |
| | | // * Who sets the ACIs to start with |
| | | // * Whether the entries were created with the ACIs or they were added later. LDIFModify would work here. |
| | | // |
| | | |
| | | private static List<SearchTestParams> SEARCH_TEST_PARAMS = new ArrayList<SearchTestParams>(); |
| | | private static SearchTestParams registerNewTestParams(String initialDitLdif, String... aciLdif) { |
| | | SearchTestParams testParams = new SearchTestParams(initialDitLdif, aciLdif); |
| | | SEARCH_TEST_PARAMS.add(testParams); |
| | | return testParams; |
| | | } |
| | | |
| | | |
| | | static { |
| | | SearchTestParams testParams; |
| | | |
| | | // |
| | | // ACIs that allow 'cn=Directory Manager' but deny the searches below to everyone else |
| | | // in some way. |
| | | // |
| | | testParams = registerNewTestParams(BASIC_LDIF__SEARCH_TESTS, |
| | | NO_ACIS_LDIF, |
| | | ALLOW_ALL_BASE_DENY_ALL_BASE_LDIF, |
| | | ALLOW_ALL_BASE_DENY_READ_BASE_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_CN_ADMINS_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_TOP_LEVEL_CN_ADMINS_INNER_LDIF, |
| | | ALLOW_ALL_BASE_NOT_ADMIN |
| | | ); |
| | | |
| | | testParams.addSingleSearch(DIR_MGR_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, INNER_OU_FULL_LDIF__SEARCH_TESTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | testParams.addSingleSearch(ANNONYMOUS_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | |
| | | testParams.addSingleSearch(DIR_MGR_DN, OU_LEAF_DN, OBJECTCLASS_STAR, SCOPE_SUB, LEAF_OU_FULL_LDIF__SEARCH_TESTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_LEAF_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | testParams.addSingleSearch(ANNONYMOUS_DN, OU_LEAF_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | |
| | | testParams.addSingleSearch(DIR_MGR_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, INNER_OU_FULL_LDIF__SEARCH_TESTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_ONE, NO_SEARCH_RESULTS); |
| | | testParams.addSingleSearch(ANNONYMOUS_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_ONE, NO_SEARCH_RESULTS); |
| | | |
| | | // ------------------------------------------------------------------------ |
| | | |
| | | // |
| | | // ACIs that allow 'cn=Directory Manager' but deny the searches below to everyone else |
| | | // in some way. |
| | | // |
| | | testParams = registerNewTestParams(BASIC_LDIF__SEARCH_TESTS, |
| | | // These ACIs are all equivalent for the single search test cases below |
| | | // (but most likely not equivalent in general). |
| | | NO_ACIS_LDIF, |
| | | ALLOW_ALL_BASE_DENY_ALL_BASE_LDIF, |
| | | ALLOW_ALL_BASE_DENY_READ_BASE_LDIF, |
| | | ALLOW_READ_BASE_DENY_ALL_BASE_LDIF, |
| | | ALLOW_ALL_BASE_DENY_ALL_INNER_LDIF, |
| | | ALLOW_READ_BASE_DENY_ALL_INNER_LDIF, |
| | | ALLOW_ALL_BASE_DENY_READ_INNER_LDIF, |
| | | ALLOW_SEARCH_BASE_DENY_ALL_INNER_LDIF, |
| | | ALLOW_ALL_BASE_DENY_SEARCH_INNER_LDIF, |
| | | ALLOW_ALL_BASE_DENY_ADMIN_INNER_LDIF, |
| | | ALLOW_ALL_BASE_DENY_OU_PERSON_INNER_LDIF, |
| | | DENY_ADMIN_BASE_ALLOW_ALL_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_OU_INNER_LDIF, |
| | | ALL0W_SEARCH_BASE_DENY_READ_BASE_LDIF, |
| | | ALL0W_ALL_BASE_DENY_ALL_REAL_ATTRS_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_REAL_ATTRS_INNER_LDIF, |
| | | ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_BASE_LDIF, |
| | | ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_BASE_LDIF_ALT, |
| | | ALL0W_ALL_BASE_DENY_WRITE_DELETE_READ_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_CN_RDN_USERS_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_UID_OR_CN_RDN_USERS_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_NON_UID_RDN_USERS_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_CN_ADMINS_INNER_LDIF, |
| | | ALL0W_ALL_BASE_DENY_READ_TO_TOP_LEVEL_CN_ADMINS_INNER_LDIF, |
| | | ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST, |
| | | ALLOW_ALL_NON_LOCALHOST, |
| | | ALLOW_ALL_BASE_DENY_ALL_TO_MISC_AND_LOCALHOST, |
| | | ALLOW_ALL_BASE_TO_NON_DNS_LOCALHOST, |
| | | ALLOW_ALL_BASE_TO_SSL_AUTH, |
| | | ALLOW_ALL_BASE_DENY_ALL_TO_SIMPLE_AUTH, |
| | | ALLOW_ALL_BASE_DENY_ALL_TODAY, |
| | | ALLOW_ALL_BASE_DENY_ALL_TODAY_AND_TOMORROW, |
| | | ALLOW_ALL_BASE_NOT_TODAY, |
| | | ALLOW_ALL_BASE_DENY_ALL_THIS_HOUR, |
| | | ALLOW_ALL_BASE_PREVIOUS_HOUR, |
| | | ALLOW_ALL_BASE_ADMIN_AND_SSL, |
| | | ALLOW_ALL_BASE_DENY_ALL_NOT_LOCALHOST_OR_ADMIN, |
| | | ALLOW_ALL_BASE_DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL, |
| | | ALLOW_ALL_BASE_NOT_ADMIN |
| | | // <FAIL> |
| | | // ALLOW_ALL_NON_MISC_AND_LOCALHOST, |
| | | // ALLOW_ALL_BASE_DENY_ALL_TO_MISC_AND_LOCALHOST_SUBNET, |
| | | // ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST_WITH_MASK |
| | | // ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST_SUBNET_WITH_MASK |
| | | // </FAIL> |
| | | ); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_ONE, NO_SEARCH_RESULTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_LEAF_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | testParams.addSingleSearch(ANNONYMOUS_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, NO_SEARCH_RESULTS); |
| | | |
| | | // ------------------------------------------------------------------------ |
| | | |
| | | // |
| | | // ACIs that allow cn=admin, but deny the searches below to anonymous |
| | | // in some way. |
| | | // |
| | | |
| | | testParams = registerNewTestParams(BASIC_LDIF__SEARCH_TESTS, |
| | | ALLOW_ALL_BASE_TO_ADMIN, |
| | | ALLOW_ALL_BASE_TO_LOCALHOST, |
| | | ALLOW_ALL_BASE_TO_ALL, |
| | | ALLOW_ALL_BASE_TO_ANYONE, |
| | | ALL0W_SEARCH_INNER_TO_ADMIN, |
| | | ALL0W_WRITE_DELETE_SEARCH_INNER_TO_ALL, |
| | | ALLOW_INNER_SEARCH_TO_CN_ADMINS, |
| | | ALLOW_INNER_ALL_TO_SIMPLE, |
| | | ALLOW_INNER_ALL_TODAY, |
| | | ALLOW_INNER_ALL_THIS_HOUR, |
| | | ALLOW_INNER_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL, |
| | | ALLOW_INNER_SEARCH_FROM_BASE_LOCALHOST, |
| | | ALLOW_BASE_SEARCH_REALATTRS_TO_LOCALHOST, |
| | | ALLOW_BASE_SEARCH_OUR_ATTRS_TO_ADMIN, |
| | | ALLOW_BASE_SEARCH_OU_AND_PERSON_TO_SIMPLE |
| | | ); |
| | | |
| | | testParams.addSingleSearch(ADMIN_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, INNER_OU_FULL_LDIF__SEARCH_TESTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_LEAF_DN, OBJECTCLASS_STAR, SCOPE_SUB, LEAF_OU_FULL_LDIF__SEARCH_TESTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_LEAF_DN, OBJECTCLASS_STAR, SCOPE_ONE, LEVEL_3_USER_LDIF__SEARCH_TESTS); |
| | | testParams.addSingleSearch(ADMIN_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_BASE, INNER_OU_LDIF__SEARCH_TESTS); |
| | | } |
| | | |
| | | |
| | | // TODO: add explicit attribute list support to this. |
| | | private static class SingleSearchParams { |
| | | private final String _bindDn; |
| | | private final String _bindPw; |
| | | private final String _searchBaseDn; |
| | | private final String _searchFilter; |
| | | private final String _searchScope; |
| | | private final String _expectedResultsLdif; |
| | | private final String _initialDitLdif; |
| | | private final String _aciLdif; |
| | | |
| | | public SingleSearchParams(String bindDn, String bindPw, String searchBaseDn, String searchFilter, String searchScope, String expectedResultsLdif, String initialDitLdif, String aciLdif) { |
| | | _bindDn = bindDn; |
| | | _bindPw = bindPw; |
| | | _searchBaseDn = searchBaseDn; |
| | | _searchFilter = searchFilter; |
| | | _searchScope = searchScope; |
| | | _expectedResultsLdif = expectedResultsLdif; |
| | | _initialDitLdif = initialDitLdif; |
| | | _aciLdif = aciLdif; |
| | | } |
| | | |
| | | public SingleSearchParams(SingleSearchParams that, String initialDitLdif, String aciLdif) { |
| | | _bindDn = that._bindDn; |
| | | _bindPw = that._bindPw; |
| | | _searchBaseDn = that._searchBaseDn; |
| | | _searchFilter = that._searchFilter; |
| | | _searchScope = that._searchScope; |
| | | _expectedResultsLdif = that._expectedResultsLdif; |
| | | _initialDitLdif = initialDitLdif; |
| | | _aciLdif = aciLdif; |
| | | } |
| | | |
| | | public SingleSearchParams clone(String initialDitLdif, String aciLdif) { |
| | | return new SingleSearchParams(this, initialDitLdif, aciLdif); |
| | | } |
| | | |
| | | public String[] getLdapSearchArgs() { |
| | | if (_bindDn.equals(ANNONYMOUS_DN)) { |
| | | return new String[]{ |
| | | "-h", "127.0.0.1", |
| | | "-p", getServerLdapPort(), |
| | | "-b", _searchBaseDn, |
| | | "-s", _searchScope, |
| | | _searchFilter}; |
| | | } else { |
| | | return new String[]{ |
| | | "-h", "127.0.0.1", |
| | | "-p", getServerLdapPort(), |
| | | "-D", _bindDn, |
| | | "-w", _bindPw, |
| | | "-b", _searchBaseDn, |
| | | "-s", _searchScope, |
| | | _searchFilter}; |
| | | } |
| | | } |
| | | |
| | | // This is primarily used for debug output on a failure. |
| | | public String getCombinedSearchArgs() { |
| | | return "-h 127.0.0.1" + |
| | | " -p " + getServerLdapPort() + |
| | | " -D " + _bindDn + |
| | | " -w " + _bindPw + |
| | | " -b " + _searchBaseDn + |
| | | " -s " + _searchScope + |
| | | " \"" + _searchFilter + "\""; |
| | | } |
| | | } |
| | | |
| | | private static class SearchTestParams { |
| | | private final String _initialDitLdif; |
| | | private final List<String> _equivalentAciLdifs; |
| | | private final List<SingleSearchParams> _searchTests = new ArrayList<SingleSearchParams>(); |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | public SearchTestParams(String initialDitLdif, String... equivalentAciLdifs) { |
| | | _initialDitLdif = initialDitLdif; |
| | | _equivalentAciLdifs = Arrays.asList(equivalentAciLdifs); |
| | | } |
| | | |
| | | private void addSingleSearch(String bindDn, String searchBaseDn, String searchFilter, String searchScope, String expectedResultsLdif) { |
| | | for (String equivalentAci: _equivalentAciLdifs) { |
| | | _searchTests.add(new SingleSearchParams(bindDn, DN_TO_PW.get(bindDn), searchBaseDn, searchFilter, searchScope, expectedResultsLdif, _initialDitLdif, equivalentAci)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | private List<SingleSearchParams> explodeTestParams() throws Exception { |
| | | List<SingleSearchParams> explodedTests = new ArrayList<SingleSearchParams>(); |
| | | |
| | | for (SingleSearchParams searchTest: _searchTests) { |
| | | // Add the search test as is. |
| | | explodedTests.add(searchTest); |
| | | |
| | | // And add it with the ACIs merged into the initial import |
| | | String ditWithAcis = applyChangesToLdif(searchTest._initialDitLdif, searchTest._aciLdif); |
| | | explodedTests.add(searchTest.clone(ditWithAcis, "")); |
| | | } |
| | | |
| | | return explodedTests; |
| | | } |
| | | |
| | | /** |
| | | * @return the LDIF result of applying changesLdif to changesLdif |
| | | */ |
| | | private String applyChangesToLdif(String baseLdif, String changesLdif) throws Exception { |
| | | LDIFReader baseReader = new LDIFReader(new LDIFImportConfig(new StringReader(baseLdif))); |
| | | LDIFReader changesReader = new LDIFReader(new LDIFImportConfig(new StringReader(changesLdif))); |
| | | |
| | | ByteArrayOutputStream updatedEntriesStream = new ByteArrayOutputStream(); |
| | | LDIFWriter ldifWriter = new LDIFWriter(new LDIFExportConfig(updatedEntriesStream)); |
| | | |
| | | List<String> errors = new ArrayList<String>(); |
| | | LDIFModify.modifyLDIF(baseReader, changesReader, ldifWriter, errors); |
| | | Assert.assertTrue(errors.isEmpty(), "Unexpected errors applying LDIF changes: " + errors); |
| | | ldifWriter.flush(); |
| | | |
| | | return updatedEntriesStream.toString(); |
| | | } |
| | | } |
| | | |
| | | @DataProvider |
| | | private Object[][] searchTestParams() throws Throwable { |
| | | TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass. |
| | | |
| | | try { |
| | | List<Object[]> allTestParams = new ArrayList<Object[]>(); |
| | | |
| | | for (SearchTestParams testParams: SEARCH_TEST_PARAMS) { |
| | | List<SingleSearchParams> explodedTests = testParams.explodeTestParams(); |
| | | for (SingleSearchParams singleTest: explodedTests) { |
| | | allTestParams.add(new Object[]{singleTest}); |
| | | } |
| | | } |
| | | |
| | | return (Object[][]) allTestParams.toArray(new Object[][]{}); |
| | | } catch (Throwable e) { |
| | | // We had some exceptions here and they were hard to track down |
| | | // because they get hidden behind an InvocationTargetException. |
| | | e.printStackTrace(); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | @Test(dataProvider = "searchTestParams") |
| | | public void testSearchWithAcis(SingleSearchParams params) throws Throwable { |
| | | if (TESTS_ARE_DISABLED) { // This is a hack to make sure we can disable the tests. |
| | | return; |
| | | } |
| | | String searchResults = "<search-not-issued>"; |
| | | String diffFromExpected = "<diff-not-calculated>"; |
| | | try { |
| | | // Modify the entries, and apply the LDIF |
| | | addEntries(params._initialDitLdif, DIR_MGR_DN, DIR_MGR_PW); |
| | | modEntries(params._aciLdif, DIR_MGR_DN, DIR_MGR_PW); |
| | | |
| | | // Now issue the search and see if we get what we expect. |
| | | searchResults = ldapSearch(params.getLdapSearchArgs()); |
| | | diffFromExpected = diffLdif(params._expectedResultsLdif, searchResults); |
| | | |
| | | // Ignoring whitespace the diff should be empty. |
| | | Assert.assertTrue(diffFromExpected.replaceAll("\\s", "").length() == 0); |
| | | } catch (Throwable e) { |
| | | System.err.println( |
| | | "Started with dit:\n" + |
| | | params._initialDitLdif + |
| | | ((params._aciLdif.length() == 0) ? |
| | | "" : ("And then applied the following acis on top of this:\n" + params._aciLdif)) + |
| | | "'ldapsearch " + params.getCombinedSearchArgs() + "' returned\n" + |
| | | searchResults + "\nInstead of:\n" + |
| | | params._expectedResultsLdif + |
| | | "The difference is:\n" + |
| | | diffFromExpected); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | |
| | | // ----------------------------------------------------------------------------- |
| | | // ----------------------------------------------------------------------------- |
| | | // |
| | | // U T I L I T I E S |
| | | // |
| | | // ----------------------------------------------------------------------------- |
| | | // ----------------------------------------------------------------------------- |
| | | |
| | | /** |
| | | * Build the value for the aci from the specified fields. |
| | | * |
| | | * This is a bit of a kludge, but it does help us from having nested "\"", |
| | | * and it does allow us to more easily generate combinations of acis. |
| | | */ |
| | | private static String buildAciValue(String... aciFields) { |
| | | StringBuilder aci = new StringBuilder("aci: "); |
| | | |
| | | // Go through target* first |
| | | for (int i = 0; i < aciFields.length - 1; i += 2) { |
| | | String aciField = aciFields[i]; |
| | | String aciValue = aciFields[i+1]; |
| | | |
| | | if (aciField.startsWith("target")) { |
| | | if (!aciField.endsWith("=")) { // We allow = or more importantly != to be included with the target |
| | | aciField += "="; |
| | | } |
| | | aci.append("(" + aciField + "\"" + aciValue + "\")" + EOL + " "); |
| | | } |
| | | } |
| | | |
| | | aci.append("(version 3.0;acl "); |
| | | |
| | | // Try to get the name |
| | | for (int i = 0; i < aciFields.length - 1; i += 2) { |
| | | String aciField = aciFields[i]; |
| | | String aciValue = aciFields[i+1]; |
| | | |
| | | if (aciField.equals("name")) { |
| | | aci.append("\"" + aciValue + "\""); |
| | | } |
| | | } |
| | | |
| | | aci.append("; "); |
| | | |
| | | // Anything else is permission and a bindRule |
| | | for (int i = 0; i < aciFields.length - 1; i += 2) { |
| | | String permission = aciFields[i]; |
| | | String bindRule = aciFields[i+1]; |
| | | |
| | | if (!permission.startsWith("target") && !permission.equals("name")) { |
| | | aci.append(EOL + " " + permission + " " + bindRule + ";"); |
| | | } |
| | | } |
| | | |
| | | aci.append(")"); |
| | | |
| | | return aci.toString(); |
| | | } |
| | | |
| | | private static String makeAddAciLdif(String dn, String aci) { |
| | | return TestCaseUtils.makeLdif( |
| | | "dn: " + dn, |
| | | "changetype: modify", |
| | | "add: aci", |
| | | aci); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | private void addEntries(String ldif, String bindDn, String bindPassword) throws Exception { |
| | | addEntries(ldif, bindDn, bindPassword, true); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | private void addEntries(String ldif, String bindDn, String bindPassword, boolean expectSuccess) throws Exception { |
| | | File tempFile = getTemporaryLdifFile(); |
| | | TestCaseUtils.writeFile(tempFile, ldif); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", getServerLdapPort(), |
| | | "-D", bindDn, |
| | | "-w", bindPassword, |
| | | "-a", |
| | | "-f", tempFile.getAbsolutePath() |
| | | }; |
| | | |
| | | ldapModify(args, expectSuccess); |
| | | } |
| | | |
| | | private void ldapModify(String[] args, boolean expectSuccess) throws Exception { |
| | | clearOutputStream(); |
| | | int retVal = LDAPModify.mainModify(args, false, getOutputStream(), getOutputStream()); |
| | | assertEquals((retVal == 0), expectSuccess, "Return value = " + retVal); |
| | | } |
| | | |
| | | private String ldapSearch(String[] args) throws Exception { |
| | | clearOutputStream(); |
| | | int retVal = LDAPSearch.mainSearch(args, false, getOutputStream(), getOutputStream()); |
| | | Assert.assertEquals(0, retVal, "Non-zero return code because, error: " + getOutputStreamContents()); |
| | | return getOutputStreamContents(); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | private void modEntries(String ldif, String bindDn, String bindPassword) throws Exception { |
| | | modEntries(ldif, bindDn, bindPassword, true); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | private void modEntriesExpectFailure(String ldif, String bindDn, String bindPassword) throws Exception { |
| | | modEntries(ldif, bindDn, bindPassword, false); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | private void modEntries(String ldif, String bindDn, String bindPassword, boolean expectSuccess) throws Exception { |
| | | File tempFile = getTemporaryLdifFile(); |
| | | TestCaseUtils.writeFile(tempFile, ldif); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", getServerLdapPort(), |
| | | "-D", bindDn, |
| | | "-w", bindPassword, |
| | | "-f", tempFile.getAbsolutePath() |
| | | }; |
| | | |
| | | ldapModify(args, expectSuccess); |
| | | } |
| | | |
| | | private void deleteAllTestEntries() throws Exception { |
| | | // TODO: make this actually do a search first! |
| | | StringBuilder ldif = new StringBuilder(); |
| | | for (String dn: ALL_TEST_ENTRY_DNS_BOTTOM_UP) { |
| | | ldif.append(TestCaseUtils.makeLdif( |
| | | "dn: " + dn, |
| | | "changetype: delete" |
| | | )); |
| | | } |
| | | |
| | | // I don't like copying this, but it's necessary since we want to continue on failure. |
| | | File tempFile = getTemporaryLdifFile(); |
| | | TestCaseUtils.writeFile(tempFile, ldif.toString()); |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", getServerLdapPort(), |
| | | "-D", DIR_MGR_DN, |
| | | "-w", DIR_MGR_PW, |
| | | "-f", tempFile.getAbsolutePath(), |
| | | "-c" |
| | | }; |
| | | |
| | | ldapModify(args, true); |
| | | } |
| | | |
| | | /** |
| | | * Return the difference between two ldif files. |
| | | */ |
| | | private String diffLdif(String actualLdif, String expectedLdif) throws Exception { |
| | | actualLdif = stripPassword(actualLdif); |
| | | expectedLdif = stripPassword(expectedLdif); |
| | | |
| | | File actualLdifFile = getTemporaryLdifFile("aci-tests-actual"); |
| | | File expectedLdifFile = getTemporaryLdifFile("aci-tests-expected"); |
| | | File diffLdifFile = getTemporaryLdifFile("aci-tests-diff"); |
| | | |
| | | TestCaseUtils.writeFile(actualLdifFile, actualLdif); |
| | | TestCaseUtils.writeFile(expectedLdifFile, expectedLdif); |
| | | diffLdifFile.delete(); |
| | | |
| | | String[] args = |
| | | { |
| | | "--sourceLDIF", actualLdifFile.getAbsolutePath(), |
| | | "--targetLDIF", expectedLdifFile.getAbsolutePath(), |
| | | "--outputLDIF", diffLdifFile.getAbsolutePath() |
| | | }; |
| | | |
| | | int retVal = LDIFDiff.mainDiff(args, true); |
| | | assertEquals(retVal, 0, "LDIFDiff failed"); |
| | | |
| | | if (diffLdifFile.exists()) { |
| | | return stripComments(TestCaseUtils.readFile(diffLdifFile)); |
| | | } else { |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | private static String stripPassword(String ldif) { |
| | | return stripAttrs(ldif, "userpassword"); |
| | | } |
| | | |
| | | // This won't catch attrs that wrap to the next line, but that shouldn't happen. |
| | | private static String stripAttrs(String ldif, String... attrs) { |
| | | // Generate "((cn)|(givenname))" |
| | | String anyAttr = "("; |
| | | for (int i = 0; i < attrs.length; i++) { |
| | | if (i > 0) { |
| | | anyAttr += "|"; |
| | | } |
| | | anyAttr += "(" + attrs[i] + ")"; |
| | | } |
| | | anyAttr += ")"; |
| | | |
| | | Pattern pattern = Pattern.compile("^" + anyAttr + "\\:(.*?)^", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.DOTALL); |
| | | return pattern.matcher(ldif).replaceAll(""); |
| | | } |
| | | |
| | | // This won't catch passwords that wrap to the next line, but that shouldn't happen. |
| | | private static final Pattern COMMENTS_REGEX = Pattern.compile("#.*", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); |
| | | private static String stripComments(String ldif) { |
| | | return COMMENTS_REGEX.matcher(ldif).replaceAll(""); |
| | | } |
| | | |
| | | private static ThreadLocal<Map<String,File>> _tempLdifFilesByName = new ThreadLocal<Map<String,File>>(); |
| | | |
| | | // To avoid a proliferation of temporary files, use the same ones over and over. |
| | | // We expect to use a single thread for the tests, but use a threadlocal |
| | | // just in case. |
| | | private File getTemporaryLdifFile(String name) throws IOException { |
| | | Map<String,File> tempFilesForThisThread = _tempLdifFilesByName.get(); |
| | | if (tempFilesForThisThread == null) { |
| | | tempFilesForThisThread = new HashMap<String,File>(); |
| | | _tempLdifFilesByName.set(tempFilesForThisThread); |
| | | } |
| | | File tempFile = tempFilesForThisThread.get(name); |
| | | if (tempFile == null) { |
| | | tempFile = File.createTempFile(name, ".ldif"); |
| | | tempFile.deleteOnExit(); |
| | | tempFilesForThisThread.put(name, tempFile); |
| | | } |
| | | return tempFile; |
| | | } |
| | | |
| | | // Convenience for when we only need one at time. |
| | | private File getTemporaryLdifFile() throws IOException { |
| | | return getTemporaryLdifFile("aci-tests"); |
| | | } |
| | | |
| | | private static ByteArrayOutputStream _cmdOutput = new ByteArrayOutputStream(); |
| | | private static void clearOutputStream() { |
| | | _cmdOutput.reset(); |
| | | } |
| | | |
| | | private static String getOutputStreamContents() { |
| | | return _cmdOutput.toString(); |
| | | } |
| | | |
| | | private static OutputStream getOutputStream() { |
| | | return _cmdOutput; |
| | | } |
| | | |
| | | |
| | | private static String makeUserLdif(String dn, String givenName, String sn, String password) { |
| | | String cn = givenName + " " + sn; |
| | | Assert.assertTrue(dn.startsWith("cn=" + cn)); // Enforce this since it's awkward to build the dn here too |
| | | return TestCaseUtils.makeLdif( |
| | | "dn: " + dn, |
| | | "objectclass: inetorgperson", |
| | | "objectclass: organizationalperson", |
| | | "objectclass: person", |
| | | "objectclass: top", |
| | | "cn: " + cn, |
| | | "sn: " + sn, |
| | | "givenName: " + givenName, |
| | | "userpassword: " + password); |
| | | } |
| | | |
| | | private static String makeOuLdif(String dn, String ou) { |
| | | Assert.assertTrue(dn.startsWith("ou=" + ou)); // Enforce this since it's awkward to build the dn here too |
| | | return TestCaseUtils.makeLdif( |
| | | "dn: " + dn, |
| | | "objectclass: organizationalunit", |
| | | "objectclass: top", |
| | | "ou: " + ou); |
| | | } |
| | | |
| | | private static String getThisDayOfWeek() { |
| | | int dayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); |
| | | return DAYS_OF_WEEK[dayOfWeek]; |
| | | } |
| | | |
| | | private static String getTomorrowDayOfWeek() { |
| | | int dayOfWeek = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) + 1) % 7; |
| | | return DAYS_OF_WEEK[dayOfWeek]; |
| | | } |
| | | |
| | | private static String getNotThisDayOfWeek() { |
| | | Set<String> otherDays = new HashSet<String>(Arrays.asList(DAYS_OF_WEEK)); |
| | | otherDays.remove(getThisDayOfWeek()); |
| | | String dayList = ""; |
| | | for (String otherDay: otherDays) { |
| | | if (dayList.length() > 0) { |
| | | dayList += ","; |
| | | } |
| | | dayList += otherDay; |
| | | } |
| | | return dayList; |
| | | } |
| | | |
| | | private static String getTimeNow() { |
| | | return TIME_FORMATTER.format(new Date()); |
| | | } |
| | | |
| | | private static String getTimeFromNowWithHourOffset(int hourOffset) { |
| | | GregorianCalendar calendar = new GregorianCalendar(); |
| | | calendar.setTime(new Date()); |
| | | calendar.add(Calendar.HOUR_OF_DAY, hourOffset); |
| | | return TIME_FORMATTER.format(calendar.getTime()); |
| | | } |
| | | |
| | | private static String getTimeOfDayRuleNextHour() { |
| | | String now = getTimeNow(); |
| | | String hourFromNow = getTimeFromNowWithHourOffset(1); |
| | | // If we're within an hour of midnight |
| | | if (hourFromNow.compareTo(now) < 0) { |
| | | return "(timeofday>=\"2300\" or timeofday<=\"0100\")"; |
| | | } else { |
| | | return "(timeofday>=\"" + now + "\" and timeofday<=\"" + hourFromNow + "\")"; |
| | | } |
| | | } |
| | | |
| | | private static String getTimeOfDayRulePreviousHour() { |
| | | String now = getTimeNow(); |
| | | String hourAgo = getTimeFromNowWithHourOffset(1); |
| | | // If we're within an hour of midnight |
| | | if (hourAgo.compareTo(now) > 0) { |
| | | return "(timeofday>=\"2300\" or timeofday<\"" + getTimeNow() + "\")"; |
| | | } else { |
| | | return "(timeofday<\"" + now + "\" and timeofday>=\"" + hourAgo + "\")"; |
| | | } |
| | | } |
| | | |
| | | private static final String and(String bindRule1, String bindRule2) { |
| | | return "(" + bindRule1 + " and " + bindRule2 + ")"; |
| | | } |
| | | |
| | | private static final String or(String bindRule1, String bindRule2) { |
| | | return "(" + bindRule1 + " or " + bindRule2 + ")"; |
| | | } |
| | | |
| | | private static final String not(String bindRule) { |
| | | return "not " + bindRule; |
| | | } |
| | | |
| | | private static final String getServerLdapPort() { |
| | | return String.valueOf(TestCaseUtils.getServerLdapPort()); |
| | | } |
| | | } |