/*
* 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
*
*
* Copyright 2008-2009 Sun Microsystems, Inc.
* Portions copyright 2012 ForgeRock AS.
*/
package org.opends.server.authorization.dseecompat;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.annotations.*;
import org.opends.server.protocols.ldap.LDAPResultCode;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.config.ConfigConstants.ATTR_AUTHZ_GLOBAL_ACI;
/**
* Unit test to test the targetcontrol ACI keyword.
*/
public class TargetControlTestCase extends AciTestCase {
private static final String superUser="uid=superuser,ou=admins,o=test";
private static final String level3User="uid=user.3,ou=People,o=test";
private static final String level4User="uid=user.4,ou=People,o=test";
private static final String newPWD="newPWD";
private static final String level1User="uid=user.1,ou=People,o=test";
private static final String base="uid=user.3,ou=People,o=test";
private static final String newRDN = "uid=user.3x";
private static final String newSup="ou=new,o=test";
private static final String newDN="uid=user.4," + base;
private static final String peopleBase="ou=People,o=test";
private static final String adminBase="ou=Admins,o=test";
private static final String newPeopleDN="uid=user.6," + peopleBase;
private static final String newAdminDN="uid=user.6," + adminBase;
@BeforeClass
public void setupClass() throws Exception {
deleteAttrFromAdminEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
addEntries("o=test");
}
@BeforeMethod
public void clearBackend() throws Exception {
deleteAttrFromEntry(peopleBase, "aci");
deleteAttrFromEntry(base, "aci");
deleteAttrFromAdminEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
}
private static final String[] newEntry = new String[] {
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: john.doe",
"givenName: John",
"sn: Doe",
"cn: John Doe",
"mail: john.doe@example.com",
"userPassword: password",
};
//Valid targetcontrol statements. Not the complete ACI.
@DataProvider(name = "validStatements")
public Object[][] valids() {
return new Object[][] {
{"1.3.6.1.4.1.42.2.27.8.5.1"},
{"2.16.840.1.113730.3.4.18"},
{"*"},
};
}
//Invalid targetcontrol statements. Not the complete ACI.
@DataProvider(name = "invalidStatements")
public Object[][] invalids() {
return new Object[][] {
{"1.3.6.1.4.1.42.2.27..8.5.1"},
{"2.16.840.1.113730.3.XXX.18"},
{"2.16.840.1.113730.*.4.18"},
{"2.16.840,1.113730.3.4.18"},
{"+"},
};
}
private static final
String ALLOW_ALL = "(targetattr=\"*\")" +
"(version 3.0;acl \"aclRights access\";" +
"allow (all) " +
"userdn=\"ldap:///self\";)";
private static final
String aclRightsAci = "(targetattr=\"aclRights\")" +
"(version 3.0;acl \"aclRights access\";" +
"allow (search, read) " +
"userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)";
//Disallow all controls with wild-card.
private static final
String controlNotWC = "(targetcontrol!=\"" + "*" + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + superUser + "\";)";
//Allow all controls with wild-card.
private static final
String controlWC = "(targetcontrol=\"" + "*" + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + superUser + "\";)";
//People branch can do any control but geteffectiverights assertion control.
private static final
String controlPeople = "(targetcontrol!=\"" +
OID_GET_EFFECTIVE_RIGHTS + "\")" +
"(target=\"ldap:///" + peopleBase + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
//Admin branch can only do geteffectiverights control.
private static final
String controlAdmin = "(targetcontrol=\"" + OID_GET_EFFECTIVE_RIGHTS + "\")" +
"(target=\"ldap:///" + adminBase + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
//Allow either reportauthzID or passwordpolicy controls. Used in the
//bind tests.
private static final
String pwdControls =
"(targetcontrol=\"" + OID_AUTHZID_REQUEST + "||" +
OID_PASSWORD_POLICY_CONTROL + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
//Allow either no-op or passwordpolicy controls. Used in the
//ext op tests.
private static final
String extOpControls =
"(targetcontrol=\"" + OID_LDAP_NOOP_OPENLDAP_ASSIGNED + "||" +
OID_PASSWORD_POLICY_CONTROL + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
//Allow all to extended op.
private static final
String extOpAll =
"(extop=\"" + "*" + "\")" +
"(version 3.0; acl \"control\";" +
"allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
//Only allow access to the password policy control. Used to test if the
//targetattr rule will give access erroneously.
private static final
String complicated =
"(targetcontrol=\"" + OID_PASSWORD_POLICY_CONTROL + "\")" +
"(targetattr != \"userpassword\")" +
"(version 3.0; acl \"control\";" +
"allow(all) userdn=\"ldap:///" + "anyone" + "\";)";
/**
* Test valid targetcontrol statements.
*
* @param statement The targetcontrol statement to attempt to decode.
* @throws AciException If an unexpected result happens.
*/
@Test(dataProvider = "validStatements")
public void testValidStatements(String statement) throws AciException {
TargetControl.decode(EnumTargetOperator.EQUALITY, statement);
}
/**
* Test invalid targetcontrol statements.
*
* @param statement The targetcontrol statement to attempt to decode.
* @throws Exception If an unexpected result happens.
*/
@Test(expectedExceptions= AciException.class, dataProvider="invalidStatements")
public void testInvalidStatements(String statement) throws Exception {
try {
TargetControl.decode(EnumTargetOperator.EQUALITY,statement);
} catch (AciException e) {
throw e;
} catch (Exception e) {
System.out.println(
"Invalid targetcontrol <" + statement +
"> threw wrong exception type.");
throw e;
}
throw new RuntimeException(
"Invalid targetcontrol <" + statement +
"> did not throw an exception.");
}
/**
* Test access to disallowed control based on a targetattr rule allowing
* access.
*
* @throws Exception If an unexpected result is returned.
*/
@Test()
public void testTargetattrSideEffect() throws Exception {
String pwdLdifs =
makeAddLDIF("aci", peopleBase, complicated);
LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
String noOpCtrlStr=OID_LDAP_NOOP_OPENLDAP_ASSIGNED + ":true";
//This should fail beacause this ACI only allows acces to the
//password policy control.
pwdModify(level4User, PWD, newPWD, noOpCtrlStr, null,
LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
deleteAttrFromEntry(peopleBase, "aci");
}
/**
* Test access to extended op controls (no-op and userPasswordPolicy).
*
* @throws Exception If an unexpected result is returned.
*/
@Test()
public void testExtendOpControls() throws Exception {
String pwdLdifs =
makeAddLDIF("aci", peopleBase, extOpControls, extOpAll, ALLOW_ALL);
LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
String noOpCtrlStr=OID_LDAP_NOOP_OPENLDAP_ASSIGNED + ":true";
//This pwd change should return no-op since the no-op control is
//specified and it is allowed for authorization dn.
pwdModify(level3User, PWD, newPWD, noOpCtrlStr, null,
LDAPResultCode.NO_OPERATION);
//This pwd change should fail even though the no-op is specified, since
//since the no-op control is not allowed for this authorization dn.
pwdModify(superUser, PWD, newPWD, noOpCtrlStr, null,
LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
deleteAttrFromEntry(peopleBase, "aci");
}
/**
* Test access to bind controls (reportAuthzID and usePasswordPolicy).
*
* @throws Exception If an unexpected result is returned.
*/
@Test()
public void testBindControl() throws Exception {
String pwdLdifs =
makeAddLDIF("aci", peopleBase, pwdControls, ALLOW_ALL);
LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
//The bind operation control access is based on the bind DN so this
//should succeed since both pwd policy and authzID control are allowed on
//ou=people, o=test suffix.
LDAPSearchParams(level3User, PWD, null, null, null,
superUser, filter, "aclRights mail description", true,
false, 0);
LDAPSearchParams(level3User, PWD, null, null, null,
superUser, filter, "aclRights mail description", true,
true, 0);
//This should succeed since both controls are not allowed for the
//ou=admins, o=test suffix, but both are critical.
LDAPSearchParams(superUser, PWD, null, null, null,
superUser, filter, "aclRights mail description", true,
true, 0);
deleteAttrFromEntry(peopleBase, "aci");
}
/**
* Test target from global ACI level. Two global ACIs are added, one allowing
* all controls except geteffective rights to the ou=people, o=test
* suffix. The other ACI only allows the geteffectiverights control on
* the ou=admin, o=test suffix. Comments in method should explain more
* what operations and controls are attempted.
*
* @throws Exception If an unexpected result happens.
*/
@Test()
public void testGlobalTargets() throws Exception {
String globalControlAcis=
makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
controlAdmin, controlPeople);
LDIFAdminModify(globalControlAcis, DIR_MGR_DN, PWD);
//Succeeds because geteffectiverights control is not allowed on
//ou=people, o=test, but it is non-critical.
LDAPSearchParams(level3User, PWD, null,
"dn: " + level1User, null,
level1User, filter, "aclRights mail description",
false, false, 0);
//Ok because geteffectiverights control is allowed on
//ou=admin, o=test
LDAPSearchParams(level3User, PWD, null,
"dn: " + level1User, null,
superUser, filter, "aclRights mail description",
false, false, 0);
String controlStr=OID_LDAP_ASSERTION + ":true:junk";
//Test add to ou=people, o=test with assertion control,
//should get protocol error since this control is allowed but value is
//junk.
String addEntryLDIF=makeAddEntryLDIF(newPeopleDN, newEntry);
LDIFAdd(addEntryLDIF, superUser, PWD, controlStr,
LDAPResultCode.PROTOCOL_ERROR);
//Test add to ou=admin, o=test with assertion control, and critical
//should get access denied since this control is not allowed.
String addEntryLDIF1=makeAddEntryLDIF(newAdminDN, newEntry);
LDIFAdd(addEntryLDIF1, superUser, PWD, controlStr,
LDAPResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
deleteAttrFromAdminEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
}
/**
* Test wildcard access. First test "targetcontrol != *"
* expression. Should all be access denied. Remove that ACI and add
* "targetcontrol = *" expression. Use assertion control with bad filter,
* all should return protocol error (modify, add, delete, modifyDN). Search
* with geteffectiverights should succeed.
*
* @throws Exception If an unexpected result happens.
*/
@Test()
public void testWildCard() throws Exception {
String aciDeny=makeAddLDIF("aci", base, controlNotWC);
String aciRight=makeAddLDIF("aci", base, aclRightsAci);
LDIFModify(aciDeny, DIR_MGR_DN, PWD);
LDAPSearchParams(superUser, PWD, null,
"dn: " + superUser, null,
base, filter, "aclRights mail description", false, false,
0 /* disallowed but non-critical */);
LDIFModify(aciRight, superUser, PWD, OID_LDAP_READENTRY_PREREAD,
LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
deleteAttrFromEntry (base, "aci");
String aciAllow=makeAddLDIF("aci", base, controlWC, ALLOW_ALL);
LDIFModify(aciAllow, DIR_MGR_DN, PWD);
//Search with geteffectiverights control.
LDAPSearchParams(superUser, PWD, null,
"dn: " + superUser, null,
base, filter, "aclRights mail description");
String controlStr=OID_LDAP_ASSERTION + ":true:junk";
//Attempt modify. Protocol error means we passed access control
LDIFModify(aciRight, superUser, PWD, controlStr ,
LDAPResultCode.PROTOCOL_ERROR);
//Attempt add, protocol error means we passed access control
String addEntryLDIF=makeAddEntryLDIF(newDN, newEntry);
LDIFAdd(addEntryLDIF, superUser, PWD, controlStr,
LDAPResultCode.PROTOCOL_ERROR);
//Attempt delete. Protocol error means we passed access control.
LDIFDelete(base, superUser, PWD, controlStr,
LDAPResultCode.PROTOCOL_ERROR);
String modDNLDIF=makeModDNLDIF(base, newRDN , "0", newSup);
//Attempt modify DN. Protocol error means we passed access control.
LDIFModify(modDNLDIF, superUser, PWD, controlStr ,
LDAPResultCode.PROTOCOL_ERROR);
deleteAttrFromEntry(base, "aci");
}
}