PasswordPolicyControlTestCase.java revision ea1068c292e9b341af6d6b563cd8988a96be20a9
/*
* 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
* or http://forgerock.org/license/CDDLv1.0.html.
* 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-2009 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS.
*/
package org.opends.server.controls;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.TestCaseUtils;
import org.opends.server.protocols.ldap.*;
import org.opends.server.types.Control;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.opends.server.types.RawAttribute;
import org.opends.server.types.RawModification;
import org.opends.server.util.StaticUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.opends.server.util.ServerConstants.*;
import static org.testng.Assert.*;
/**
* This class contains test cases that verify the appropriate handling of the
* password policy control as defined in draft-behera-ldap-password-policy.
*/
public class PasswordPolicyControlTestCase
extends ControlsTestCase
{
/**
* Make sure that the server is running.
*
* @throws Exception If an unexpected problem occurs.
*/
@BeforeClass
public void startServer()
throws Exception
{
TestCaseUtils.startServer();
}
/**
* Tests that an appropriate password policy response control is returned for
* an add operation when the user's password is in a "must change" state.
* This test will also ensure that the bind response is also capable of
* including the password policy response control with the "change after
* reset" error type set.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddMustChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest, controls);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for (Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
ArrayList<RawAttribute> rawAttrs = new ArrayList<RawAttribute>();
rawAttrs.add(RawAttribute.create("objectClass", "organizationalUnit"));
rawAttrs.add(RawAttribute.create("ou", "People"));
AddRequestProtocolOp addRequest = new AddRequestProtocolOp(
ByteString.valueOf("ou=People,o=test"), rawAttrs);
controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, addRequest, controls);
w.writeMessage(message);
message = r.readMessage();
AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
assertFalse(addResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
found = false;
for (Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* an add operation in which the proposed password is pre-encoded.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddPreEncodedPassword()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("cn=Directory Manager"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawAttribute> rawAttrs = new ArrayList<RawAttribute>();
rawAttrs.add(RawAttribute.create("objectClass", "inetOrgPerson"));
rawAttrs.add(RawAttribute.create("uid", "test.user"));
rawAttrs.add(RawAttribute.create("givenName", "Test"));
rawAttrs.add(RawAttribute.create("sn", "User"));
rawAttrs.add(RawAttribute.create("cn", "Test User"));
rawAttrs.add(RawAttribute.create("userPassword",
"{SSHA}0pZPpMIm6xSBIW4hGvR/72fjO4M9p3Ff1g7QFw=="));
AddRequestProtocolOp addRequest = new AddRequestProtocolOp(
ByteString.valueOf("ou=uid=test.user,o=test"), rawAttrs);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, addRequest, controls);
w.writeMessage(message);
message = r.readMessage();
AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
assertFalse(addResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY);
found = true;
}
}
assertTrue(found);
}
finally
{
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* an add operation in which the proposed password fails validation.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddPasswordFailsValidation()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--add", "password-validator:Length-Based Password Validator");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("cn=Directory Manager"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawAttribute> rawAttrs = new ArrayList<RawAttribute>();
rawAttrs.add(RawAttribute.create("objectClass", "inetOrgPerson"));
rawAttrs.add(RawAttribute.create("uid", "test.user"));
rawAttrs.add(RawAttribute.create("givenName", "Test"));
rawAttrs.add(RawAttribute.create("sn", "User"));
rawAttrs.add(RawAttribute.create("cn", "Test User"));
rawAttrs.add(RawAttribute.create("userPassword", "short"));
AddRequestProtocolOp addRequest = new AddRequestProtocolOp(
ByteString.valueOf("ou=uid=test.user,o=test"), rawAttrs);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, addRequest, controls);
w.writeMessage(message);
message = r.readMessage();
AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
assertFalse(addResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--remove", "password-validator:Length-Based Password Validator");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a bind operation in which the user's account is locked due to
* authentication failures.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testBindLockedDueToFailures()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "lockout-failure-count:3");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("wrong"));
for (int i=1; i <= 3; i++)
{
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertFalse(bindResponse.getResultCode() == LDAPResultCode.SUCCESS);
}
bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
LDAPMessage message = new LDAPMessage(4, bindRequest, controls);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertFalse(bindResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.ACCOUNT_LOCKED);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "lockout-failure-count:0");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a compare operation when the user's password is in a "must change" state.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testCompareMustChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
CompareRequestProtocolOp compareRequest =
new CompareRequestProtocolOp(ByteString.valueOf("o=test"), "o",
ByteString.valueOf("test"));
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, compareRequest, controls);
w.writeMessage(message);
message = r.readMessage();
CompareResponseProtocolOp compareResponse =
message.getCompareResponseProtocolOp();
assertFalse(compareResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a delete operation when the user's password is in a "must change" state.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testDeleteMustChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntries(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl",
"",
"dn: ou=People,o=test",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: People");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
DeleteRequestProtocolOp deleteRequest =
new DeleteRequestProtocolOp(ByteString.valueOf("ou=People,o=test"));
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, deleteRequest, controls);
w.writeMessage(message);
message = r.readMessage();
DeleteResponseProtocolOp deleteResponse =
message.getDeleteResponseProtocolOp();
assertFalse(deleteResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
/**
* Creates test data for testModifyMustChange.
*
* Fields:
* <userDN> <entryDN> <changeAfterReset>
*
* @return Returns test data for testModifyMustChange.
*/
@DataProvider(name = "testModifyMustChange")
public Object[][] createTestModifyMustChange() {
return new Object[][] {
// User does not need to change their password.
{ "uid=test.admin,o=test", "uid=test.admin,o=test", false },
{ "uid=test.admin,o=test", "uid=test.user,o=test", false },
{ "uid=test.admin,o=test", "o=test", false },
// User does need to change their password.
{ "uid=test.user,o=test", "uid=test.admin,o=test", true },
{ "uid=test.user,o=test", "uid=test.user,o=test", true },
{ "uid=test.user,o=test", "o=test", true }
};
}
/**
* Tests that an appropriate password policy response control is
* returned for a modify operation when the user's password is in a
* "must change" state.
*
* @param userDN
* The name of the user to bind as.
* @param entryDN
* The name of the entry to modify.
* @param changeAfterReset
* {@code true} if change after reset is expected.
* @throws Exception
* If an unexpected problem occurs.
*/
@Test(dataProvider="testModifyMustChange")
public void testModifyMustChange(String userDN, String entryDN, boolean changeAfterReset)
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.addEntry(
"dn: uid=test.admin,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.admin",
"givenName: Test Admin",
"sn: Admin",
"cn: Test Admin",
"userPassword: password",
"ds-privilege-name: bypass-acl");
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf(userDN), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawModification> mods = new ArrayList<RawModification>();
mods.add(RawModification.create(ModificationType.REPLACE, "description",
"foo"));
ModifyRequestProtocolOp modifyRequest =
new ModifyRequestProtocolOp(ByteString.valueOf(entryDN), mods);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, modifyRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyResponseProtocolOp modifyResponse =
message.getModifyResponseProtocolOp();
if (changeAfterReset)
{
assertEquals(modifyResponse.getResultCode(),
LDAPResultCode.CONSTRAINT_VIOLATION);
}
else
{
assertEquals(modifyResponse.getResultCode(),
LDAPResultCode.SUCCESS);
}
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
if (changeAfterReset) {
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
} else {
assertNull(pwpControl.getErrorType());
}
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is
* returned for a modify operation when the authorized user is forced to
* change their own password before changing a different entry.
*
* @throws Exception
* If an unexpected problem occurs.
*/
@Test
public void testAuthzModifyMustChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
String userDN = "uid=test.admin,o=test";
String entryDN = "uid=test.user,o=test";
String authzDN = "uid=authz.user,o=test";
TestCaseUtils.addEntry(
"dn: uid=test.admin,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.admin",
"givenName: Test Admin",
"sn: Admin",
"cn: Test Admin",
"userPassword: password",
"ds-privilege-name: bypass-acl",
"ds-privilege-name: proxied-auth");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntry(
"dn: uid=authz.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: authz.user",
"givenName: Authz",
"sn: User",
"cn: Authz User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf(userDN), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawModification> mods = new ArrayList<RawModification>();
mods.add(RawModification.create(ModificationType.REPLACE, "description",
"foo"));
ModifyRequestProtocolOp modifyRequest =
new ModifyRequestProtocolOp(ByteString.valueOf(entryDN), mods);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
controls.add(new LDAPControl(OID_PROXIED_AUTH_V2, true,
ByteString.valueOf("dn:" + authzDN)));
message = new LDAPMessage(2, modifyRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyResponseProtocolOp modifyResponse =
message.getModifyResponseProtocolOp();
assertEquals(modifyResponse.getResultCode(),
LDAPResultCode.CONSTRAINT_VIOLATION);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a modify operation when users do not have permission to change their own
* passwords.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyCannotChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "allow-user-password-changes:false");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawModification> mods = new ArrayList<RawModification>();
mods.add(RawModification.create(ModificationType.REPLACE, "userPassword",
"newpassword"));
ModifyRequestProtocolOp modifyRequest =
new ModifyRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), mods);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, modifyRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyResponseProtocolOp modifyResponse =
message.getModifyResponseProtocolOp();
assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "allow-user-password-changes:true");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a modify operation when the proposed password is in the user's password
* history.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyPasswordInHistory()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "password-history-count:5");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawModification> mods = new ArrayList<RawModification>();
mods.add(RawModification.create(ModificationType.REPLACE, "userPassword",
"password"));
ModifyRequestProtocolOp modifyRequest =
new ModifyRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), mods);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, modifyRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyResponseProtocolOp modifyResponse =
message.getModifyResponseProtocolOp();
assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.PASSWORD_IN_HISTORY);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "password-history-count:0");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a modify operation when the user didn't provide their current password when
* it was required.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyMissingCurrentPassword()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "password-change-requires-current-password:true");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawModification> mods = new ArrayList<RawModification>();
mods.add(RawModification.create(ModificationType.REPLACE, "userPassword",
"newpassword"));
ModifyRequestProtocolOp modifyRequest =
new ModifyRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), mods);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, modifyRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyResponseProtocolOp modifyResponse =
message.getModifyResponseProtocolOp();
assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.MUST_SUPPLY_OLD_PASSWORD);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "password-change-requires-current-password:false");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a modify operation when the user tried to perform multiple password changes
* without respecting the minimum age.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyMinimumPasswordAge()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "min-password-age:24 hours");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ArrayList<RawModification> mods = new ArrayList<RawModification>();
mods.add(RawModification.create(ModificationType.REPLACE, "userPassword",
"newpassword"));
ModifyRequestProtocolOp modifyRequest =
new ModifyRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), mods);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, modifyRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyResponseProtocolOp modifyResponse =
message.getModifyResponseProtocolOp();
assertFalse(modifyResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.PASSWORD_TOO_YOUNG);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "min-password-age:0 seconds");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a modify DN operation when the user's password is in a "must change" state.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyDNMustChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntries(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl",
"",
"dn: ou=People,o=test",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: People");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
ModifyDNRequestProtocolOp modifyDNRequest =
new ModifyDNRequestProtocolOp(
ByteString.valueOf("ou=People,o=test"),
ByteString.valueOf("ou=Users"), true);
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, modifyDNRequest, controls);
w.writeMessage(message);
message = r.readMessage();
ModifyDNResponseProtocolOp modifyDNResponse =
message.getModifyDNResponseProtocolOp();
assertFalse(modifyDNResponse.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
/**
* Tests that an appropriate password policy response control is returned for
* a search operation when the user's password is in a "must change" state.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testSearchMustChange()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:true");
TestCaseUtils.addEntry(
"dn: uid=test.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: test.user",
"givenName: Test",
"sn: User",
"cn: Test User",
"userPassword: password",
"ds-privilege-name: bypass-acl");
Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
org.opends.server.tools.LDAPWriter w = new org.opends.server.tools.LDAPWriter(s);
try
{
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
ByteString.valueOf("uid=test.user,o=test"), 3,
ByteString.valueOf("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
SearchRequestProtocolOp searchRequest =
new SearchRequestProtocolOp(ByteString.valueOf("o=test"),
SearchScope.BASE_OBJECT,
DereferenceAliasesPolicy.NEVER, 0, 0, false,
LDAPFilter.objectClassPresent(),
new LinkedHashSet<String>());
List<Control> controls = new ArrayList<Control>();
controls.add(new LDAPControl(OID_PASSWORD_POLICY_CONTROL, true));
message = new LDAPMessage(2, searchRequest, controls);
w.writeMessage(message);
message = r.readMessage();
SearchResultDoneProtocolOp searchDone =
message.getSearchResultDoneProtocolOp();
assertFalse(searchDone.getResultCode() == LDAPResultCode.SUCCESS);
controls = message.getControls();
assertNotNull(controls);
assertFalse(controls.isEmpty());
boolean found = false;
for(Control c : controls)
{
if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
{
PasswordPolicyResponseControl pwpControl;
if(c instanceof LDAPControl)
{
pwpControl =
PasswordPolicyResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl)c).getValue());
}
else
{
pwpControl = (PasswordPolicyResponseControl)c;
}
assertEquals(pwpControl.getErrorType(),
PasswordPolicyErrorType.CHANGE_AFTER_RESET);
found = true;
}
}
assertTrue(found);
}
finally
{
TestCaseUtils.dsconfig(
"set-password-policy-prop",
"--policy-name", "Default Password Policy",
"--set", "force-change-on-add:false");
StaticUtils.close(s);
}
}
}