AciTests.java revision 98e8aab354a385055392de7154758c1890a3265a
/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS
* Portions Copyright 2013 Manuel Gaupp
*
*/
/**
* 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.
*/
@SuppressWarnings("javadoc")
public class AciTests extends AciTestCase {
// TODO: test modify use cases
// TODO: test searches where we expect a subset of attributes and entries
// TODO: test delete
// TODO: test more combinations of attributes
// TODO: test multiple permission bind rules in the same ACI
// 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.
private static final boolean TESTS_ARE_DISABLED = false;
// 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"};
// -----------------------------------------------------------------------------
// USERS
// -----------------------------------------------------------------------------
static {
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//These entries are used to test groupdn, roledn and userattr stuff.
//End group entries.
//Used by modrdn new superior
private static final String MANAGER_NEW_DN =
"cn=new managers," + OU_BASE_DN;
//These entries are going to be used to test userattr parent stuff.
private static final String SALES_USER_NEW_1 =
"cn=sales1 person," + SALES_NEW_DN;
private static final String LEVEL_1_USER_URL =
"ldap:///??base?(cn=level1 user)";
//End userattr entries.
//The proxy 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 = {
};
private static final String BIND_RULE_USERDN_LEVEL_1 = "userdn=\"ldap:///" + LEVEL_1_USER_DN + "\"";
//The proxy userdn bind rule.
private static final String BIND_RULE_USERDN_PROXY =
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_GROUPDN_GROUP_1 =
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_AUTHMETHOD_SASL_DIGEST_MD5 = "authmethod=\"sasl DIGEST-MD5\"";
// 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_AND_TOMORROW = "dayofweek=\"" + getThisDayOfWeek() + "," + getTomorrowDayOfWeek() + "\"";
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));
// These 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))\"";
//bind rule user attr ACIs
private static final String BIND_RULE_USERATTR_USERDN_1 = "userattr=\"ldap:///dc=example,dc=com?owner#USERDN\"";
private static final String BIND_RULE_USERATTR_GROUPDN_1 = "userattr=\"ldap:///dc=example,dc=com?owner#GROUPDN\"";
private static final String BIND_RULE_USERATTR_USERDN_INHERITANCE = "userattr=\"parent[0,1,2].cn#USERDN\"";
private static final String BIND_RULE_USERATTR_GROUPDN_INHERITANCE = "userattr=\"parent[0,1,2].cn#GROUPDN\"";
//targattrfilters
private static final String TARG_ATTR_FILTERS_1 = "add=cn:(!(cn=superAdmin)) && telephoneNumber:(telephoneNumber=123*)";
private static final String TARG_ATTR_FILTERS_2 = "add=cn:(!(cn=superAdmin)), del=sn:(!(sn=nonSuperAdmin))";
//targattrfilters invalids
private static final String TARG_ATTR_FILTERS_INVALID_FILTER = "del=cn:(&(cnfoo)(cn=f*)) && sn:(snjoe*)";
private static final String TARG_ATTR_FILTERS_BAD_OP = "delete=cn:(&(cn=foo)(cn=f*)) && sn:(sn=joe*)";
private static final String TARG_ATTR_FILTERS_BAD_OP_MATCH = TARG_ATTR_FILTERS_1 + "," + TARG_ATTR_FILTERS_1 ;
private static final String TARG_ATTR_FILTERS_BAD_FILTER_ATTR = "del=cn:(&(cn=foo)(cn=f*)) && sn:(cn=joe*)";
private static final String TARG_ATTR_FILTERS_BAD_FORMAT = "delete=cn;(&(cn=foo)(cn=f*)) && sn:(sn=joe*)";
private static final String TARG_ATTR_FILTERS_TOO_MANY_LISTS = TARG_ATTR_FILTERS_1 + "," + TARG_ATTR_FILTERS_4 + "," + TARG_ATTR_FILTERS_1;
private static final String TARG_ATTR_FILTERS_BAD_TOK = "delete=cn:(&(cn=foo)(cn=f*)) && sn:(sn=joe*) || pager:(pager=123-*)";
private static final String TARG_ATTR_FILTERS_ATTR_TYPE_NAME = "del=cn:(&(cn=foo)(cn=f*)) && 1sn_:(1sn_=joe*)";
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 =
private static final String ALLOW_ALL_TO_COMPARE =
buildAciValue("name", "allow compare", "targetattr", "*", "target", "ldap:///cn=*," + OU_LEAF_DN, "allow(compare)", BIND_RULE_USERDN_ALL);
"deny read cn sn if person", "targetfilter", "objectClass=person",
//The ACIs for the proxy tests.
private static final String ALLOW_PROXY_CONTROL_TO_LEVEL_1=
OID_PROXIED_AUTH_V2, "allow(read)",
private static final String ALLOW_PROXY_TO_IMPORT_MGR_NEW =
private static final String ALLOW_PROXY_TO_IMPORT_MGR=
private static final String ALLOW_PROXY_TO_EXPORT_MGR_NEW =
private static final String ALLOW_PROXY_TO_EXPORT_MGR=
private static final String ALLOW_PROXY_TO_WRITE_RDN_ATTRS=
private static final String ALLOW_PROXY_TO_MOVED_ENTRY =
"allow(search,read)", BIND_RULE_USERDN_PROXY);
private static final String ALLOW_PROXY_TO_LEVEL1 =
"allow(proxy)", BIND_RULE_USERDN_LEVEL_1);
private static final String ALLOW_ALL_TO_IMPORT_MGR_NEW =
buildAciValue("name", "allow import mgr new tree", "target", MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_ALL_TO_IMPORT_MGR=
buildAciValue("name", "allow import mgr tree", "target", MGR_DN_URL, "allow(import)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_ALL_TO_EXPORT_MGR_NEW =
buildAciValue("name", "allow export mgr new tree", "target", MGR_NEW_DN_URL, "allow(export)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_ALL_TO_EXPORT_MGR=
buildAciValue("name", "allow export mgr tree", "target", MGR_DN_URL, "allow(export)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_ALL_TO_WRITE_RDN_ATTRS=
buildAciValue("name", "allow write to RDN attrs", "targetattr", "uid || cn || sn", "allow(write)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_ALL_TO_MOVED_ENTRY =
buildAciValue("name", "allow all to moved", "targetattr", "*", "allow(search,read)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_ALL_TO_SELFWRITE =
buildAciValue("name", "allow selfwrite", "targetattr", "member", "allow(selfwrite)", 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_GROUP1_GROUPDN =
private static final String ALLOW_SEARCH_TO_ADMIN =
buildAciValue("name", "allow search to admin", "targetattr", "*", "allow(search, read)", BIND_RULE_USERDN_ADMIN);
private static final String DENY_ALL_TO_ALL =
private static final String DENY_READ_TO_ALL =
private static final String DENY_SEARCH_TO_ALL =
private static final String ALLOW_SEARCH_TO_ALL =
buildAciValue("name", "allow search", "targetattr", "*", "allow(search, read)", BIND_RULE_USERDN_ALL);
private static final String ALLOW_READ_TO_ALL =
private static final String DENY_ALL_TO_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, read)", 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, read)", 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 ALLOW_ALL_TO_DNS_ALL =
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 ALLOW_ALL_TO_SASL_DIGEST_MD5 =
buildAciValue("name", "allow all to sasl DIGEST-MD5", "targetattr", "*", "allow(all)", BIND_RULE_AUTHMETHOD_SASL_DIGEST_MD5);
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 =
private static final String ALLOW_ALL_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 =
private static final String DENY_ALL_THIS_HOUR =
private static final String ALLOW_ALL_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, read)", BIND_RULE_IP_LOCALHOST);
private static final String ALLOW_SEARCH_REALATTRS_TO_LOCALHOST =
buildAciValue("name", "allow search to localhost", "targetattr!=", "bogusAttr", "allow(search, read)", 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, read)", 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, read)", 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, read)", BIND_RULE_AUTHMETHOD_SIMPLE);
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
// S E T U P
//
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
public void setupClass() throws Exception {
}
public void clearBackend() throws Exception {
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
// T E S T S
//
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// VALID AND INVALID ACIS
// -----------------------------------------------------------------------------
"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!
"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[] VALID_ACIS = {
// Test each feature in isolation.
// <PASSES>
// // TARGETS
buildAciValue("name", "parenthesis (dummy) and ( ) and () test", "allow (read)", 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),
//These are four are OpenDS specific attr names
buildAciValue("name", "opends targetattr", "targetattr", "1-digitinfirst", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "opendstargetattr", "targetattr", "this_has_underscores", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "oid targetattr", "targetattr", " 2.16.840.1.113730.3.3.2.18.1.4", "allow (write)", BIND_RULE_USERDN_SELF),
// OpenDJ 2.5 doesn't support acis with options
// buildAciValue("name", "locality targetattr", "targetattr", "locality;lang-fr-ca", "allow (write)", BIND_RULE_USERDN_SELF),
// buildAciValue("name", "complicated targetattr", "targetattr", "1ocal_ity;lang-fr-ca", "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/ targetScope", "targetScope", "subordinate", "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),
buildAciValue("name", "w/ targattrfilters", "targattrfilters=", TARG_ATTR_FILTERS, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "w/ targattrfilters", "targattrfilters=", TARG_ATTR_FILTERS_1 , "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "w/ targattrfilters", "targattrfilters=", TARG_ATTR_FILTERS_2 , "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "w/ targattrfilters", "targattrfilters=", TARG_ATTR_FILTERS_5 , "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_ATTR_TYPE_NAME", "targattrfilters",TARG_ATTR_FILTERS_ATTR_TYPE_NAME, "allow (write)", 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|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", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_USERDN_INHERITANCE),
buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_GROUPDN_INHERITANCE),
// 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>
buildAciValue("name", "deny all to example.com", "targetattr", "*", "deny(all)", "dns=\"*.example.com\""),
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_PREVIOUS_HOUR),
// </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("name", "invalid", "target", "ldap:///not a DN", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "invalid", "targetattr", "not an attr", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "invalid", "targetattr", "not/an/attr", "allow (write)", BIND_RULE_USERDN_SELF),
/* Test cases for OPENDJ-433 */
buildAciValue("name", "invalid", "targetattr", "cn", "garbage allow (read)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "invalid", "targetattr", "cn", "allow (read)", BIND_RULE_USERDN_SELF, "garbage allow (search)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "invalid", "targetattr", "cn", "allow (read)", BIND_RULE_USERDN_SELF, "allow (search)", BIND_RULE_USERDN_SELF, "garbage allow (compare)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "invalid", "targetattr", "cn", "allow (read)", BIND_RULE_USERDN_SELF, "allow (search)", BIND_RULE_USERDN_SELF, "allow (compare)", BIND_RULE_USERDN_SELF, "garbage allow (delete)", BIND_RULE_USERDN_SELF),
// Add tests with invalid keywords : typos in "targetattr", "targattfilters", "targetfilter"
buildAciValue("name", "bad_filters", "targattrfilters",TARG_ATTR_FILTERS_INVALID_FILTER, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_op", "targattrfilters",TARG_ATTR_FILTERS_BAD_OP, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_op_match", "targattrfilters",TARG_ATTR_FILTERS_BAD_OP_MATCH, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_filter_attr", "targattrfilters",TARG_ATTR_FILTERS_BAD_FILTER_ATTR, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_format", "targattrfilters",TARG_ATTR_FILTERS_BAD_FORMAT, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "too_many_lists", "targattrfilters",TARG_ATTR_FILTERS_TOO_MANY_LISTS, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_tok", "targattrfilters",TARG_ATTR_FILTERS_BAD_TOK, "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad_targetfilter", "targetfilter","this is a bad filter", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad targetScope", "targetScope", "sub_tree", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad right", "targetattr", "*", "allow (read, write, add, delete, search, compare, selfwrite, all, foo)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad access type", "targetattr", "*", "allows (read, write, add, delete, search, compare, selfwrite, all)", BIND_RULE_USERDN_SELF),
//no name
buildAciValue("targetattr", "*", "allows (read, write, add, delete, search, compare, selfwrite, all)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "bad groupdn url", "targetattr", "*", "allow (read, write, add, delete, search, compare, selfwrite, all)", "groupdn=\"ldap:///bogus\""),
buildAciValue("name", "bad groupdn url2", "targetattr", "*", "allow (read, write, add, delete, search, compare, selfwrite, all)", "groupdn=\"ldap1:///bogus\""),
//Roledn keyword is not supported anymore.
buildAciValue("name", "unsupported roledn", "targetattr", "*", "allow (all)", "roledn=\"ldap:///cn=foo, dc=bar\""),
// OpenDJ 2.5 doesn't support acis with options
buildAciValue("name", "unsupported option in targetattr", "targetattr", "locality;lang-fr-ca", "allow (write)", BIND_RULE_USERDN_SELF),
buildAciValue("name", "complicated unsupported option in targetattr", "targetattr", "1ocal_ity;lang-fr-ca", "allow (write)", BIND_RULE_USERDN_SELF),
// </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"},
};
TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass.
}
}
// This makes sure that all of the acis in the INVALID_ACIS_IF_ANY_CHAR_REMOVED
// tests are valid acis.
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;
}
}
TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass.
}
TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass.
}
}
// 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 \"
// 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.
}
}
return acisMissingOneChar;
}
// Common between validAcis and invalidAcis
// aci set in Add
"dn: " + OU_INNER_DN,
"changetype: add",
"objectclass: organizationalunit",
"ou: inner",
aci));
if (testMultipleCombos) {
"dn: " + OU_INNER_DN,
"changetype: add",
"objectclass: organizationalunit",
"ou: inner");
// aci set in modify via add
"dn: " + OU_INNER_DN,
"changetype: modify",
"add: aci",
aci));
// aci set in modify via replace
"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.
if (testMultipleCombos) {
}
}
}
}
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;
}
}
private void testValidAcisHelper(String modifierDn, String modifierPw, String aciModLdif) throws Throwable {
try {
// Setup the basic DIT
// Test that we can add entries with valid ACIs as well as set valid ACIs on a an entry
} catch (Throwable e) {
System.err.println("Started with dit:\nldapmodify -a -D \"cn=Directory Manager\" -w etegrity -p 13324\n" + VALIDITY_TESTS_DIT +
throw e;
}
}
// I'd like to make this dependsOnMethods = {"testBasisOfInvalidityTestsAreValid(String,String,String)"}
// but I can't figure out how.
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
// Test that we can add entries with valid ACIs as well as set valid ACIs on a an entry
} catch (Throwable e) {
System.err.println("Started with dit:\nldapmodify -a -D \"cn=Directory Manager\" -w etegrity -p 13324\n" + VALIDITY_TESTS_DIT +
throw e;
}
}
TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass.
}
/** 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. */
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;
}
}
// -----------------------------------------------------------------------------
// SEARCHING
// -----------------------------------------------------------------------------
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");
private static final String PROXY_USER_LDIF__SEARCH_TESTS =
private static final String SALES_USER_1__SEARCH_TESTS =
private static final String SALES_USER_2__SEARCH_TESTS =
private static final String SALES_USER_3__SEARCH_TESTS =
private static final String MANAGER__SEARCH_TESTS =
private static final String MANAGER_NEW__SEARCH_TESTS =
private static final String SALES__SEARCH_TESTS =
//LDIF entries used to test group stuff.
private static final String GROUP_LDIF__SEARCH_TESTS =
private static final
private static final
ADMIN_DN);
//ACI are used to test global ACI stuff.
private static final String ACCESS_HANDLER_DN =
"cn=Access Control Handler,cn=config";
private static final String GLOBAL_ALLOW_ALL_TO_ADMIN_ACI =
private static final String GLOBAL_ALLOW_MONITOR_TO_ADMIN_ACI =
"*", "target", "ldap:///cn=monitor",
"allow(all)", BIND_RULE_USERDN_ADMIN);
private static final String GLOBAL_ALLOW_BASE_DN_TO_LEVEL_1_ACI =
"allow(all)", BIND_RULE_USERDN_LEVEL_1);
private static final String ALLOW_ALL_GLOBAL_TO_ADMIN_MOD =
private static final String GLOBAL_MODS =
//Global defaults
private static final String GLOBAL_ANONYMOUS_READ_ACI =
"userPassword||authPassword",
"allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
private static final String GLOBAL_SELF_WRITE_ACI =
"*",
"allow(write)", BIND_RULE_USERDN_SELF);
private static final String GLOBAL_SCHEMA_ACI =
buildGlobalAciValue("name",
"User-Visible Schema Operational Attributes",
"target", "ldap:///cn=schema", "targetscope", "base",
"targetattr",
"attributeTypes||dITContentRules||dITStructureRules||" +
"ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||" +
"objectClasses",
"allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
"name","User-Visible Root DSE Operational Attributes",
"target", "ldap:///", "targetscope", "base",
"targetattr",
"namingContexts||supportedAuthPasswordSchemes||supportedControl||" +
"supportedExtension||supportedFeatures||supportedSASLMechanisms||" +
"vendorName||vendorVersion",
"allow(read, search, compare)",BIND_RULE_USERDN_ANYONE);
"name", "User-Visible Operational Attributes", "targetattr",
"createTimestamp||creatorsName||modifiersName||modifyTimestamp||" +
"entryDN||entryUUID||subschemaSubentry",
"allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
"name", "Anonymous control access", "targetcontrol",
"*",
"allow(read)", BIND_RULE_USERDN_ANYONE);
"name", "Anonymous extend op access", "extop",
"*",
"allow(read)", BIND_RULE_USERDN_ANYONE);
private static final String GLOBAL_DEFAULT_ACIS =
// ACI used to test LDAP compare.
// ACI used to test LDAP search with attributes.
//ACI used to test selfwrite
//ACIs used for standard modDN tests (export, import)
private static final String ACI_IMPORT_MGR_NEW =
private static final String ACI_IMPORT_MGR =
private static final String ACI_EXPORT_MGR_NEW =
private static final String ACI_EXPORT_MGR =
private static final String ACI_WRITE_RDN_ATTRS =
private static final String ACI_MOVED_ENTRY =
//ACIs used for proxied auth modDN tests
private static final String ACI_PROXY_IMPORT_MGR_NEW =
private static final String ACI_PROXY_CONTROL_LEVEL_1 =
private static final String ACI_PROXY_IMPORT_MGR =
private static final String ACI_PROXY_EXPORT_MGR_NEW =
private static final String ACI_PROXY_EXPORT_MGR =
private static final String ACI_PROXY_WRITE_RDN_ATTRS =
private static final String ACI_PROXY_LEVEL_1=
private static final String ACI_PROXY_MOVED_ENTRY =
//ACI used in testing the groupdn bind rule keywords.
private static final
//Aci to test dns="*".
private static final
// ou=leaf,ou=inner,ou=acitest,dc=example,dc=com and everything under it
private static final String LEAF_OU_FULL_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 =
// ou=acitest,dc=example,dc=com and everything under it
private static final String BASE_OU_FULL_LDIF__SEARCH_TESTS =
private static final String BASIC_LDIF__SEARCH_TESTS =
private static final String BASIC_LDIF__GROUP_SEARCH_TESTS =
// ------------------------------------------------------------
// THESE ALL WILL RETURN NO RESULTS FOR ADMINS AND ANONYMOUS
// ------------------------------------------------------------
private static final String ALLOW_ALL_BASE_DENY_ALL_BASE_LDIF =
private static final String ALLOW_ALL_BASE_DENY_READ_BASE_LDIF =
private static final String ALLOW_READ_BASE_DENY_ALL_BASE_LDIF =
private static final String ALLOW_READ_BASE_DENY_ALL_INNER_LDIF =
private static final String ALLOW_ALL_BASE_DENY_READ_INNER_LDIF =
private static final String ALLOW_SEARCH_BASE_DENY_ALL_INNER_LDIF =
private static final String ALLOW_ALL_BASE_DENY_SEARCH_INNER_LDIF =
private static final String ALLOW_ALL_BASE_DENY_ALL_INNER_LDIF =
private static final String ALLOW_ALL_BASE_DENY_ADMIN_INNER_LDIF =
private static final String ALLOW_ALL_BASE_DENY_OU_PERSON_INNER_LDIF =
private static final String DENY_ADMIN_BASE_ALLOW_ALL_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_OU_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_BASE_LDIF =
private static final String ALL0W_SEARCH_BASE_DENY_READ_BASE_LDIF =
private static final String ALL0W_ALL_BASE_DENY_ALL_REAL_ATTRS_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_REAL_ATTRS_INNER_LDIF =
private static final String ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_BASE_LDIF =
private static final String ALL0W_ALL_TO_ALL_OTHER_OBJECTCLASSES_BASE_LDIF_ALT =
private static final String ALL0W_ALL_BASE_DENY_WRITE_DELETE_READ_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_TO_CN_RDN_USERS_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_TO_UID_OR_CN_RDN_USERS_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_TO_NON_UID_RDN_USERS_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_TO_CN_ADMINS_INNER_LDIF =
private static final String ALL0W_ALL_BASE_DENY_READ_TO_TOP_LEVEL_CN_ADMINS_INNER_LDIF =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST =
private static final String ALLOW_ALL_NON_LOCALHOST =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_MISC_AND_LOCALHOST =
private static final String ALLOW_ALL_NON_MISC_AND_LOCALHOST =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_MISC_AND_LOCALHOST_SUBNET =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST_WITH_MASK =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_LOCALHOST_SUBNET_WITH_MASK =
private static final String ALLOW_ALL_BASE_TO_NON_DNS_LOCALHOST =
private static final String ALLOW_ALL_BASE_TO_SSL_AUTH =
private static final String ALLOW_ALL_BASE_TO_SASL_DIGEST_MD5_AUTH =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_SIMPLE_AUTH =
private static final String ALLOW_ALL_BASE_DENY_ALL_TODAY =
private static final String ALLOW_ALL_BASE_DENY_ALL_TODAY_AND_TOMORROW =
private static final String ALLOW_ALL_BASE_NOT_TODAY =
private static final String ALLOW_ALL_BASE_DENY_ALL_THIS_HOUR =
private static final String ALLOW_ALL_BASE_PREVIOUS_HOUR =
private static final String ALLOW_ALL_BASE_ADMIN_AND_SSL =
private static final String ALLOW_ALL_BASE_DENY_ALL_NOT_LOCALHOST_OR_ADMIN =
private static final String ALLOW_ALL_BASE_DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL =
private static final String ALLOW_ALL_BASE_NOT_ADMIN =
// -----------------------------------------------------------------
// THESE ALL WILL RETURN EVERYTHING IN AT LEAST OU=INNER FOR ADMINS
// -----------------------------------------------------------------
private static final String ALLOW_ALL_BASE_TO_ADMIN =
private static final String ALLOW_ALL_BASE_TO_LOCALHOST =
private static final String ALLOW_ALL_BASE_TO_ANYONE =
private static final String ALLOW_ALL_BASE_TO_ALL =
private static final String ALL0W_SEARCH_INNER_TO_ADMIN =
private static final String ALL0W_WRITE_DELETE_SEARCH_INNER_TO_ALL =
private static final String ALLOW_INNER_SEARCH_TO_CN_ADMINS =
private static final String ALLOW_INNER_ALL_TO_SIMPLE =
private static final String ALLOW_INNER_ALL_TODAY =
private static final String ALLOW_INNER_ALL_THIS_HOUR =
private static final String ALLOW_INNER_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL =
private static final String ALLOW_INNER_SEARCH_FROM_BASE_LOCALHOST =
private static final String ALLOW_BASE_SEARCH_REALATTRS_TO_LOCALHOST =
private static final String ALLOW_BASE_SEARCH_OUR_ATTRS_TO_ADMIN =
private static final String ALLOW_BASE_SEARCH_OU_AND_PERSON_TO_SIMPLE =
// ------------------------------------------------------------
//
// ------------------------------------------------------------
// 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.
//
return testParams;
}
static {
//
// ACIs that allow 'cn=Directory Manager' but deny the searches below to everyone else
// in some way.
//
);
testParams.addSingleSearch(DIR_MGR_DN, OU_INNER_DN, OBJECTCLASS_STAR, SCOPE_SUB, INNER_OU_FULL_LDIF__SEARCH_TESTS);
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(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(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.
//
// These ACIs are all equivalent for the single search test cases below
// (but most likely not equivalent in general).
// <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(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.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 _searchBaseDn;
private final String _searchFilter;
private final String _searchScope;
private final String _expectedResultsLdif;
private final String _initialDitLdif;
private final String[] _attributes;
{
}
{
}
String... attributes)
{
}
}
public String[] getLdapSearchArgs()
{
{
"-h", "127.0.0.1",
"-p", getServerLdapPort(),
"-b", _searchBaseDn,
"-s", _searchScope,
}
{
"-h", "127.0.0.1",
"-p", getServerLdapPort(),
"-D", _bindDn,
"-w", _bindPw,
"-b", _searchBaseDn,
"-s", _searchScope,
}
else
{
"-h", "127.0.0.1",
"-p", getServerLdapPort(),
"-D", _bindDn,
"-w", _bindPw,
"-b", _searchBaseDn,
"-s", _searchScope,
}
{
}
}
// 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 +
}
return new String[] {
"-h", "127.0.0.1",
"-p", getServerLdapPort(),
"-D", _bindDn,
"-w", _bindPw,
"--useCompareResultCode",
}
}
private static class SearchTestParams {
/** The server DIT to run the tests against. */
private final String _initialDitLdif;
/** ACIs that will produce the same search results for the above DIT. */
}
private void addSingleSearch(String bindDn, String searchBaseDn, String searchFilter, String searchScope, String expectedResultsLdif) {
_searchTests.add(SingleSearchParams.nonProxiedSearch(bindDn, DN_TO_PW.get(bindDn), searchBaseDn, searchFilter, searchScope, expectedResultsLdif, _initialDitLdif, equivalentAci));
}
}
/**
* @return the LDIF result of applying changesLdif to changesLdif
*/
ldifWriter.flush();
return updatedEntriesStream.toString();
}
}
TestCaseUtils.startServer(); // This appears to be necessary since the DataProviders can be called before @BeforeClass.
try {
}
}
} 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 LDAP compare.
* @throws Throwable If the compare is not valid for the ACI.
*/
@Test
public void testCompare() throws Throwable
{
}
/**
* Test proxy keyword using modify DN. Exact test as testModDN, except using
* proxied authorization for modifies and searches.
*
* Add a set of ACIs to allow exports, imports and write rights to the
* proxy user PROXY_USER_DN. Also add an aci low in the DIT, with search and
* read rights to the proxy user. This is ACI is to test the
* ACI list after a move has been made. Add an ACI that allows LEVEL_1_USER_DN
* proxy authorization rights (proxy).
*
* Move the subtree binding as LEVEL_1_USER_DN using proxied authorization,
* search with base at new DN binding as LEVEL_1_USER_DN proxied
* authorization, then move the tree back binding as LEVEL_1_USER_DN using
* proxied authorization and lastly re-search with base at orig DN
* binding as LEVEL_1_USER_DN using proxied authorization.
* @throws Throwable
*/
@Test
public void testProxyModDN() throws Throwable {
{
}
}
/**
* Test modify DN. Add a set of ACIs to allow exports, imports and write
* rights. Also add an aci low in the DIT to test the ACI list after a move
* has been made. Move the subtree, search with base at new DN, move the
* tree back and re-search with base at orig DN.
* @throws Throwable
*/
@Test
"pa$$word", SALES_USER_1,
"pa$$word", SALES_USER_NEW_1,
{
}
}
/**
* Test anonymous modify DN with the same RDN.
*/
@Test
public void testAnonymousModDNSameRDN() throws Throwable {
}
/**
* Test selfwrite right. Attempt to bind as level3 user and remove level1
* user from a group, should fail.
* @throws Throwable If the delete succeeds.
*/
@Test
public void testNonSelfWrite() throws Throwable {
LEVEL_3_USER_DN, "pa$$word", false);
}
/**
* Test selfwrite right. Attempt to bind as level1 user and remove itself
* from a group, should succeed.
* @throws Throwable If the delete fails.
*/
@Test
public void testSelfWrite() throws Throwable {
LEVEL_1_USER_DN, "pa$$word", true);
}
/**
* Test ACI using dns="*" bind rule pattern. Search should succeed.
* @throws Throwable If the search doesn't return any entries.
*/
@Test
public void testDNSWildCard() throws Throwable {
"pa$$word", LEVEL_3_USER_DN,
{
}
}
/**
* Test group bind rule ACI keywords.
*/
@Test
public void testGroupAcis() throws Throwable {
//group2 fail
//group1 pass
"pa$$word", LEVEL_3_USER_DN,
{
}
}
/**
* Test global ACI. Two ACIs are used, one protecting "cn=monitor" and the
* other the test DIT.
*
* @throws Throwable
*/
@Test
public void testGlobalAcis() throws Throwable {
"pa$$word", OU_BASE_DN,
}
if (TESTS_ARE_DISABLED) { // This is a hack to make sure we can disable the tests.
return;
}
try {
// Modify the entries, and apply the LDIF
// Now issue the search and see if we get what we expect.
// Ignoring whitespace the diff should be empty.
} catch (Throwable e) {
"Started with dit:\n" +
searchResults + "\nInstead of:\n" +
"The difference is:\n" +
throw e;
}
}
/**
* Test search with target filter and target attributes do not conflict with
* requested attributes in search request. See OpenDS issue 4583.
*
* @throws Exception
* If an unexpected exception occurred.
*/
@Test
public void testSearchTargetFilterAndAttributes() throws Exception
{
// Now issue the search and see if we get what we expect.
// First check cn, sn, and givenName are all readable without the ACI.
"dn: " + LEVEL_3_USER_DN,
"cn: level3 user",
"sn: user",
"givenName: level3");
// Ignoring whitespace the diff should be empty.
// Add the ACI: this will prevent the cn and sn attributes from being read
// for entries having the person objectClass. We need to ensure that this
// ACI is applied even though the target filter attribute (objectClass) is
// not being returned in the results.
"dn: " + LEVEL_3_USER_DN,
"givenName: level3");
// Ignoring whitespace the diff should be empty.
}
/**
* Test online handler re-initialization using global and selfwrite
* right test cases.
* @throws Throwable If any test cases fail after re-initialization.
*/
@Test
public void testAciHandlerReInit() throws Throwable {
// Setup using global and selfwrite test cases.
// Disable ACI handler.
"--set", "enabled:false");
// Enable ACI handler.
"--set", "enabled:true");
// Test global ACI. Two ACIs are used, one protecting
// "cn=monitor" and the other the test DIT.
"pa$$word", OU_BASE_DN,
// Test selfwrite right. Attempt to bind as level3 user and remove
// level1 user from a group, should fail.
LEVEL_3_USER_DN, "pa$$word", false);
// Test selfwrite right. Attempt to bind as level1 user and remove
// itself from a group, should succeed.
LEVEL_1_USER_DN, "pa$$word", true);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
// U T I L I T I E S
//
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
/**
* Create an ACI string with the specified variable string list. The method
* uses the global ACI attribute type name, instead of "aci".
* @param aciFields The fields to use to build the ACI.
* @return An ACI string.
*/
}
/**
* 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.
*/
}
/**
* 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.
*/
// Go through target* first
aciField += "=";
}
}
}
// Try to get the name
}
}
// Anything else is permission and a bindRule
}
}
}
/**
* Create a ldif entry with the specified variable ACI list. This method
* allows the attribute type to be specified in an argument.
* @param attr The attribute type name to use for the aci attribute.
* @param dn The dn to use.
* @param acis A variable list of ACI strings.
* @return A ldif entry string.
*/
}
}
}
}
private void addEntries(String ldif, String bindDn, String bindPassword, boolean expectSuccess) throws Exception {
{
"-h", "127.0.0.1",
"-p", getServerLdapPort(),
"-D", bindDn,
"-w", bindPassword,
"-a",
};
}
}
Assert.assertEquals(retVal, 0, "Non-zero return code because, error: " + getOutputStreamContents());
return getOutputStreamContents();
}
Assert.assertEquals(retVal, expectedRc, "Non-zero return code because, error: " + getOutputStreamContents());
return getOutputStreamContents();
}
throws Exception {
}
throws Exception {
}
}
boolean expectSuccess) throws Exception {
{
"-h", "127.0.0.1",
"-p", getServerLdapPort(),
"-D", bindDn,
"-w", bindPassword,
};
}
boolean contFlag)
throws Exception {
if(contFlag)
}
}
private void deleteAllTestEntries() throws Exception {
}
"dn: " + dn,
"changetype: modify",
"delete: " + attr,
}
if(newSuperior != null)
}
"dn: " + dn,
"changetype: modify",
"delete: " + attr));
}
// TODO: make this actually do a search first!
"dn: " + dn,
"changetype: delete"
));
}
}
/**
* Return the difference between two ldif files.
*/
{
};
if (diffLdifFile.exists()) {
}
return "";
}
}
// This won't catch attrs that wrap to the next line, but that shouldn't happen.
// Generate "((cn)|(givenname))"
if (i > 0) {
anyAttr += "|";
}
}
anyAttr += ")";
Pattern pattern = Pattern.compile("^" + anyAttr + "\\:(.*?)^", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
}
// 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 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.
if (tempFilesForThisThread == null) {
}
}
return tempFile;
}
// Convenience for when we only need one at time.
return getTemporaryLdifFile("aci-tests");
}
private static void clearOutputStream() {
_cmdOutput.reset();
}
private static String getOutputStreamContents() {
return _cmdOutput.toString();
}
private static OutputStream getOutputStream() {
return _cmdOutput;
}
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,
"ds-privilege-name: proxied-auth");
}
// Enforce this since it's awkward to build the dn here too
else
}
}
/**
* Makes a group ldif entry using the the specified DN and members.
* @param dn The dn to use in building the ldif.
* @param members A variable list of member strings.
* @return The ldif entry string.
*/
}
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() {
return DAYS_OF_WEEK[dayOfWeek];
}
private static String getTomorrowDayOfWeek() {
return DAYS_OF_WEEK[dayOfWeek];
}
private static String getNotThisDayOfWeek() {
dayList += ",";
}
}
return dayList;
}
private static String getTimeNow() {
}
}
private static String getTimeOfDayRuleNextHour() {
// If we're within an hour of midnight
return "(timeofday>=\"2300\" or timeofday<=\"0100\")";
} else {
}
}
private static String getTimeOfDayRulePreviousHour() {
// If we're within an hour of midnight
} else {
}
}
}
}
return "not " + bindRule;
}
private static String getServerLdapPort() {
}
}