/*
* 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 2006-2009 Sun Microsystems, Inc.
* Portions Copyright 2011-2013 ForgeRock AS
*/
package org.opends.server.extensions;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.
PasswordPolicyStateExtendedOperationHandlerCfg;
import org.opends.server.api.AuthenticationPolicy;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ExtendedOperationHandler;
import org.opends.server.config.ConfigException;
import org.opends.server.core.*;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.asn1.ASN1;
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.schema.GeneralizedTimeSyntax;
import org.opends.server.types.*;
import static org.opends.messages.CoreMessages.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
* This class implements an LDAP extended operation that can be used to query
* and update elements of the Directory Server password policy state for a given
* user. The ASN.1 definition for the value of the extended request is:
* <BR>
* <PRE>
* PasswordPolicyStateValue ::= SEQUENCE {
* targetUser LDAPDN
* operations SEQUENCE OF PasswordPolicyStateOperation OPTIONAL }
*
* PasswordPolicyStateOperation ::= SEQUENCE {
* opType ENUMERATED {
* getPasswordPolicyDN (0),
* getAccountDisabledState (1),
* setAccountDisabledState (2),
* clearAccountDisabledState (3),
* getAccountExpirationTime (4),
* setAccountExpirationTime (5),
* clearAccountExpirationTime (6),
* getSecondsUntilAccountExpiration (7),
* getPasswordChangedTime (8),
* setPasswordChangedTime (9),
* clearPasswordChangedTime (10),
* getPasswordExpirationWarnedTime (11),
* setPasswordExpirationWarnedTime (12),
* clearPasswordExpirationWarnedTime (13),
* getSecondsUntilPasswordExpiration (14),
* getSecondsUntilPasswordExpirationWarning (15),
* getAuthenticationFailureTimes (16),
* addAuthenticationFailureTime (17),
* setAuthenticationFailureTimes (18),
* clearAuthenticationFailureTimes (19),
* getSecondsUntilAuthenticationFailureUnlock (20),
* getRemainingAuthenticationFailureCount (21),
* getLastLoginTime (22),
* setLastLoginTime (23),
* clearLastLoginTime (24),
* getSecondsUntilIdleLockout (25),
* getPasswordResetState (26),
* setPasswordResetState (27),
* clearPasswordResetState (28),
* getSecondsUntilPasswordResetLockout (29),
* getGraceLoginUseTimes (30),
* addGraceLoginUseTime (31),
* setGraceLoginUseTimes (32),
* clearGraceLoginUseTimes (33),
* getRemainingGraceLoginCount (34),
* getPasswordChangedByRequiredTime (35),
* setPasswordChangedByRequiredTime (36),
* clearPasswordChangedByRequiredTime (37),
* getSecondsUntilRequiredChangeTime (38),
* getPasswordHistory (39),
* clearPasswordHistory (40),
* ... },
* opValues SEQUENCE OF OCTET STRING OPTIONAL }
* </PRE>
* <BR>
* Both the request and response values use the same encoded form, and they both
* use the same OID of "1.3.6.1.4.1.26027.1.6.1". The response value will only
* include get* elements. If the request did not include any operations, then
* the response will include all get* elements; otherwise, the response will
* only include the get* elements that correspond to the state fields referenced
* in the request (regardless of whether that operation was included in a get*,
* set*, add*, remove*, or clear* operation).
*/
public class PasswordPolicyStateExtendedOperation
extends ExtendedOperationHandler<
PasswordPolicyStateExtendedOperationHandlerCfg>
{
/**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
/** The enumerated value for the getPasswordPolicyDN operation. */
public static final int OP_GET_PASSWORD_POLICY_DN = 0;
/** The enumerated value for the getAccountDisabledState operation. */
public static final int OP_GET_ACCOUNT_DISABLED_STATE = 1;
/** The enumerated value for the setAccountDisabledState operation. */
public static final int OP_SET_ACCOUNT_DISABLED_STATE = 2;
/** The enumerated value for the clearAccountDisabledState operation. */
public static final int OP_CLEAR_ACCOUNT_DISABLED_STATE = 3;
/** The enumerated value for the getAccountExpirationTime operation. */
public static final int OP_GET_ACCOUNT_EXPIRATION_TIME = 4;
/** The enumerated value for the setAccountExpirationTime operation. */
public static final int OP_SET_ACCOUNT_EXPIRATION_TIME = 5;
/** The enumerated value for the clearAccountExpirationTime operation. */
public static final int OP_CLEAR_ACCOUNT_EXPIRATION_TIME = 6;
/**
* The enumerated value for the getSecondsUntilAccountExpiration operation.
*/
public static final int OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION = 7;
/** The enumerated value for the getPasswordChangedTime operation. */
public static final int OP_GET_PASSWORD_CHANGED_TIME = 8;
/** The enumerated value for the setPasswordChangedTime operation. */
public static final int OP_SET_PASSWORD_CHANGED_TIME = 9;
/** The enumerated value for the clearPasswordChangedTime operation. */
public static final int OP_CLEAR_PASSWORD_CHANGED_TIME = 10;
/** The enumerated value for the getPasswordExpirationWarnedTime operation. */
public static final int OP_GET_PASSWORD_EXPIRATION_WARNED_TIME = 11;
/** The enumerated value for the setPasswordExpirationWarnedTime operation. */
public static final int OP_SET_PASSWORD_EXPIRATION_WARNED_TIME = 12;
/**
* The enumerated value for the clearPasswordExpirationWarnedTime operation.
*/
public static final int OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME = 13;
/**
* The enumerated value for the getSecondsUntilPasswordExpiration operation.
*/
public static final int OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION = 14;
/**
* The enumerated value for the getSecondsUntilPasswordExpirationWarning
* operation.
*/
public static final int OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING = 15;
/** The enumerated value for the getAuthenticationFailureTimes operation. */
public static final int OP_GET_AUTHENTICATION_FAILURE_TIMES = 16;
/** The enumerated value for the addAuthenticationFailureTime operation. */
public static final int OP_ADD_AUTHENTICATION_FAILURE_TIME = 17;
/** The enumerated value for the setAuthenticationFailureTimes operation. */
public static final int OP_SET_AUTHENTICATION_FAILURE_TIMES = 18;
/** The enumerated value for the clearAuthenticationFailureTimes operation. */
public static final int OP_CLEAR_AUTHENTICATION_FAILURE_TIMES = 19;
/**
* The enumerated value for the getSecondsUntilAuthenticationFailureUnlock
* operation.
*/
public static final int OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK =
20;
/**
* The enumerated value for the getRemainingAuthenticationFailureCount
* operation.
*/
public static final int OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT = 21;
/** The enumerated value for the getLastLoginTime operation. */
public static final int OP_GET_LAST_LOGIN_TIME = 22;
/** The enumerated value for the setLastLoginTime operation. */
public static final int OP_SET_LAST_LOGIN_TIME = 23;
/** The enumerated value for the clearLastLoginTime operation. */
public static final int OP_CLEAR_LAST_LOGIN_TIME = 24;
/** The enumerated value for the getSecondsUntilIdleLockout operation. */
public static final int OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT = 25;
/** The enumerated value for the getPasswordResetState operation. */
public static final int OP_GET_PASSWORD_RESET_STATE = 26;
/** The enumerated value for the setPasswordResetState operation. */
public static final int OP_SET_PASSWORD_RESET_STATE = 27;
/** The enumerated value for the clearPasswordResetState operation. */
public static final int OP_CLEAR_PASSWORD_RESET_STATE = 28;
/**
* The enumerated value for the getSecondsUntilPasswordResetLockout operation.
*/
public static final int OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT = 29;
/** The enumerated value for the getGraceLoginUseTimes operation. */
public static final int OP_GET_GRACE_LOGIN_USE_TIMES = 30;
/** The enumerated value for the addGraceLoginUseTime operation. */
public static final int OP_ADD_GRACE_LOGIN_USE_TIME = 31;
/** The enumerated value for the setGraceLoginUseTimes operation. */
public static final int OP_SET_GRACE_LOGIN_USE_TIMES = 32;
/** The enumerated value for the clearGraceLoginUseTimes operation. */
public static final int OP_CLEAR_GRACE_LOGIN_USE_TIMES = 33;
/** The enumerated value for the getRemainingGraceLoginCount operation. */
public static final int OP_GET_REMAINING_GRACE_LOGIN_COUNT = 34;
/**
* The enumerated value for the getPasswordChangedByRequiredTime operation.
*/
public static final int OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME = 35;
/**
* The enumerated value for the setPasswordChangedByRequiredTime operation.
*/
public static final int OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME = 36;
/**
* The enumerated value for the clearPasswordChangedByRequiredTime operation.
*/
public static final int OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME = 37;
/**
* The enumerated value for the getSecondsUntilRequiredChangeTime operation.
*/
public static final int OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME = 38;
/** The enumerated value for the getPasswordHistory operation. */
public static final int OP_GET_PASSWORD_HISTORY = 39;
/** The enumerated value for the clearPasswordHistory operation. */
public static final int OP_CLEAR_PASSWORD_HISTORY = 40;
/** The set of attributes to request when retrieving a user's entry. */
private LinkedHashSet<String> requestAttributes;
/** The search filter that will be used to retrieve user entries. */
private SearchFilter userFilter;
private boolean isAccountSetDisabled;
private boolean isAccountSetEnabled;
/**
* Create an instance of this password policy state extended operation. All
* initialization should be performed in the
* {@code initializeExtendedOperationHandler} method.
*/
public PasswordPolicyStateExtendedOperation()
{
super();
}
/**
* Initializes this extended operation handler based on the information in the
* provided configuration entry. It should also register itself with the
* Directory Server for the particular kinds of extended operations that it
* will process.
*
* @param config The configuration that contains the information
* to use to initialize this extended operation handler.
*
* @throws ConfigException If an unrecoverable problem arises in the
* process of performing the initialization.
*
* @throws InitializationException If a problem occurs during initialization
* that is not related to the server
* configuration.
*/
@Override
public void initializeExtendedOperationHandler(
PasswordPolicyStateExtendedOperationHandlerCfg config)
throws ConfigException, InitializationException
{
// Construct the filter that will be used to retrieve user entries.
try
{
userFilter = SearchFilter.createFilterFromString("(objectClass=*)");
}
catch (Exception e)
{
// This should never happen.
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
}
// Construct the set of request attributes.
requestAttributes = new LinkedHashSet<String>(2);
requestAttributes.add("*");
requestAttributes.add("+");
DirectoryServer.registerSupportedExtension(OID_PASSWORD_POLICY_STATE_EXTOP,
this);
// FIXME registerControlAndFeatures?
}
/**
* Processes the provided extended operation.
*
* @param operation The extended operation to be processed.
*/
@Override
public void processExtendedOperation(ExtendedOperation operation)
{
operation.setResultCode(ResultCode.UNDEFINED);
// The user must have the password-reset privilege in order to be able to do
// anything with this extended operation.
ClientConnection clientConnection = operation.getClientConnection();
if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET, operation))
{
Message message = ERR_PWPSTATE_EXTOP_NO_PRIVILEGE.get();
operation.appendErrorMessage(message);
operation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
return;
}
// There must be a request value, and it must be a sequence. Decode it
// into its components.
ByteString requestValue = operation.getRequestValue();
if (requestValue == null)
{
Message message = ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE.get();
operation.appendErrorMessage(message);
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
return;
}
ByteString dnString;
ASN1Reader reader = ASN1.getReader(requestValue);
try
{
reader.readStartSequence();
dnString = reader.readOctetString();
}
catch (Exception e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message message =
ERR_PWPSTATE_EXTOP_DECODE_FAILURE.get(getExceptionMessage(e));
operation.appendErrorMessage(message);
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
return;
}
// Decode the DN and get the corresponding user entry.
DN targetDN;
try
{
targetDN = DN.decode(dnString);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
operation.setResponseData(de);
return;
}
DN rootDN = DirectoryServer.getActualRootBindDN(targetDN);
if (rootDN != null)
{
targetDN = rootDN;
}
Entry userEntry;
InternalClientConnection conn =
new InternalClientConnection(clientConnection.getAuthenticationInfo());
userEntry = searchUserEntry(conn, operation, targetDN);
if (userEntry == null)
{
return;
}
// Get the password policy state for the user entry.
PasswordPolicyState pwpState;
try
{
AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry,
false);
if (!policy.isPasswordPolicy())
{
operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
operation.appendErrorMessage(ERR_EXTOP_PWPSTATE_ACCOUNT_NOT_LOCAL
.get(String.valueOf(userEntry)));
return;
}
pwpState = (PasswordPolicyState) policy
.createAuthenticationPolicyState(userEntry);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
operation.setResponseData(de);
return;
}
PasswordPolicy policy = pwpState.getAuthenticationPolicy();
isAccountSetDisabled = false;
isAccountSetEnabled = false;
// Create a hash set that will be used to hold the types of the return
// types that should be included in the response.
boolean returnAll;
LinkedHashSet<Integer> returnTypes = new LinkedHashSet<Integer>();
try
{
if (!reader.hasNextElement())
{
// There is no operations sequence.
returnAll = true;
}
else if(reader.peekLength() <= 0)
{
// There is an operations sequence but its empty.
returnAll = true;
reader.readStartSequence();
reader.readEndSequence();
}
else
{
returnAll = false;
reader.readStartSequence();
while(reader.hasNextElement())
{
int opType;
ArrayList<String> opValues;
reader.readStartSequence();
opType = (int)reader.readInteger();
if (!reader.hasNextElement())
{
// There is no values sequence
opValues = null;
}
else if(reader.peekLength() <= 0)
{
// There is a values sequence but its empty
opValues = null;
reader.readStartSequence();
reader.readEndSequence();
}
else
{
reader.readStartSequence();
opValues = new ArrayList<String>();
while (reader.hasNextElement())
{
opValues.add(reader.readOctetStringAsString());
}
reader.readEndSequence();
}
reader.readEndSequence();
if(!processOp(opType, opValues, operation,
returnTypes, pwpState, policy))
{
return;
}
}
reader.readEndSequence();
}
reader.readEndSequence();
// If there are any modifications that need to be made to the password
// policy state, then apply them now.
List<Modification> stateMods = pwpState.getModifications();
if (stateMods != null && !stateMods.isEmpty())
{
ModifyOperation modifyOperation =
conn.processModify(targetDN, stateMods);
if (modifyOperation.getResultCode() != ResultCode.SUCCESS)
{
operation.setResultCode(modifyOperation.getResultCode());
operation.setErrorMessage(modifyOperation.getErrorMessage());
operation.setMatchedDN(modifyOperation.getMatchedDN());
operation.setReferralURLs(modifyOperation.getReferralURLs());
return;
}
// Retrieve the updated entry
userEntry = searchUserEntry(conn, operation, targetDN);
if (userEntry == null)
{
return;
}
// And it's updated password policy state
try
{
// We should not need to re-fetch the password policy.
pwpState = (PasswordPolicyState) policy
.createAuthenticationPolicyState(userEntry);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
operation.setResponseData(de);
return;
}
}
}
catch (Exception e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get(
e.getLocalizedMessage());
operation.appendErrorMessage(message);
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
return;
}
try
{
// Construct the sequence of values to return.
ByteString responseValue =
encodeResponse(dnString, returnAll, returnTypes, pwpState, policy);
operation.setResponseOID(OID_PASSWORD_POLICY_STATE_EXTOP);
operation.setResponseValue(responseValue);
operation.setResultCode(ResultCode.SUCCESS);
}
catch(Exception e)
{
// TODO: Need a better message
Message message = ERR_PWPSTATE_EXTOP_INVALID_OP_ENCODING.get(
e.getLocalizedMessage());
operation.appendErrorMessage(message);
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
}
// Post AccountStatus Notifications if needed.
if (isAccountSetDisabled)
{
pwpState.generateAccountStatusNotification(
AccountStatusNotificationType.ACCOUNT_DISABLED,
userEntry, INFO_MODIFY_ACCOUNT_DISABLED.get(),
AccountStatusNotification.createProperties(pwpState, false, -1,
null, null));
}
if (isAccountSetEnabled)
{
pwpState.generateAccountStatusNotification(
AccountStatusNotificationType.ACCOUNT_ENABLED,
userEntry, INFO_MODIFY_ACCOUNT_ENABLED.get(),
AccountStatusNotification.createProperties(pwpState, false, -1,
null, null));
}
}
/**
* Searches and returns the entry referenced by targetDN. If there's not
* exactly one entry found, an error is reported for the operation.
*
* @param conn The internal connection used to issue the search
* @param operation The extended operation being processed
* @param targetDN The DN targeted by this operation
*
* @return the Entry if one and only one is found, null otherwise
*/
private Entry searchUserEntry (InternalClientConnection conn,
ExtendedOperation operation,
DN targetDN)
{
Entry entry;
InternalSearchOperation internalSearch =
conn.processSearch(targetDN, SearchScope.BASE_OBJECT,
DereferencePolicy.NEVER_DEREF_ALIASES, 1, 0,
false, userFilter, requestAttributes, null);
if (internalSearch.getResultCode() != ResultCode.SUCCESS)
{
operation.setResultCode(internalSearch.getResultCode());
operation.setErrorMessage(internalSearch.getErrorMessage());
operation.setMatchedDN(internalSearch.getMatchedDN());
operation.setReferralURLs(internalSearch.getReferralURLs());
return null;
}
List<SearchResultEntry> matchingEntries = internalSearch.getSearchEntries();
if (matchingEntries.isEmpty())
{
operation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
return null;
}
else if (matchingEntries.size() > 1)
{
Message message = ERR_PWPSTATE_EXTOP_MULTIPLE_ENTRIES.get(
String.valueOf(targetDN));
operation.appendErrorMessage(message);
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return null;
}
else
{
entry = matchingEntries.get(0);
}
return entry;
}
/**
* Encodes the provided information in a form suitable for including in the
* response value.
*
* @param writer The ASN1Writer to use to encode.
* @param opType The operation type to use for the value.
* @param value The single value to include in the response.
*
* @throws IOException if an error occurs while encoding.
*/
public static void encode(ASN1Writer writer, int opType, String value)
throws IOException
{
writer.writeStartSequence();
writer.writeEnumerated(opType);
if (value != null)
{
writer.writeStartSequence();
writer.writeOctetString(value);
writer.writeEndSequence();
}
writer.writeEndSequence();
}
/**
* Encodes the provided information in a form suitable for including in the
* response value.
*
* @param writer The ASN1Writer to use to encode.
* @param opType The operation type to use for the value.
* @param values The set of string values to include in the response.
*
* @throws IOException if an error occurs while encoding.
*/
public static void encode(ASN1Writer writer, int opType, String[] values)
throws IOException
{
writer.writeStartSequence();
writer.writeEnumerated(opType);
if (values != null && values.length > 0)
{
writer.writeStartSequence();
for (String value : values)
{
writer.writeOctetString(value);
}
writer.writeEndSequence();
}
writer.writeEndSequence();
}
/**
* Encodes the provided information in a form suitable for including in the
* response value.
*
* @param writer The ASN1Writer to use to encode.
* @param opType The operation type to use for the value.
* @param values The set of timestamp values to include in the response.
*
* @throws IOException if an error occurs while encoding.
*/
public static void encode(ASN1Writer writer, int opType, List<Long> values)
throws IOException
{
writer.writeStartSequence();
writer.writeEnumerated(opType);
if (values != null && values.size() > 0)
{
writer.writeStartSequence();
for (long l : values)
{
writer.writeOctetString(GeneralizedTimeSyntax.format(l));
}
writer.writeEndSequence();
}
writer.writeEndSequence();
}
private ByteString encodeResponse(ByteString dnString, boolean returnAll,
LinkedHashSet<Integer> returnTypes,
PasswordPolicyState pwpState,
PasswordPolicy policy)
throws IOException
{
ByteStringBuilder builder = new ByteStringBuilder();
ASN1Writer writer = ASN1.getWriter(builder);
writer.writeStartSequence();
writer.writeOctetString(dnString);
writer.writeStartSequence();
if (returnAll || returnTypes.contains(OP_GET_PASSWORD_POLICY_DN))
{
encode(writer, OP_GET_PASSWORD_POLICY_DN,
policy.getDN().toString());
}
if (returnAll || returnTypes.contains(OP_GET_ACCOUNT_DISABLED_STATE))
{
encode(writer, OP_GET_ACCOUNT_DISABLED_STATE,
String.valueOf(pwpState.isDisabled()));
}
if (returnAll || returnTypes.contains(OP_GET_ACCOUNT_EXPIRATION_TIME))
{
String expTimeStr;
long expTime = pwpState.getAccountExpirationTime();
if (expTime < 0)
{
expTimeStr = null;
}
else
{
expTimeStr = GeneralizedTimeSyntax.format(expTime);
}
encode(writer, OP_GET_ACCOUNT_EXPIRATION_TIME, expTimeStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION))
{
String secondsStr = null;
long expTime = pwpState.getAccountExpirationTime();
if (expTime >= 0)
{
long seconds = (expTime - pwpState.getCurrentTime()) / 1000;
if (seconds > 0)
{
secondsStr = String.valueOf(seconds);
}
}
encode(writer, OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION,
secondsStr);
}
if (returnAll || returnTypes.contains(OP_GET_PASSWORD_CHANGED_TIME))
{
String timeStr;
long changedTime = pwpState.getPasswordChangedTime();
if (changedTime < 0)
{
timeStr = null;
}
else
{
timeStr = GeneralizedTimeSyntax.format(changedTime);
}
encode(writer, OP_GET_PASSWORD_CHANGED_TIME, timeStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME))
{
String timeStr;
long warnedTime = pwpState.getWarnedTime();
if (warnedTime < 0)
{
timeStr = null;
}
else
{
timeStr = GeneralizedTimeSyntax.format(warnedTime);
}
encode(writer, OP_GET_PASSWORD_EXPIRATION_WARNED_TIME, timeStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION))
{
String secondsStr;
int secondsUntilExp = pwpState.getSecondsUntilExpiration();
if (secondsUntilExp < 0)
{
secondsStr = null;
}
else
{
secondsStr = String.valueOf(secondsUntilExp);
}
encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION,
secondsStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING))
{
String secondsStr;
long secondsUntilExp = pwpState.getSecondsUntilExpiration();
if (secondsUntilExp < 0)
{
secondsStr = null;
}
else
{
long secondsUntilWarning = secondsUntilExp
- policy.getPasswordExpirationWarningInterval();
if (secondsUntilWarning <= 0)
{
secondsStr = "0";
}
else
{
secondsStr = String.valueOf(secondsUntilWarning);
}
}
encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING,
secondsStr);
}
if (returnAll || returnTypes.contains(OP_GET_AUTHENTICATION_FAILURE_TIMES))
{
encode(writer, OP_GET_AUTHENTICATION_FAILURE_TIMES,
pwpState.getAuthFailureTimes());
}
if (returnAll || returnTypes.contains(
OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK))
{
// We have to check whether the account is locked due to failures before
// we can get the length of time until the account is unlocked.
String secondsStr;
if (pwpState.lockedDueToFailures())
{
int seconds = pwpState.getSecondsUntilUnlock();
if (seconds <= 0)
{
secondsStr = null;
}
else
{
secondsStr = String.valueOf(seconds);
}
}
else
{
secondsStr = null;
}
encode(writer, OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK,
secondsStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT))
{
String remainingFailuresStr;
int allowedFailureCount = policy.getLockoutFailureCount();
if (allowedFailureCount > 0)
{
int remainingFailures =
allowedFailureCount - pwpState.getAuthFailureTimes().size();
if (remainingFailures < 0)
{
remainingFailures = 0;
}
remainingFailuresStr = String.valueOf(remainingFailures);
}
else
{
remainingFailuresStr = null;
}
encode(writer, OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT,
remainingFailuresStr);
}
if (returnAll || returnTypes.contains(OP_GET_LAST_LOGIN_TIME))
{
String timeStr;
long lastLoginTime = pwpState.getLastLoginTime();
if (lastLoginTime < 0)
{
timeStr = null;
}
else
{
timeStr = GeneralizedTimeSyntax.format(lastLoginTime);
}
encode(writer, OP_GET_LAST_LOGIN_TIME, timeStr);
}
if (returnAll || returnTypes.contains(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT))
{
String secondsStr;
long lockoutInterval = policy.getIdleLockoutInterval();
if (lockoutInterval > 0)
{
long lastLoginTime = pwpState.getLastLoginTime();
if (lastLoginTime < 0)
{
secondsStr = "0";
}
else
{
long lockoutTime = lastLoginTime + (lockoutInterval*1000);
long currentTime = pwpState.getCurrentTime();
int secondsUntilLockout = (int) ((lockoutTime - currentTime) / 1000L);
if (secondsUntilLockout <= 0)
{
secondsStr = "0";
}
else
{
secondsStr = String.valueOf(secondsUntilLockout);
}
}
}
else
{
secondsStr = null;
}
encode(writer, OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT, secondsStr);
}
if (returnAll || returnTypes.contains(OP_GET_PASSWORD_RESET_STATE))
{
encode(writer, OP_GET_PASSWORD_RESET_STATE,
String.valueOf(pwpState.mustChangePassword()));
}
if (returnAll ||
returnTypes.contains(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT))
{
String secondsStr;
if (pwpState.mustChangePassword())
{
long maxAge = policy.getMaxPasswordResetAge();
if (maxAge > 0)
{
long currentTime = pwpState.getCurrentTime();
long changedTime = pwpState.getPasswordChangedTime();
int changeAge = (int) ((currentTime - changedTime) / 1000L);
long timeToLockout = maxAge - changeAge;
if (timeToLockout <= 0)
{
secondsStr = "0";
}
else
{
secondsStr = String.valueOf(timeToLockout);
}
}
else
{
secondsStr = null;
}
}
else
{
secondsStr = null;
}
encode(writer, OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT,
secondsStr);
}
if (returnAll || returnTypes.contains(OP_GET_GRACE_LOGIN_USE_TIMES))
{
encode(writer, OP_GET_GRACE_LOGIN_USE_TIMES,
pwpState.getGraceLoginTimes());
}
if (returnAll || returnTypes.contains(OP_GET_REMAINING_GRACE_LOGIN_COUNT))
{
String remainingStr;
int remainingGraceLogins = pwpState.getGraceLoginsRemaining();
if (remainingGraceLogins <= 0)
{
remainingStr = "0";
}
else
{
remainingStr = String.valueOf(remainingGraceLogins);
}
encode(writer, OP_GET_REMAINING_GRACE_LOGIN_COUNT, remainingStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME))
{
String timeStr;
long requiredChangeTime = pwpState.getRequiredChangeTime();
if (requiredChangeTime < 0)
{
timeStr = null;
}
else
{
timeStr = GeneralizedTimeSyntax.format(requiredChangeTime);
}
encode(writer, OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME, timeStr);
}
if (returnAll ||
returnTypes.contains(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME))
{
String secondsStr;
long policyRequiredChangeTime = policy.getRequireChangeByTime();
if (policyRequiredChangeTime > 0)
{
long accountRequiredChangeTime = pwpState.getRequiredChangeTime();
if (accountRequiredChangeTime >= policyRequiredChangeTime)
{
secondsStr = null;
}
else
{
long currentTime = pwpState.getCurrentTime();
if (currentTime >= policyRequiredChangeTime)
{
secondsStr = "0";
}
else
{
secondsStr =
String.valueOf((policyRequiredChangeTime-currentTime) / 1000);
}
}
}
else
{
secondsStr = null;
}
encode(writer, OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME,
secondsStr);
}
if (returnAll || returnTypes.contains(OP_GET_PASSWORD_HISTORY))
{
encode(writer, OP_GET_PASSWORD_HISTORY,
pwpState.getPasswordHistoryValues());
}
writer.writeEndSequence();
writer.writeEndSequence();
return builder.toByteString();
}
private boolean processOp(int opType, ArrayList<String> opValues,
ExtendedOperation operation,
LinkedHashSet<Integer> returnTypes,
PasswordPolicyState pwpState,
PasswordPolicy policy)
{
switch (opType)
{
case OP_GET_PASSWORD_POLICY_DN:
returnTypes.add(OP_GET_PASSWORD_POLICY_DN);
break;
case OP_GET_ACCOUNT_DISABLED_STATE:
returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
break;
case OP_SET_ACCOUNT_DISABLED_STATE:
if (opValues == null)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_NO_DISABLED_VALUE.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
String value = opValues.get(0);
if ("true".equalsIgnoreCase(value))
{
pwpState.setDisabled(true);
isAccountSetDisabled = true;
}
else if ("false".equalsIgnoreCase(value))
{
pwpState.setDisabled(false);
isAccountSetEnabled = true;
}
else
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_DISABLED_VALUE.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
break;
case OP_CLEAR_ACCOUNT_DISABLED_STATE:
pwpState.setDisabled(false);
isAccountSetEnabled = true;
returnTypes.add(OP_GET_ACCOUNT_DISABLED_STATE);
break;
case OP_GET_ACCOUNT_EXPIRATION_TIME:
returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
break;
case OP_SET_ACCOUNT_EXPIRATION_TIME:
if (opValues == null)
{
pwpState.setAccountExpirationTime(pwpState.getCurrentTime());
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
pwpState.setAccountExpirationTime(time);
}
catch (DirectoryException de)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_ACCT_EXP_VALUE.get(
opValues.get(0),
de.getMessageObject()));
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
break;
case OP_CLEAR_ACCOUNT_EXPIRATION_TIME:
pwpState.clearAccountExpirationTime();
returnTypes.add(OP_GET_ACCOUNT_EXPIRATION_TIME);
break;
case OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION:
returnTypes.add(OP_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION);
break;
case OP_GET_PASSWORD_CHANGED_TIME:
returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
break;
case OP_SET_PASSWORD_CHANGED_TIME:
if (opValues == null)
{
pwpState.setPasswordChangedTime();
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
pwpState.setPasswordChangedTime(time);
}
catch (DirectoryException de)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_PWCHANGETIME_VALUE.get(
opValues.get(0),
de.getMessageObject()));
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
break;
case OP_CLEAR_PASSWORD_CHANGED_TIME:
pwpState.clearPasswordChangedTime();
returnTypes.add(OP_GET_PASSWORD_CHANGED_TIME);
break;
case OP_GET_PASSWORD_EXPIRATION_WARNED_TIME:
returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
break;
case OP_SET_PASSWORD_EXPIRATION_WARNED_TIME:
if (opValues == null)
{
pwpState.setWarnedTime();
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
pwpState.setWarnedTime(time);
}
catch (DirectoryException de)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_PWWARNEDTIME_VALUE.get(
opValues.get(0),
de.getMessageObject()));
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
break;
case OP_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME:
pwpState.clearWarnedTime();
returnTypes.add(OP_GET_PASSWORD_EXPIRATION_WARNED_TIME);
break;
case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION:
returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION);
break;
case OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING:
returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING);
break;
case OP_GET_AUTHENTICATION_FAILURE_TIMES:
returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
break;
case OP_ADD_AUTHENTICATION_FAILURE_TIME:
if (opValues == null)
{
if (policy.getLockoutFailureCount() == 0)
{
returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
break;
}
pwpState.updateAuthFailureTimes();
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_ADD_FAILURE_TIME_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
List<Long> authFailureTimes = pwpState.getAuthFailureTimes();
ArrayList<Long> newFailureTimes =
new ArrayList<Long>(authFailureTimes.size()+1);
newFailureTimes.addAll(authFailureTimes);
newFailureTimes.add(time);
pwpState.setAuthFailureTimes(newFailureTimes);
}
catch (DirectoryException de)
{
Message message = ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(
opValues.get(0),
de.getMessageObject());
operation.setResultCode(de.getResultCode());
operation.appendErrorMessage(message);
return false;
}
}
returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
break;
case OP_SET_AUTHENTICATION_FAILURE_TIMES:
if (opValues == null)
{
ArrayList<Long> valueList = new ArrayList<Long>(1);
valueList.add(pwpState.getCurrentTime());
pwpState.setAuthFailureTimes(valueList);
}
else
{
ArrayList<Long> valueList = new ArrayList<Long>(opValues.size());
for (String s : opValues)
{
try
{
valueList.add(
GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
ByteString.valueOf(s)));
}
catch (DirectoryException de)
{
Message message =
ERR_PWPSTATE_EXTOP_BAD_AUTH_FAILURE_TIME.get(
s,
de.getMessageObject());
operation.setResultCode(de.getResultCode());
operation.appendErrorMessage(message);
return false;
}
}
pwpState.setAuthFailureTimes(valueList);
}
returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
break;
case OP_CLEAR_AUTHENTICATION_FAILURE_TIMES:
pwpState.clearFailureLockout();
returnTypes.add(OP_GET_AUTHENTICATION_FAILURE_TIMES);
break;
case OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK:
returnTypes.add(OP_GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK);
break;
case OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT:
returnTypes.add(OP_GET_REMAINING_AUTHENTICATION_FAILURE_COUNT);
break;
case OP_GET_LAST_LOGIN_TIME:
returnTypes.add(OP_GET_LAST_LOGIN_TIME);
break;
case OP_SET_LAST_LOGIN_TIME:
if (opValues == null)
{
pwpState.setLastLoginTime();
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
pwpState.setLastLoginTime(time);
}
catch (DirectoryException de)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_LAST_LOGIN_TIME.get(
opValues.get(0),
de.getMessageObject()));
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_LAST_LOGIN_TIME);
break;
case OP_CLEAR_LAST_LOGIN_TIME:
pwpState.clearLastLoginTime();
returnTypes.add(OP_GET_LAST_LOGIN_TIME);
break;
case OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT:
returnTypes.add(OP_GET_SECONDS_UNTIL_IDLE_LOCKOUT);
break;
case OP_GET_PASSWORD_RESET_STATE:
returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
break;
case OP_SET_PASSWORD_RESET_STATE:
if (opValues == null)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_NO_RESET_STATE_VALUE.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
String value = opValues.get(0);
if ("true".equalsIgnoreCase(value))
{
pwpState.setMustChangePassword(true);
}
else if ("false".equalsIgnoreCase(value))
{
pwpState.setMustChangePassword(false);
}
else
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_RESET_STATE_VALUE.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
break;
case OP_CLEAR_PASSWORD_RESET_STATE:
pwpState.setMustChangePassword(false);
returnTypes.add(OP_GET_PASSWORD_RESET_STATE);
break;
case OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT:
returnTypes.add(OP_GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT);
break;
case OP_GET_GRACE_LOGIN_USE_TIMES:
returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
break;
case OP_ADD_GRACE_LOGIN_USE_TIME:
if (opValues == null)
{
pwpState.updateGraceLoginTimes();
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_ADD_GRACE_LOGIN_TIME_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
List<Long> authFailureTimes = pwpState.getGraceLoginTimes();
ArrayList<Long> newGraceTimes =
new ArrayList<Long>(authFailureTimes.size()+1);
newGraceTimes.addAll(authFailureTimes);
newGraceTimes.add(time);
pwpState.setGraceLoginTimes(newGraceTimes);
}
catch (DirectoryException de)
{
Message message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(
opValues.get(0),
de.getMessageObject());
operation.setResultCode(de.getResultCode());
operation.appendErrorMessage(message);
return false;
}
}
returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
break;
case OP_SET_GRACE_LOGIN_USE_TIMES:
if (opValues == null)
{
ArrayList<Long> valueList = new ArrayList<Long>(1);
valueList.add(pwpState.getCurrentTime());
pwpState.setGraceLoginTimes(valueList);
}
else
{
ArrayList<Long> valueList = new ArrayList<Long>(opValues.size());
for (String s : opValues)
{
try
{
valueList.add(
GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
ByteString.valueOf(s)));
}
catch (DirectoryException de)
{
Message message = ERR_PWPSTATE_EXTOP_BAD_GRACE_LOGIN_TIME.get(
s, de.getMessageObject());
operation.setResultCode(de.getResultCode());
operation.appendErrorMessage(message);
return false;
}
}
pwpState.setGraceLoginTimes(valueList);
}
returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
break;
case OP_CLEAR_GRACE_LOGIN_USE_TIMES:
pwpState.clearGraceLoginTimes();
returnTypes.add(OP_GET_GRACE_LOGIN_USE_TIMES);
break;
case OP_GET_REMAINING_GRACE_LOGIN_COUNT:
returnTypes.add(OP_GET_REMAINING_GRACE_LOGIN_COUNT);
break;
case OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
break;
case OP_SET_PASSWORD_CHANGED_BY_REQUIRED_TIME:
if (opValues == null)
{
pwpState.setRequiredChangeTime();
}
else if (opValues.size() != 1)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME_COUNT.get());
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
else
{
try
{
ByteString valueString =
ByteString.valueOf(opValues.get(0));
long time = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(
valueString);
pwpState.setRequiredChangeTime(time);
}
catch (DirectoryException de)
{
operation.appendErrorMessage(
ERR_PWPSTATE_EXTOP_BAD_REQUIRED_CHANGE_TIME.get(
opValues.get(0),
de.getMessageObject()));
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
}
returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
break;
case OP_CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME:
pwpState.clearRequiredChangeTime();
returnTypes.add(OP_GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
break;
case OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME:
returnTypes.add(OP_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME);
break;
case OP_GET_PASSWORD_HISTORY:
returnTypes.add(OP_GET_PASSWORD_HISTORY);
break;
case OP_CLEAR_PASSWORD_HISTORY:
pwpState.clearPasswordHistory();
returnTypes.add(OP_GET_PASSWORD_HISTORY);
break;
default:
operation.appendErrorMessage(ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE.get(
String.valueOf(opType)));
operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
return false;
}
return true;
}
/** {@inheritDoc} */
@Override
public String getExtendedOperationOID()
{
return OID_PASSWORD_POLICY_STATE_EXTOP;
}
/** {@inheritDoc} */
@Override
public String getExtendedOperationName()
{
return "Password Policy State";
}
}