001/*
002 * Copyright 2020-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2020-2022 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2020-2022 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds;
037
038
039
040import java.io.Serializable;
041import java.util.ArrayList;
042import java.util.Collections;
043import java.util.Date;
044import java.util.LinkedHashMap;
045import java.util.List;
046import java.util.Map;
047
048import com.unboundid.ldap.sdk.Entry;
049import com.unboundid.ldap.sdk.LDAPException;
050import com.unboundid.ldap.sdk.LDAPInterface;
051import com.unboundid.ldap.sdk.ResultCode;
052import com.unboundid.ldap.sdk.SearchResultEntry;
053import com.unboundid.ldap.sdk.unboundidds.controls.RecentLoginHistory;
054import com.unboundid.ldap.sdk.unboundidds.extensions.
055            PasswordPolicyStateAccountUsabilityError;
056import com.unboundid.ldap.sdk.unboundidds.extensions.
057            PasswordPolicyStateAccountUsabilityNotice;
058import com.unboundid.ldap.sdk.unboundidds.extensions.
059            PasswordPolicyStateAccountUsabilityWarning;
060import com.unboundid.ldap.sdk.unboundidds.extensions.
061            PasswordPolicyStateExtendedRequest;
062import com.unboundid.ldap.sdk.unboundidds.extensions.PasswordQualityRequirement;
063import com.unboundid.util.Debug;
064import com.unboundid.util.NotMutable;
065import com.unboundid.util.NotNull;
066import com.unboundid.util.Nullable;
067import com.unboundid.util.StaticUtils;
068import com.unboundid.util.ThreadSafety;
069import com.unboundid.util.ThreadSafetyLevel;
070import com.unboundid.util.json.JSONObject;
071import com.unboundid.util.json.JSONString;
072import com.unboundid.util.json.JSONValue;
073
074import static com.unboundid.ldap.sdk.unboundidds.PasswordPolicyStateJSONField.*;
075import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*;
076
077
078
079/**
080 * This class provides support for reading and decoding the value of the
081 * {@code ds-pwp-state-json} virtual attribute, which holds information about a
082 * user's password policy state.
083 * <BR>
084 * <BLOCKQUOTE>
085 *   <B>NOTE:</B>  This class, and other classes within the
086 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
087 *   supported for use against Ping Identity, UnboundID, and
088 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
089 *   for proprietary functionality or for external specifications that are not
090 *   considered stable or mature enough to be guaranteed to work in an
091 *   interoperable way with other types of LDAP servers.
092 * </BLOCKQUOTE>
093 *
094 *
095 * @see ModifiablePasswordPolicyStateJSON
096 * @see PasswordPolicyStateExtendedRequest
097 * @see PasswordPolicyStateJSONField
098 */
099@NotMutable()
100@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
101public final class PasswordPolicyStateJSON
102       implements Serializable
103{
104  /**
105   * The name of the operational attribute that holds a JSON representation of a
106   * user's password policy state.
107   */
108  @NotNull public static final String PASSWORD_POLICY_STATE_JSON_ATTRIBUTE =
109       "ds-pwp-state-json";
110
111
112
113  /**
114   * The name of the field that will be used to indicate whether a password
115   * quality requirement applies to add operations.
116   */
117  @NotNull private static final String REQUIREMENT_FIELD_APPLIES_TO_ADD =
118       "applies-to-add";
119
120
121
122  /**
123   * The name of the field that will be used to indicate whether a password
124   * quality requirement applies to administrative password resets.
125   */
126  @NotNull private static final String
127       REQUIREMENT_FIELD_APPLIES_TO_ADMIN_RESET =
128            "applies-to-administrative-reset";
129
130
131
132  /**
133   * The name of the field that will be used to indicate whether a password
134   * quality requirement applies to bind operations.
135   */
136  @NotNull private static final String REQUIREMENT_FIELD_APPLIES_TO_BIND =
137       "applies-to-bind";
138
139
140
141  /**
142   * The name of the field that will be used to indicate whether a password
143   * quality requirement applies to self password changes.
144   */
145  @NotNull private static final String
146       REQUIREMENT_FIELD_APPLIES_TO_SELF_CHANGE = "applies-to-self-change";
147
148
149
150  /**
151   * The name of the field that will be used to hold the set of client-side
152   * validation properties.
153   */
154  @NotNull private static final String
155       REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_PROPERTIES =
156       "client-side-validation-properties";
157
158
159
160  /**
161   * The name of the field that will be used to hold the name of a client-side
162   * validation property.
163   */
164  @NotNull private static final String
165       REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_PROPERTY_NAME = "name";
166
167
168
169  /**
170   * The name of the field that will be used to hold the value of a client-side
171   * validation property.
172   */
173  @NotNull private static final String
174       REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_PROPERTY_VALUE = "value";
175
176
177
178  /**
179   * The name of the field that will be used to hold the name of the client-side
180   * validation type for a password quality requirement.
181   */
182  @NotNull private static final String
183       REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_TYPE =
184            "client-side-validation-type";
185
186
187
188  /**
189   * The name of the field that will be used to hold the description component
190   * of a password quality requirement.
191   */
192  @NotNull private static final String REQUIREMENT_FIELD_DESCRIPTION =
193       "description";
194
195
196
197  /**
198   * The name of the field that will be used to hold the message component of an
199   * account usability error, warning, or notice.
200   */
201  @NotNull private static final String USABILITY_FIELD_MESSAGE = "message";
202
203
204
205  /**
206   * The name of the field that will be used to hold the integer version of
207   * the identifier for of an account usability error, warning, or notice.
208   */
209  @NotNull private static final String USABILITY_FIELD_TYPE_ID = "type-id";
210
211
212
213  /**
214   * The name of the field that will be used to hold the name of the identifier
215   * for of an account usability error, warning, or notice.
216   */
217  @NotNull private static final String USABILITY_FIELD_TYPE_NAME = "type-name";
218
219
220
221  /**
222   * The serial version UID for this serializable class.
223   */
224  private static final long serialVersionUID = -3953182526241789456L;
225
226
227
228
229  // The JSON object that contains the password policy state information.
230  @NotNull private final JSONObject passwordPolicyStateObject;
231
232
233
234  /**
235   * Creates a new instance of this object from the provided JSON object.
236   *
237   * @param  passwordPolicyStateObject  The JSON object containing the encoded
238   *                                    password policy state.
239   */
240  public PasswordPolicyStateJSON(
241       @NotNull final JSONObject passwordPolicyStateObject)
242  {
243    this.passwordPolicyStateObject = passwordPolicyStateObject;
244  }
245
246
247
248  /**
249   * Attempts to retrieve and decode the password policy state information for
250   * the specified user.
251   *
252   * @param  connection  The connection to use to communicate with the server.
253   *                     It must not be {@code null}, and it must be established
254   *                     and authenticated as an account with permission to
255   *                     access the target user's password policy state
256   *                     information.
257   * @param  userDN      The DN of the user for whom to retrieve the password
258   *                     policy state.  It must not be {@code null}.
259   *
260   * @return  The password policy state information for the specified user, or
261   *          {@code null} because no password policy state information is
262   *          available for the user.
263   *
264   * @throws  LDAPException  If a problem is encountered while trying to
265   *                         retrieve the user's entry or decode the password
266   *                         policy state JSON object.
267   */
268  @Nullable()
269  public static PasswordPolicyStateJSON get(
270                     @NotNull final LDAPInterface connection,
271                     @NotNull final String userDN)
272         throws LDAPException
273  {
274    final SearchResultEntry userEntry = connection.getEntry(userDN,
275         PASSWORD_POLICY_STATE_JSON_ATTRIBUTE);
276    if (userEntry == null)
277    {
278      throw new LDAPException(ResultCode.NO_SUCH_OBJECT,
279           ERR_PW_POLICY_STATE_JSON_GET_NO_SUCH_USER.get(userDN));
280    }
281
282    return get(userEntry);
283  }
284
285
286
287  /**
288   * Attempts to retrieve and decode the password policy state information from
289   * the provided user entry.
290   *
291   * @param  userEntry  The entry for the user for whom to obtain the password
292   *                    policy state information.  It must not be {@code null}.
293   *
294   * @return  The password policy state information from the provided user
295   *          entry, or {@code null} if no password policy state information is
296   *          available for the user.
297   *
298   * @throws  LDAPException  If a problem is encountered while trying to decode
299   *                         the password policy state JSON object.
300   */
301  @Nullable()
302  public static PasswordPolicyStateJSON get(@NotNull final Entry userEntry)
303         throws LDAPException
304  {
305    final String valueString =
306         userEntry.getAttributeValue(PASSWORD_POLICY_STATE_JSON_ATTRIBUTE);
307    if (valueString == null)
308    {
309      return null;
310    }
311
312    final JSONObject jsonObject;
313    try
314    {
315      jsonObject = new JSONObject(valueString);
316    }
317    catch (final Exception e)
318    {
319      Debug.debugException(e);
320      throw new LDAPException(ResultCode.DECODING_ERROR,
321           ERR_PW_POLICY_STATE_JSON_GET_CANNOT_DECODE.get(
322                PASSWORD_POLICY_STATE_JSON_ATTRIBUTE, userEntry.getDN()),
323           e);
324    }
325
326    return new PasswordPolicyStateJSON(jsonObject);
327  }
328
329
330
331  /**
332   * Retrieves the JSON object that contains the encoded password policy state
333   * information.
334   *
335   * @return  The JSON object that contains the encoded password policy state
336   *          information.
337   */
338  @NotNull()
339  public JSONObject getPasswordPolicyStateJSONObject()
340  {
341    return passwordPolicyStateObject;
342  }
343
344
345
346  /**
347   * Retrieves the DN of the entry that defines the password policy that governs
348   * the associated user.
349   *
350   * @return  The DN of the entry that defines hte password policy that governs
351   *          the associated user, or {@code null} if this was not included in
352   *          the password policy state JSON object.
353   */
354  @Nullable()
355  public String getPasswordPolicyDN()
356  {
357    return passwordPolicyStateObject.getFieldAsString(
358         PASSWORD_POLICY_DN.getFieldName());
359  }
360
361
362
363  /**
364   * Retrieves the value of a flag that indicates whether the user's account is
365   * in a state that the server considers usable.
366   *
367   * @return  {@code Boolean.TRUE} if the account is in a usable state,
368   *          {@code Boolean.FALSE} if the account is not in a usable state, or
369   *          {@code null} if this flag was not included in the password policy
370   *          state JSON object.
371   */
372  @Nullable()
373  public Boolean getAccountIsUsable()
374  {
375    return passwordPolicyStateObject.getFieldAsBoolean(
376         ACCOUNT_IS_USABLE.getFieldName());
377  }
378
379
380
381  /**
382   * Retrieves a list of information about any error conditions that may
383   * affect usability of the user's account.
384   *
385   * @return  A list of information about any error conditions that may affect
386   *          the usability of the user's account.  The returned list may be
387   *          empty if there are no account usability errors or if this was not
388   *          included in the password policy state JSON object.
389   */
390  @NotNull()
391  public List<PasswordPolicyStateAccountUsabilityError>
392              getAccountUsabilityErrors()
393  {
394    final List<PasswordPolicyStateAccountUsabilityError> errors =
395         new ArrayList<>();
396    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
397         ACCOUNT_USABILITY_ERRORS.getFieldName());
398    if (values != null)
399    {
400      for (final JSONValue v : values)
401      {
402        if (v instanceof JSONObject)
403        {
404          final JSONObject o = (JSONObject) v;
405          final String typeName = o.getFieldAsString(USABILITY_FIELD_TYPE_NAME);
406          final Integer typeID = o.getFieldAsInteger(USABILITY_FIELD_TYPE_ID);
407          final String message = o.getFieldAsString(USABILITY_FIELD_MESSAGE);
408          if ((typeName != null) && (typeID != null))
409          {
410            errors.add(new PasswordPolicyStateAccountUsabilityError(typeID,
411                 typeName, message));
412          }
413        }
414      }
415    }
416
417    return Collections.unmodifiableList(errors);
418  }
419
420
421
422  /**
423   * Retrieves a list of information about any warning conditions that may soon
424   * affect usability of the user's account.
425   *
426   * @return  A list of information about any warning conditions that may soon
427   *          affect the usability of the user's account.  The returned list may
428   *          be empty if there are no account usability warnings or if this was
429   *          not included in the password policy state JSON object.
430   */
431  @NotNull()
432  public List<PasswordPolicyStateAccountUsabilityWarning>
433              getAccountUsabilityWarnings()
434  {
435    final List<PasswordPolicyStateAccountUsabilityWarning> warnings =
436         new ArrayList<>();
437    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
438         ACCOUNT_USABILITY_WARNINGS.getFieldName());
439    if (values != null)
440    {
441      for (final JSONValue v : values)
442      {
443        if (v instanceof JSONObject)
444        {
445          final JSONObject o = (JSONObject) v;
446          final String typeName = o.getFieldAsString(USABILITY_FIELD_TYPE_NAME);
447          final Integer typeID = o.getFieldAsInteger(USABILITY_FIELD_TYPE_ID);
448          final String message = o.getFieldAsString(USABILITY_FIELD_MESSAGE);
449          if ((typeName != null) && (typeID != null))
450          {
451            warnings.add(new PasswordPolicyStateAccountUsabilityWarning(typeID,
452                 typeName, message));
453          }
454        }
455      }
456    }
457
458    return Collections.unmodifiableList(warnings);
459  }
460
461
462
463  /**
464   * Retrieves a list of information about any notices related to the usability
465   * of the user's account.
466   *
467   * @return  A list of information about any notices related to the usability
468   *          of the user's account.  The returned list may be empty if there
469   *          are no account usability notices or if this was not included in
470   *          the password policy state JSON object.
471   */
472  @NotNull()
473  public List<PasswordPolicyStateAccountUsabilityNotice>
474              getAccountUsabilityNotices()
475  {
476    final List<PasswordPolicyStateAccountUsabilityNotice> notices =
477         new ArrayList<>();
478    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
479         ACCOUNT_USABILITY_NOTICES.getFieldName());
480    if (values != null)
481    {
482      for (final JSONValue v : values)
483      {
484        if (v instanceof JSONObject)
485        {
486          final JSONObject o = (JSONObject) v;
487          final String typeName = o.getFieldAsString(USABILITY_FIELD_TYPE_NAME);
488          final Integer typeID = o.getFieldAsInteger(USABILITY_FIELD_TYPE_ID);
489          final String message = o.getFieldAsString(USABILITY_FIELD_MESSAGE);
490          if ((typeName != null) && (typeID != null))
491          {
492            notices.add(new PasswordPolicyStateAccountUsabilityNotice(typeID,
493                 typeName, message));
494          }
495        }
496      }
497    }
498
499    return Collections.unmodifiableList(notices);
500  }
501
502
503
504  /**
505   * Retrieves the value of a flag that indicates whether the user's account
506   * contains at least one static password.
507   *
508   * @return  {@code Boolean.TRUE} if the account has at least one static
509   *          password, {@code Boolean.FALSE} if the account does not have any
510   *          static password, or {@code null} if this flag was not included in
511   *          the password policy state JSON object.
512   */
513  @Nullable()
514  public Boolean getHasStaticPassword()
515  {
516    return passwordPolicyStateObject.getFieldAsBoolean(
517         HAS_STATIC_PASSWORD.getFieldName());
518  }
519
520
521
522  /**
523   * Retrieves the time that the user's password was last changed.
524   *
525   * @return  The time that the user's password was last changed, or
526   *          {@code null} if this was not included in the password policy state
527   *          JSON object.
528   */
529  @Nullable()
530  public Date getPasswordChangedTime()
531  {
532    return getDate(PASSWORD_CHANGED_TIME);
533  }
534
535
536
537  /**
538   * Retrieves the length of time in seconds that has passed since the user's
539   * password was last changed.
540   *
541   * @return  The length of time in seconds that has passed since the user's
542   *          password was last changed, or {@code null} if this was not
543   *          included in the password policy state JSON object.
544   */
545  @Nullable()
546  public Integer getSecondsSincePasswordChange()
547  {
548    return passwordPolicyStateObject.getFieldAsInteger(
549         SECONDS_SINCE_PASSWORD_CHANGE.getFieldName());
550  }
551
552
553
554  /**
555   * Retrieves the value of a flag that indicates whether the user's account has
556   * been administratively disabled.
557   *
558   * @return  {@code Boolean.TRUE} if the account has been administratively
559   *          disabled, {@code Boolean.FALSE} if the account has not been
560   *          administratively disabled, or {@code null} if this flag was not
561   *          included in the password policy state JSON object.
562   */
563  @Nullable()
564  public Boolean getAccountIsDisabled()
565  {
566    return passwordPolicyStateObject.getFieldAsBoolean(
567         ACCOUNT_IS_DISABLED.getFieldName());
568  }
569
570
571
572  /**
573   * Retrieves the value of a flag that indicates whether the user's account is
574   * not yet active because it has an activation time that is in the future.
575   *
576   * @return  {@code Boolean.TRUE} if the account is not yet active,
577   *          {@code Boolean.FALSE} if the account either does not have an
578   *          activation time or if that time has already passed, or
579   *          {@code null} if this flag was not included in the password policy
580   *          state JSON object.
581   */
582  @Nullable()
583  public Boolean getAccountIsNotYetActive()
584  {
585    return passwordPolicyStateObject.getFieldAsBoolean(
586         ACCOUNT_IS_NOT_YET_ACTIVE.getFieldName());
587  }
588
589
590
591  /**
592   * Retrieves the time that the user's account became (or will become) active.
593   *
594   * @return  The time that the user's account became (or will become) active,
595   *          or {@code null} if this was not included in the password policy
596   *          state JSON object.
597   */
598  @Nullable()
599  public Date getAccountActivationTime()
600  {
601    return getDate(ACCOUNT_ACTIVATION_TIME);
602  }
603
604
605
606  /**
607   * Retrieves the length of time in seconds until the user's account will
608   * become active.
609   *
610   * @return  The length of time in seconds until the user's account will become
611   *          active, or {@code null} if this was not included in the password
612   *          policy state JSON object (e.g., because the user does not have an
613   *          activation time in the future).
614   */
615  @Nullable()
616  public Integer getSecondsUntilAccountActivation()
617  {
618    return passwordPolicyStateObject.getFieldAsInteger(
619         SECONDS_UNTIL_ACCOUNT_ACTIVATION.getFieldName());
620  }
621
622
623
624  /**
625   * Retrieves the length of time in seconds since the user's account became
626   * active.
627   *
628   * @return  The length of time in seconds since the user's account became
629   *          active, or {@code null} if this was not included in the password
630   *          policy state JSON object (e.g., because the user does not have an
631   *          activation time in the past).
632   */
633  @Nullable()
634  public Integer getSecondsSinceAccountActivation()
635  {
636    return passwordPolicyStateObject.getFieldAsInteger(
637         SECONDS_SINCE_ACCOUNT_ACTIVATION.getFieldName());
638  }
639
640
641
642  /**
643   * Retrieves the value of a flag that indicates whether the user's account is
644   * expired.
645   *
646   * @return  {@code Boolean.TRUE} if the account is expired,
647   *          {@code Boolean.FALSE} if the account is not expired, or
648   *          {@code null} if this flag was not included in the password policy
649   *          state JSON object.
650   */
651  @Nullable()
652  public Boolean getAccountIsExpired()
653  {
654    return passwordPolicyStateObject.getFieldAsBoolean(
655         ACCOUNT_IS_EXPIRED.getFieldName());
656  }
657
658
659
660  /**
661   * Retrieves the time that the user's account will (or did) expire.
662   *
663   * @return  The time that the user's account will (or did) expire, or
664   *          {@code null} if this was not included in the password policy state
665   *          JSON object.
666   */
667  @Nullable()
668  public Date getAccountExpirationTime()
669  {
670    return getDate(ACCOUNT_EXPIRATION_TIME);
671  }
672
673
674
675  /**
676   * Retrieves the length of time in seconds until the user's account will
677   * expire.
678   *
679   * @return  The length of time in seconds until the user's account will
680   *          expire, or {@code null} if this was not included in the password
681   *          policy state JSON object (e.g., because the user does not have an
682   *          expiration time in the future).
683   */
684  @Nullable()
685  public Integer getSecondsUntilAccountExpiration()
686  {
687    return passwordPolicyStateObject.getFieldAsInteger(
688         SECONDS_UNTIL_ACCOUNT_EXPIRATION.getFieldName());
689  }
690
691
692
693  /**
694   * Retrieves the length of time in seconds since the user's account expired.
695   *
696   * @return  The length of time in seconds since the user's account expired,
697   *          or {@code null} if this was not included in the password policy
698   *          state JSON object (e.g., because the user does not have an
699   *          expiration time in the past).
700   */
701  @Nullable()
702  public Integer getSecondsSinceAccountExpiration()
703  {
704    return passwordPolicyStateObject.getFieldAsInteger(
705         SECONDS_SINCE_ACCOUNT_EXPIRATION.getFieldName());
706  }
707
708
709
710  /**
711   * Retrieves the value of a flag that indicates whether the user's password is
712   * expired.
713   *
714   * @return  {@code Boolean.TRUE} if the password is expired,
715   *          {@code Boolean.FALSE} if the password is not expired, or
716   *          {@code null} if this flag was not included in the password policy
717   *          state JSON object.
718   */
719  @Nullable()
720  public Boolean getPasswordIsExpired()
721  {
722    return passwordPolicyStateObject.getFieldAsBoolean(
723         PASSWORD_IS_EXPIRED.getFieldName());
724  }
725
726
727
728  /**
729   * Retrieves the maximum length of time in seconds after a password change
730   * that the user is allowed to keep using that password.
731   *
732   * @return  The maximum length of time in seconds after a password change that
733   *          the user is allowed to keep using that password, or {@code null}
734   *          if this flag was not included in the password policy state JSON
735   *          object (e.g., because password expiration is not configured in the
736   *          password policy that governs the user).
737   */
738  @Nullable()
739  public Integer getMaximumPasswordAgeSeconds()
740  {
741    return passwordPolicyStateObject.getFieldAsInteger(
742         MAXIMUM_PASSWORD_AGE_SECONDS.getFieldName());
743  }
744
745
746
747  /**
748   * Retrieves the time that the user's password will (or did) expire.
749   *
750   * @return  The time that the user's password will (or did) expire, or
751   *          {@code null} if this was not included in the password policy state
752   *          JSON object (e.g., because password expiration is not configured
753   *          in the password policy that governs the user).
754   */
755  @Nullable()
756  public Date getPasswordExpirationTime()
757  {
758    return getDate(PASSWORD_EXPIRATION_TIME);
759  }
760
761
762
763  /**
764   * Retrieves the length of time in seconds until the user's password will
765   * expire.
766   *
767   * @return  The length of time in seconds until the user's password will
768   *          expire, or {@code null} if this was not included in the password
769   *          policy state JSON object (e.g., because password expiration is not
770   *          configured in the password policy that governs the user, or
771   *          because the user's password is already expired).
772   */
773  @Nullable()
774  public Integer getSecondsUntilPasswordExpiration()
775  {
776    return passwordPolicyStateObject.getFieldAsInteger(
777         SECONDS_UNTIL_PASSWORD_EXPIRATION.getFieldName());
778  }
779
780
781
782  /**
783   * Retrieves the length of time in seconds since the user's password expired.
784   *
785   * @return  The length of time in seconds since the user's password expired,
786   *          or {@code null} if this was not included in the password policy
787   *          state JSON object (e.g., because password expiration is not
788   *          configured in the password policy that governs the user, or
789   *          because the user's password is not expired).
790   */
791  @Nullable()
792  public Integer getSecondsSincePasswordExpiration()
793  {
794    return passwordPolicyStateObject.getFieldAsInteger(
795         SECONDS_SINCE_PASSWORD_EXPIRATION.getFieldName());
796  }
797
798
799
800  /**
801   * Retrieves the length of time in seconds before an upcoming password
802   * expiration that the user will be eligible to start receving warnings about
803   * that expiration.
804   *
805   * @return  The length of time in seconds before an upcoming password
806   *          expiration that the user will be eligible to start receiving
807   *          messages about that expiration, or {@code null} if this was not
808   *          included in the password policy state JSON object (e.g., because
809   *          password expiration is not configured in the password policy that
810   *          governs the user).
811   */
812  @Nullable()
813  public Integer getPasswordExpirationWarningIntervalSeconds()
814  {
815    return passwordPolicyStateObject.getFieldAsInteger(
816         PASSWORD_EXPIRATION_WARNING_INTERVAL_SECONDS.getFieldName());
817  }
818
819
820
821  /**
822   * Retrieves the value of a flag that indicates whether the server will allow
823   * a user's password to expire even if they have not yet received any warnings
824   * about an upcoming expiration.
825   *
826   * @return  {@code Boolean.TRUE} if the server will allow a user's password to
827   *          expire even if they have not been warned about an upcoming
828   *          expiration, {@code Boolean.FALSE} if the server will ensure that
829   *          the user receives at least one warning before expiring the
830   *          password, or {@code null} if this flag was not included in the
831   *          password policy state JSON object (e.g., because password
832   *          expiration is not configured in the password policy that governs
833   *          the user).
834   */
835  @Nullable()
836  public Boolean getExpirePasswordsWithoutWarning()
837  {
838    return passwordPolicyStateObject.getFieldAsBoolean(
839         EXPIRE_PASSWORDS_WITHOUT_WARNING.getFieldName());
840  }
841
842
843
844  /**
845   * Retrieves the value of a flag that indicates whether the user has
846   * received at least one warning about an upcoming password expiration.
847   *
848   * @return  {@code Boolean.TRUE} if the user has received at least one warning
849   *          about an upcoming password expiration, {@code Boolean.FALSE} if
850   *          the user has not been warned about an upcoming password
851   *          expiration, or {@code null} if this flag was not included in the
852   *          password policy state JSON object (e.g., because password
853   *          expiration is not configured in the password policy that governs
854   *          the user).
855   */
856  @Nullable()
857  public Boolean getPasswordExpirationWarningIssued()
858  {
859    return passwordPolicyStateObject.getFieldAsBoolean(
860         PASSWORD_EXPIRATION_WARNING_ISSUED.getFieldName());
861  }
862
863
864
865  /**
866   * Retrieves the time that the user will be eligible to receive (or the time
867   * that the user first received) a warning about an upcoming password
868   * expiration.
869   *
870   * @return  The time that the user will be eligible to receive (or the time
871   *          that the user first received) a warning about an upcoming password
872   *          expiration, or {@code null} if this was not included in the
873   *          password policy state JSON object (e.g., because password
874   *          expiration is not configured in the password policy that governs
875   *          the user).
876   */
877  @Nullable()
878  public Date getPasswordExpirationWarningTime()
879  {
880    return getDate(PASSWORD_EXPIRATION_WARNING_TIME);
881  }
882
883
884
885  /**
886   * Retrieves the length of time in seconds until the user will be eligible to
887   * receive a warning about an upcoming password expiration.
888   *
889   * @return  The length of time in seconds until the user will be eligible to
890   *          receive a warning about an upcoming password expiration, or
891   *          {@code null} if this was not included in the password policy state
892   *          JSON object (e.g., because password expiration is not configured
893   *          in the password policy that governs the user, or because the user
894   *          has already been warned about an upcoming expiration).
895   */
896  @Nullable()
897  public Integer getSecondsUntilPasswordExpirationWarning()
898  {
899    return passwordPolicyStateObject.getFieldAsInteger(
900         SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING.getFieldName());
901  }
902
903
904
905  /**
906   * Retrieves the length of time in seconds since the user received the first
907   * warning about an upcoming password expiration.
908   *
909   * @return  The length of time in seconds since the user received the first
910   *          warning about an upcoming password expiration, or {@code null} if
911   *          this was not included in the password policy state JSON object
912   *          (e.g., because password expiration is not configured in the
913   *          password policy that governs the user, or because the user has
914   *          not yet been warned about an upcoming expiration).
915   */
916  @Nullable()
917  public Integer getSecondsSincePasswordExpirationWarning()
918  {
919    return passwordPolicyStateObject.getFieldAsInteger(
920         SECONDS_SINCE_PASSWORD_EXPIRATION_WARNING.getFieldName());
921  }
922
923
924
925  /**
926   * Retrieves the value of a flag that indicates whether the user account is
927   * currently locked as a result of too many failed authentication attempts.
928   *
929   * @return  {@code Boolean.TRUE} if the user account is locked as a result of
930   *          too many failed authentication attempts, {@code Boolean.FALSE} if
931   *          the user account is not locked because of too many failed
932   *          authentication attempts, or {@code null} if this flag was not
933   *          included in the password policy state JSON object.
934   */
935  @Nullable()
936  public Boolean getAccountIsFailureLocked()
937  {
938    return passwordPolicyStateObject.getFieldAsBoolean(
939         ACCOUNT_IS_FAILURE_LOCKED.getFieldName());
940  }
941
942
943
944  /**
945   * Retrieves the number of consecutive failed authentication attempts that are
946   * required to lock the user's account.
947   *
948   * @return  The number of consecutive failed authentication attempts that are
949   *          required to lock the user's account, or {@code null} if this was
950   *          not included in the password policy state JSON object (e.g.,
951   *          because account lockout is not configured in the password policy
952   *          that governs the user).
953   */
954  @Nullable()
955  public Integer getFailureLockoutCount()
956  {
957    return passwordPolicyStateObject.getFieldAsInteger(
958         FAILURE_LOCKOUT_COUNT.getFieldName());
959  }
960
961
962
963  /**
964   * Retrieves the current number of failed authentication attempts for the
965   * user account.
966   *
967   * @return  The current number of failed authentication attempts for the user
968   *          account, or {@code null} if this was not included in the password
969   *          policy state JSON object (e.g., because account lockout is not
970   *          configured in the password policy that governs the user).
971   */
972  @Nullable()
973  public Integer getCurrentAuthenticationFailureCount()
974  {
975    return passwordPolicyStateObject.getFieldAsInteger(
976         CURRENT_AUTHENTICATION_FAILURE_COUNT.getFieldName());
977  }
978
979
980
981  /**
982   * Retrieves the remaining number of failed authentication attempts required
983   * to lock the user account.
984   *
985   * @return  The remaining number of failed authentication attempts required to
986   *          lock the user account, or {@code null} if this was not included in
987   *          the password policy state JSON object (e.g., because account
988   *          lockout is not configured in the password policy that governs the
989   *          user).
990   */
991  @Nullable()
992  public Integer getRemainingAuthenticationFailureCount()
993  {
994    return passwordPolicyStateObject.getFieldAsInteger(
995         REMAINING_AUTHENTICATION_FAILURE_COUNT.getFieldName());
996  }
997
998
999
1000  /**
1001   * Retrieves a list of the outstanding authentication failure times for the
1002   * user account.
1003   *
1004   * @return  A list of the outstanding authentication failure times for the
1005   *          user account, or an empty list if there are no outstanding
1006   *          authentication failures or if this was not included in the
1007   *          password policy state JSON object (e.g., because account lockout
1008   *          is not configured in the password policy that governs the user).
1009   */
1010  @NotNull()
1011  public List<Date> getAuthenticationFailureTimes()
1012  {
1013    final List<Date> authFailureTimes = new ArrayList<>();
1014
1015    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
1016         AUTHENTICATION_FAILURE_TIMES.getFieldName());
1017    if (values != null)
1018    {
1019      for (final JSONValue v : values)
1020      {
1021        try
1022        {
1023          final String valueString = ((JSONString) v).stringValue();
1024          authFailureTimes.add(StaticUtils.decodeRFC3339Time(valueString));
1025        }
1026        catch (final Exception e)
1027        {
1028          Debug.debugException(e);
1029        }
1030      }
1031    }
1032
1033    return Collections.unmodifiableList(authFailureTimes);
1034  }
1035
1036
1037
1038  /**
1039   * Retrieves the time that the user's account was locked as a result of too
1040   * many failed authentication attempts.
1041   *
1042   * @return  The time that the user's account was locked as a result of too
1043   *          many failed authentication attempts, or {@code null} if this was
1044   *          not included in the password policy state JSON object (e.g.,
1045   *          because the user's account is not failure locked).
1046   */
1047  @Nullable()
1048  public Date getFailureLockoutTime()
1049  {
1050    return getDate(FAILURE_LOCKOUT_TIME);
1051  }
1052
1053
1054
1055  /**
1056   * Retrieves the length of time in seconds that a user's account will be
1057   * locked after too many failed authentication attempts.
1058   *
1059   * @return  The length of time in seconds that a user's account will be
1060   *          locked after too many failed authentication attempts, or
1061   *          {@code null} if this was not included in the password policy state
1062   *          JSON object (e.g., because account lockout is not configured in
1063   *          the password policy that governs the user, or because account
1064   *          lockout is not temporary).
1065   */
1066  @Nullable()
1067  public Integer getFailureLockoutDurationSeconds()
1068  {
1069    return passwordPolicyStateObject.getFieldAsInteger(
1070         FAILURE_LOCKOUT_DURATION_SECONDS.getFieldName());
1071
1072  }
1073
1074
1075
1076  /**
1077   * Retrieves the time that the user's failure-locked account will be
1078   * automatically unlocked.
1079   *
1080   * @return  The time that the user's failure-locked account will be
1081   *          automatically unlocked, or {@code null} if this was not included
1082   *          in the password policy state JSON object (e.g., because the user's
1083   *          account is not failure locked, or because the lockout is not
1084   *          temporary).
1085   */
1086  @Nullable()
1087  public Date getFailureLockoutExpirationTime()
1088  {
1089    return getDate(FAILURE_LOCKOUT_EXPIRATION_TIME);
1090  }
1091
1092
1093
1094  /**
1095   * Retrieves the length of time in seconds remaining until the user's
1096   * failure-locked account will be automatically unlocked.
1097   *
1098   * @return  The length of time in seconds remaining until the user's
1099   *          failure-locked account will be automatically unlocked, or
1100   *          {@code null} if this was not included in the password policy state
1101   *          JSON object (e.g., because the user's account is not failure
1102   *          locked, or because the lockout is not temporary).
1103   */
1104  @Nullable()
1105  public Integer getSecondsRemainingInFailureLockout()
1106  {
1107    return passwordPolicyStateObject.getFieldAsInteger(
1108         SECONDS_REMAINING_IN_FAILURE_LOCKOUT.getFieldName());
1109  }
1110
1111
1112
1113  /**
1114   * Retrieves the time that the user last successfully authenticated to the
1115   * server.
1116   *
1117   * @return  The time that the user last successfully authenticated to the
1118   *          server, or {@code null} if this was not included in the password
1119   *          policy state JSON object (e.g., because last login time tracking
1120   *          is not configured in the password policy that governs the user).
1121   */
1122  @Nullable()
1123  public Date getLastLoginTime()
1124  {
1125    return getDate(LAST_LOGIN_TIME);
1126  }
1127
1128
1129
1130  /**
1131   * Retrieves the length of time in seconds since the user last successfully
1132   * authenticated to the server.
1133   *
1134   * @return  The length of time in seconds since the user last successfully
1135   *          authenticated to the server, or {@code null} if this was not
1136   *          included in the password policy state JSON object (e.g., because
1137   *          last login time tracking is not configured in the password policy
1138   *          that governs the user).
1139   */
1140  @Nullable()
1141  public Integer getSecondsSinceLastLogin()
1142  {
1143    return passwordPolicyStateObject.getFieldAsInteger(
1144         SECONDS_SINCE_LAST_LOGIN.getFieldName());
1145  }
1146
1147
1148
1149  /**
1150   * Retrieves the IP address of the client from which the user last
1151   * successfully authenticated.
1152   *
1153   * @return  The IP address of the client from which the user last successfully
1154   *          authenticated, or {@code null} if this was not included in the
1155   *          password policy state JSON object (e.g., because last login IP
1156   *          address tracking is not configured in the password policy that
1157   *          governs the user).
1158   */
1159  @Nullable()
1160  public String getLastLoginIPAddress()
1161  {
1162    return passwordPolicyStateObject.getFieldAsString(
1163         LAST_LOGIN_IP_ADDRESS.getFieldName());
1164  }
1165
1166
1167
1168  /**
1169   * Retrieves the value of a flag that indicates whether the user's account is
1170   * currently locked because it has been too long since they last authenticated
1171   * to the server.
1172   *
1173   * @return  {@code Boolean.TRUE} if the user's account is currently
1174   *          idle-locked, {@code Boolean.FALSE} if the user's account is not
1175   *          currently idle-locked, or {@code null} if this flag was not
1176   *          included in the password policy state JSON object.
1177   */
1178  @Nullable()
1179  public Boolean getAccountIsIdleLocked()
1180  {
1181    return passwordPolicyStateObject.getFieldAsBoolean(
1182         ACCOUNT_IS_IDLE_LOCKED.getFieldName());
1183  }
1184
1185
1186
1187  /**
1188   * Retrieves the maximum length of time in seconds that can elapse between
1189   * successful authentications before the user's account is locked.
1190   *
1191   * @return  The maximum length of time in seconds that can elapse between
1192   *          successful authentications before the user's account is locked, or
1193   *          {@code null} if this was not included in the password policy state
1194   *          JSON object (e.g., because idle lockout is not configured in the
1195   *          password policy that governs the user).
1196   */
1197  @Nullable()
1198  public Integer getIdleLockoutIntervalSeconds()
1199  {
1200    return passwordPolicyStateObject.getFieldAsInteger(
1201         IDLE_LOCKOUT_INTERVAL_SECONDS.getFieldName());
1202  }
1203
1204
1205
1206  /**
1207   * Retrieves the time that the user's account will be (or was) locked for
1208   * allowing too much time to elapse between successful authentications.
1209   *
1210   * @return  The time that the user's account will be (or was) locked for
1211   *          allowing too much time to elapse between successful
1212   *          authentications, or {@code null} if this was not included in the
1213   *          password policy state JSON object (e.g., because idle lockout is
1214   *          not configured in the password policy that governs the user).
1215   */
1216  @Nullable()
1217  public Date getIdleLockoutTime()
1218  {
1219    return getDate(IDLE_LOCKOUT_TIME);
1220  }
1221
1222
1223
1224  /**
1225   * Retrieves the length of time in seconds until the user's account will be
1226   * locked for allowing too much time to elapse between successful
1227   * authentications.
1228   *
1229   * @return  The length of time in seconds until the user's account will be
1230   *          locked for allowing too much time to elapse between successful
1231   *          authentication, or {@code null} if this was not included in the
1232   *          password policy state JSON object (e.g., because idle lockout is
1233   *          not configured in the password policy that governs the user, or
1234   *          because the user's account is already idle-locked).
1235   */
1236  @Nullable()
1237  public Integer getSecondsUntilIdleLockout()
1238  {
1239    return passwordPolicyStateObject.getFieldAsInteger(
1240         SECONDS_UNTIL_IDLE_LOCKOUT.getFieldName());
1241  }
1242
1243
1244
1245  /**
1246   * Retrieves the length of time in seconds since the user's account was
1247   * locked for allowing too much time to elapse between successful
1248   * authentications.
1249   *
1250   * @return  The length of time in seconds since the user's account was locked
1251   *          for allowing too much time to elapse between successful
1252   *          authentication, or {@code null} if this was not included in the
1253   *          password policy state JSON object (e.g., because idle lockout is
1254   *          not configured in the password policy that governs the user, or
1255   *          because the user's account is not idle-locked).
1256   */
1257  @Nullable()
1258  public Integer getSecondsSinceIdleLockout()
1259  {
1260    return passwordPolicyStateObject.getFieldAsInteger(
1261         SECONDS_SINCE_IDLE_LOCKOUT.getFieldName());
1262  }
1263
1264
1265
1266  /**
1267   * Retrieves the value of a flag that indicates whether the user must change
1268   * their password before they will be allowed to perform any other operations
1269   * in the server.
1270   *
1271   * @return  {@code Boolean.TRUE} if the user must change their password before
1272   *          they will be allowed to perform any other operations in the
1273   *          server, {@code Boolean.FALSE} if the user is not required to
1274   *          change their password, or {@code null} if this flag was not
1275   *          included in the password policy state JSON object.
1276   */
1277  @Nullable()
1278  public Boolean getMustChangePassword()
1279  {
1280    return passwordPolicyStateObject.getFieldAsBoolean(
1281         MUST_CHANGE_PASSWORD.getFieldName());
1282  }
1283
1284
1285
1286  /**
1287   * Retrieves the value of a flag that indicates whether the user's account is
1288   * locked because they failed to choose a new password in a timely manner
1289   * after an administrative reset.
1290   *
1291   * @return  {@code Boolean.TRUE} if the user's account is currently
1292   *          reset-locked, {@code Boolean.FALSE} if the user's account is not
1293   *          reset-locked, or {@code null} if this flag was not included in the
1294   *          password policy state JSON object.
1295   */
1296  @Nullable()
1297  public Boolean getAccountIsResetLocked()
1298  {
1299    return passwordPolicyStateObject.getFieldAsBoolean(
1300         ACCOUNT_IS_RESET_LOCKED.getFieldName());
1301  }
1302
1303
1304
1305  /**
1306   * Retrieves the value of a flag that indicates whether the password policy
1307   * that governs the user is configured to require users to choose a new
1308   * password the first time they authenticate after their account is created.
1309   *
1310   * @return  {@code Boolean.TRUE} if users are required to choose a new
1311   *          password the first time they authenticate after their account is
1312   *          created, {@code Boolean.FALSE} if users are not required to choose
1313   *          a new password after their account is created, or {@code null} if
1314   *          this flag was not included in the password policy state JSON
1315   *          object.
1316   */
1317  @Nullable()
1318  public Boolean getForceChangeOnAdd()
1319  {
1320    return passwordPolicyStateObject.getFieldAsBoolean(
1321         FORCE_CHANGE_ON_ADD.getFieldName());
1322  }
1323
1324
1325
1326  /**
1327   * Retrieves the value of a flag that indicates whether the password policy
1328   * that governs the user is configured to require users to choose a new
1329   * password the first time they authenticate after their password has been
1330   * reset by an administrator.
1331   *
1332   * @return  {@code Boolean.TRUE} if users are required to choose a new
1333   *          password the first time they authenticate after their password is
1334   *          reset, {@code Boolean.FALSE} if users are not required to choose
1335   *          a new password after their password is reset, or {@code null} if
1336   *          this flag was not included in the password policy state JSON
1337   *          object.
1338   */
1339  @Nullable()
1340  public Boolean getForceChangeOnReset()
1341  {
1342    return passwordPolicyStateObject.getFieldAsBoolean(
1343         FORCE_CHANGE_ON_RESET.getFieldName());
1344  }
1345
1346
1347
1348  /**
1349   * Retrieves the maximum length of time in seconds that a user has to change
1350   * their password after an administrative reset before their account will be
1351   * locked.
1352   *
1353   * @return  The maximum length of time in seconds that a user has to change
1354   *          their password after an administrative reset before their account
1355   *          will be locked, or {@code null} if this was not included in the
1356   *          password policy state JSON object (e.g., because reset lockout is
1357   *          not configured in the password policy that governs the user).
1358   */
1359  @Nullable()
1360  public Integer getMaximumPasswordResetAgeSeconds()
1361  {
1362    return passwordPolicyStateObject.getFieldAsInteger(
1363         MAXIMUM_PASSWORD_RESET_AGE_SECONDS.getFieldName());
1364  }
1365
1366
1367
1368  /**
1369   * Retrieves the time that the user's account will be (or was) locked after
1370   * failing to choose a new password in a timely manner after an administrative
1371   * reset.
1372   *
1373   * @return  The time that the user's account will be (or wa) locked after
1374   *          failing to choose a new password in a timely manner after an
1375   *          administrative reset, or {@code null} if this was not included in
1376   *          the password policy state JSON object (e.g., because reset lockout
1377   *          is not configured in the password policy that governs the user,
1378   *          or because the user's password has not been reset).
1379   */
1380  @Nullable()
1381  public Date getResetLockoutTime()
1382  {
1383    return getDate(RESET_LOCKOUT_TIME);
1384  }
1385
1386
1387
1388  /**
1389   * Retrieves the length of time in seconds until the user's account will be
1390   * locked for failing to choose a new password after an administrative
1391   * reset.
1392   *
1393   * @return  The length of time in seconds until the user's account will be
1394   *          locked for failing to choose a new password after an
1395   *          administrative reset, or {@code null} if this was not included in
1396   *          the password policy state JSON object (e.g., because reset lockout
1397   *          is not configured in the password policy that governs the user,
1398   *          because the user's password has not been reset, or because the
1399   *          user's account is already reset-locked).
1400   */
1401  @Nullable()
1402  public Integer getSecondsUntilResetLockout()
1403  {
1404    return passwordPolicyStateObject.getFieldAsInteger(
1405         SECONDS_UNTIL_RESET_LOCKOUT.getFieldName());
1406  }
1407
1408
1409
1410  /**
1411   * Retrieves the maximum number of passwords that the server will maintain in
1412   * the user's password history.
1413   *
1414   * @return  The maximum number of passwords that the server will maintain in
1415   *          the user's password history, or {@code null} if this was not
1416   *          included in the password policy state JSON object (e.g., because
1417   *          the password policy that governs the user is not configured to
1418   *          maintain a password history, or because it maintains a password
1419   *          history based on a duration rather than a count).
1420   */
1421  @Nullable()
1422  public Integer getMaximumPasswordHistoryCount()
1423  {
1424    return passwordPolicyStateObject.getFieldAsInteger(
1425         MAXIMUM_PASSWORD_HISTORY_COUNT.getFieldName());
1426  }
1427
1428
1429
1430  /**
1431   * Retrieves the maximum length of time in seconds that the server will
1432   * maintain passwords in the user's password history.
1433   *
1434   * @return  The maximum length of time in seconds that the server will
1435   *           maintain passwords in the user's password history, or
1436   *           {@code null} if this was not included in the password policy
1437   *           state JSON object (e.g., because the password policy that governs
1438   *           the user is not configured to maintain a password history, or
1439   *           because it maintains a password history based on a count rather
1440   *           than a duration).
1441   */
1442  @Nullable()
1443  public Integer getMaximumPasswordHistoryDurationSeconds()
1444  {
1445    return passwordPolicyStateObject.getFieldAsInteger(
1446         MAXIMUM_PASSWORD_HISTORY_DURATION_SECONDS.getFieldName());
1447  }
1448
1449
1450
1451  /**
1452   * Retrieves the number of passwords currently held in the user's password
1453   * history.
1454   *
1455   * @return  The number of passwords currently held in the user's password
1456   *          history, or {@code null} if this was not incldued in the password
1457   *          policy state JSON object (e.g., because the password policy that
1458   *          governs the user is not configured to maintain a password
1459   *          history).
1460   */
1461  @Nullable()
1462  public Integer getCurrentPasswordHistoryCount()
1463  {
1464    return passwordPolicyStateObject.getFieldAsInteger(
1465         CURRENT_PASSWORD_HISTORY_COUNT.getFieldName());
1466  }
1467
1468
1469
1470  /**
1471   * Indicates whether the user is currently prohibited from changing their
1472   * password because not enough time has elapsed since they last changed their
1473   * password.
1474   *
1475   * @return  {@code Boolean.TRUE} if the user is currently prohibited from
1476   *          changing their password because not enough time has elapsed since
1477   *          they last changed their password, {@code Boolean.FALSE} if the
1478   *          user is not prohibited from changing their password because of the
1479   *          minimum password age, or {@code null} if this flag was not
1480   *          included in the password policy state JSON object.
1481   */
1482  @Nullable()
1483  public Boolean getIsWithinMinimumPasswordAge()
1484  {
1485    return passwordPolicyStateObject.getFieldAsBoolean(
1486         IS_WITHIN_MINIMUM_PASSWORD_AGE.getFieldName());
1487  }
1488
1489
1490
1491  /**
1492   * Retrieves the minimum length of time in seconds that must elapse after a
1493   * user changes their password before they will be permitted to change it
1494   * again.
1495   *
1496   * @return  The minimum length of time in seconds that must elapse after a
1497   *          user changes their password before they will be permitted to
1498   *          change it again, or {@code null} if this was not included in the
1499   *          password policy state JSON object (e.g., because no minimum
1500   *          password age is configured in the password policy that governs the
1501   *          user).
1502   */
1503  @Nullable()
1504  public Integer getMinimumPasswordAgeSeconds()
1505  {
1506    return passwordPolicyStateObject.getFieldAsInteger(
1507         MINIMUM_PASSWORD_AGE_SECONDS.getFieldName());
1508  }
1509
1510
1511
1512  /**
1513   * Retrieves the earliest time that the user will be permitted to change their
1514   * password as a result of the minimum password age.
1515   *
1516   * @return  The earliest time that the user will be permitted to change their
1517   *          password as a result of the minimum password age, or {@code null}
1518   *          if this was not included in the password policy state JSON
1519   *          object (e.g., because no minimum password age is configured in the
1520   *          password policy that governs the user, or because it has been
1521   *          longer than the minimum age since they last changed their
1522   *          password).
1523   */
1524  @Nullable()
1525  public Date getMinimumPasswordAgeExpirationTime()
1526  {
1527    return getDate(MINIMUM_PASSWORD_AGE_EXPIRATION_TIME);
1528  }
1529
1530
1531
1532  /**
1533   * Retrieves the length of time in seconds remaining until the user will be
1534   * permitted to change their password as a result of the minimum password age.
1535   *
1536   * @return  The length of time in seconds remaining until the user will be
1537   *          permitted to change their password as a result of the minimum
1538   *          password age, or {@code null} if this was not included in the
1539   *          password policy state JSON object (e.g., because no minimum
1540   *          password age is configured in the password policy that governs the
1541   *          user, or because it has been longer than the minimum age since
1542   *          they last changed their password).
1543   */
1544  @Nullable()
1545  public Integer getSecondsRemainingInMinimumPasswordAge()
1546  {
1547    return passwordPolicyStateObject.getFieldAsInteger(
1548         SECONDS_REMAINING_IN_MINIMUM_PASSWORD_AGE.getFieldName());
1549  }
1550
1551
1552
1553  /**
1554   * Retrieves the maximum number of grace login attempts that the user will
1555   * have to allow them to change an expired password.
1556   *
1557   * @return  The maximum number of grace login attempts that the user will have
1558   *          to allow them to change an expired password, or {@code null} if
1559   *          this was not included in the password policy state JSON object
1560   *          (e.g., if grace logins are not configured in the password policy
1561   *          that governs the user).
1562   */
1563  @Nullable()
1564  public Integer getMaximumGraceLoginCount()
1565  {
1566    return passwordPolicyStateObject.getFieldAsInteger(
1567         MAXIMUM_GRACE_LOGIN_COUNT.getFieldName());
1568  }
1569
1570
1571
1572  /**
1573   * Retrieves the number of grace logins that the user has currently used.
1574   *
1575   * @return  The number of grace login attempts that the user has currently
1576   *          used, or {@code null} if this was not included in the password
1577   *          policy state JSON object (e.g., if grace logins are not configured
1578   *          in the password policy that governs the user).
1579   */
1580  @Nullable()
1581  public Integer getUsedGraceLoginCount()
1582  {
1583    return passwordPolicyStateObject.getFieldAsInteger(
1584         USED_GRACE_LOGIN_COUNT.getFieldName());
1585  }
1586
1587
1588
1589  /**
1590   * Retrieves the remaining number of grace logins for the user.
1591   *
1592   * @return  The remaining number of grace logins for the user, or {@code null}
1593   *          if this was not included in the password policy state JSON object
1594   *          (e.g., if grace logins are not configured in the password policy
1595   *          that governs the user).
1596   */
1597  @Nullable()
1598  public Integer getRemainingGraceLoginCount()
1599  {
1600    return passwordPolicyStateObject.getFieldAsInteger(
1601         REMAINING_GRACE_LOGIN_COUNT.getFieldName());
1602  }
1603
1604
1605
1606  /**
1607   * Retrieves a list of the times that the user has used a grace login to
1608   * authenticate.
1609   *
1610   * @return  A list of the times that the user has used a grace login to
1611   *          authenticate, or an empty list if the user has not used any grace
1612   *          logins, or if this was not included in the password policy state
1613   *          JSON object (e.g., if grace logins are not configured in the
1614   *          password policy that governs the user).
1615   */
1616  @NotNull()
1617  public List<Date> getGraceLoginUseTimes()
1618  {
1619    final List<Date> graceLoginTimes = new ArrayList<>();
1620
1621    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
1622         GRACE_LOGIN_USE_TIMES.getFieldName());
1623    if (values != null)
1624    {
1625      for (final JSONValue v : values)
1626      {
1627        try
1628        {
1629          final String valueString = ((JSONString) v).stringValue();
1630          graceLoginTimes.add(StaticUtils.decodeRFC3339Time(valueString));
1631        }
1632        catch (final Exception e)
1633        {
1634          Debug.debugException(e);
1635        }
1636      }
1637    }
1638
1639    return Collections.unmodifiableList(graceLoginTimes);
1640  }
1641
1642
1643
1644  /**
1645   * Retrieves the value of a flag that indicates whether the user account has a
1646   * retired former password that may still be used to authenticate.
1647   *
1648   * @return  {@code Boolean.TRUE} if the user account currently has a valid
1649   *          retired password, {@code Boolean.FALSE} if the user account does
1650   *          not have a valid retired password, or {@code null} if this flag
1651   *          was not included in the password policy state JSON object.
1652   */
1653  @Nullable()
1654  public Boolean getHasRetiredPassword()
1655  {
1656    return passwordPolicyStateObject.getFieldAsBoolean(
1657         HAS_RETIRED_PASSWORD.getFieldName());
1658  }
1659
1660
1661
1662  /**
1663   * Retrieves the time that the user's retired password will expire and can no
1664   * longer be used to authenticate.
1665   *
1666   * @return  The time that the user's retired password will expire, or
1667   *          {@code null} if this was not included in the password policy state
1668   *          JSON object (e.g., because the user does not have a retired
1669   *          password).
1670   */
1671  @Nullable()
1672  public Date getRetiredPasswordExpirationTime()
1673  {
1674    return getDate(RETIRED_PASSWORD_EXPIRATION_TIME);
1675  }
1676
1677
1678
1679  /**
1680   * Retrieves the length of time in seconds remaining until the user's retired
1681   * password expires and can no longer be used to authenticate.
1682   *
1683   * @return  The length of time in seconds remaining until the user's retired
1684   *          password expires, or {@code null} if this was not included in the
1685   *          password policy state JSON object (e.g., because the user does not
1686   *          have a retired password).
1687   */
1688  @Nullable()
1689  public Integer getSecondsUntilRetiredPasswordExpiration()
1690  {
1691    return passwordPolicyStateObject.getFieldAsInteger(
1692         SECONDS_UNTIL_RETIRED_PASSWORD_EXPIRATION.getFieldName());
1693  }
1694
1695
1696
1697  /**
1698   * Retrieves the value of a flag that indicates whether the user will be
1699   * required to authenticate in a secure manner that does not reveal their
1700   * credentials to an observer.
1701   *
1702   * @return  {@code Boolean.TRUE} if the user will be required to authenticate
1703   *          in a secure manner, {@code Boolean.FALSE} if the user will not be
1704   *          required to authenticate in a secure manner, or {@code null} if
1705   *          this flag was not included in the password policy state JSON
1706   *          object.
1707   */
1708  @Nullable()
1709  public Boolean getRequireSecureAuthentication()
1710  {
1711    return passwordPolicyStateObject.getFieldAsBoolean(
1712         REQUIRE_SECURE_AUTHENTICATION.getFieldName());
1713  }
1714
1715
1716
1717  /**
1718   * Retrieves the value of a flag that indicates whether the user will be
1719   * required to change their password in a secure manner that does not reveal
1720   * their credentials to an observer.
1721   *
1722   * @return  {@code Boolean.TRUE} if the user will be required to change their
1723   *          password in a secure manner, {@code Boolean.FALSE} if the user
1724   *          will not be required to change their password in a secure manner,
1725   *          or {@code null} if this flag was not included in the password
1726   *          policy state JSON object.
1727   */
1728  @Nullable()
1729  public Boolean getRequireSecurePasswordChanges()
1730  {
1731    return passwordPolicyStateObject.getFieldAsBoolean(
1732         REQUIRE_SECURE_PASSWORD_CHANGES.getFieldName());
1733  }
1734
1735
1736
1737  /**
1738   * Retrieves a list of the names of the SASL mechanisms that the user can use
1739   * to authenticate.
1740   *
1741   * @return  A list of the names of the SASL mechanisms that the user can use
1742   *          to authenticate, or an empty list if no SASL mechanisms are
1743   *          available to the user or if this was not included in the password
1744   *          policy state JSON object.
1745   */
1746  @NotNull()
1747  public List<String> getAvailableSASLMechanisms()
1748  {
1749    final List<String> saslMechanismNames = new ArrayList<>();
1750
1751    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
1752         AVAILABLE_SASL_MECHANISMS.getFieldName());
1753    if (values != null)
1754    {
1755      for (final JSONValue v : values)
1756      {
1757        try
1758        {
1759          saslMechanismNames.add(((JSONString) v).stringValue());
1760        }
1761        catch (final Exception e)
1762        {
1763          Debug.debugException(e);
1764        }
1765      }
1766    }
1767
1768    return Collections.unmodifiableList(saslMechanismNames);
1769  }
1770
1771
1772
1773  /**
1774   * Retrieves a list of the names of the OTP delivery mechanisms that the user
1775   * can use to receive one-time passwords, password reset tokens, and
1776   * single-use tokens.
1777   *
1778   * @return  A list of the names of the OTP delivery mechanisms that the user
1779   *          can use, or an empty list if no OTP delivery mechanisms are
1780   *          available to the user or if this was not included in the password
1781   *          policy state JSON object.
1782   */
1783  @NotNull()
1784  public List<String> getAvailableOTPDeliveryMechanisms()
1785  {
1786    final List<String> deliveryMechanismNames = new ArrayList<>();
1787
1788    final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
1789         AVAILABLE_OTP_DELIVERY_MECHANISMS.getFieldName());
1790    if (values != null)
1791    {
1792      for (final JSONValue v : values)
1793      {
1794        try
1795        {
1796          deliveryMechanismNames.add(((JSONString) v).stringValue());
1797        }
1798        catch (final Exception e)
1799        {
1800          Debug.debugException(e);
1801        }
1802      }
1803    }
1804
1805    return Collections.unmodifiableList(deliveryMechanismNames);
1806  }
1807
1808
1809
1810  /**
1811   * Retrieves the value of a flag that indicates whether the user account has
1812   * at least one TOTP shared secret that can be used to authenticate with
1813   * time-based one-time passwords via the UNBOUNDID-TOTP SASL mechanism.
1814   *
1815   * @return  {@code Boolean.TRUE} if the user account has at least one TOTP
1816   *          shared secret, {@code Boolean.FALSE} if the user account does not
1817   *          have any TOTP shared secrets, or {@code null} if this flag was not
1818   *          included in the password policy state JSON object.
1819   */
1820  @Nullable()
1821  public Boolean getHasTOTPSharedSecret()
1822  {
1823    return passwordPolicyStateObject.getFieldAsBoolean(
1824         HAS_TOTP_SHARED_SECRET.getFieldName());
1825  }
1826
1827
1828
1829  /**
1830   * Retrieves the value of a flag that indicates whether the user account has
1831   * at least one registered YubiKey OTP device that can be used to authenticate
1832   * via the UNBOUNDID-YUBIKEY-OTP SASL mechanism.
1833   *
1834   * @return  {@code Boolean.TRUE} if the user account has at least one
1835   *          registered YubiKey OTP device, {@code Boolean.FALSE} if the user
1836   *          account does not have any registered YubiKey OTP devices, or
1837   *          {@code null} if this flag was not included in the password policy
1838   *          state JSON object.
1839   */
1840  @Nullable()
1841  public Boolean getHasRegisteredYubiKeyOTPDevice()
1842  {
1843    return passwordPolicyStateObject.getFieldAsBoolean(
1844         HAS_REGISTERED_YUBIKEY_OTP_DEVICE.getFieldName());
1845  }
1846
1847
1848
1849  /**
1850   * Retrieves the value of a flag that indicates whether the user account is
1851   * currently locked because it contains a password that does not satisfy all
1852   * of the configured password validators.
1853   *
1854   * @return  {@code Boolean.TRUE} if the user account is locked because it
1855   *          contains a password that does not satisfy all of the configured
1856   *          password validators, {@code Boolean.FALSE} if the account is not
1857   *          validation-locked, or {@code null} if this flag was not included
1858   *          in the password policy state JSON object.
1859   */
1860  @Nullable()
1861  public Boolean getAccountIsValidationLocked()
1862  {
1863    return passwordPolicyStateObject.getFieldAsBoolean(
1864         ACCOUNT_IS_VALIDATION_LOCKED.getFieldName());
1865  }
1866
1867
1868
1869  /**
1870   * Retrieves the time that the server last invoked password validators during
1871   * a bind operation for the user.
1872   *
1873   * @return  The time that the server last invoked password validators during a
1874   *          bind operation for the user, or {@code null} if this was not
1875   *          included in the password policy state JSON object.
1876   */
1877  @Nullable()
1878  public Date getLastBindPasswordValidationTime()
1879  {
1880    return getDate(LAST_BIND_PASSWORD_VALIDATION_TIME);
1881  }
1882
1883
1884
1885  /**
1886   * Retrieves the length of time in seconds that has passed since the server
1887   * last invoked password validators during a bind operation for the user.
1888   *
1889   * @return  The length of time in seconds that has passed since the server
1890   *          last invoked password validators during a bind operation for the
1891   *          user, or {@code null} if this was not included in the password
1892   *          policy state JSON object.
1893   */
1894  @Nullable()
1895  public Integer getSecondsSinceLastBindPasswordValidation()
1896  {
1897    return passwordPolicyStateObject.getFieldAsInteger(
1898         SECONDS_SINCE_LAST_BIND_PASSWORD_VALIDATION.getFieldName());
1899  }
1900
1901
1902
1903  /**
1904   * Retrieves the minimum length of time in seconds that should pass between
1905   * invocations of password validators during a bind operation for the user.
1906   *
1907   * @return  The minimum length of time in seconds that should pass between
1908   *          invocations of password validators during a bind operation for
1909   *          each user, or {@code null} if this was not included in the
1910   *          password policy state JSON object.
1911   */
1912  @Nullable()
1913  public Integer getMinimumBindPasswordValidationFrequencySeconds()
1914  {
1915    return passwordPolicyStateObject.getFieldAsInteger(
1916         MINIMUM_BIND_PASSWORD_VALIDATION_FREQUENCY_SECONDS.getFieldName());
1917  }
1918
1919
1920
1921  /**
1922   * Retrieves the name of the action that the server should take if the
1923   * password provided during a bind operation fails to satisfy one or more
1924   * password validators.
1925   *
1926   * @return  The name of the action that the server should take if the password
1927   *          provided during a bind operation fails to satisfy one or more
1928   *          password validators, or {@code null} if this was not included in
1929   *          the password policy state JSON object.
1930   */
1931  @Nullable()
1932  public String getBindPasswordValidationFailureAction()
1933  {
1934    return passwordPolicyStateObject.getFieldAsString(
1935         BIND_PASSWORD_VALIDATION_FAILURE_ACTION.getFieldName());
1936  }
1937
1938
1939
1940  /**
1941   * Retrieves the recent login history for the user.
1942   *
1943   * @return  The recent login history for the user, or {@code null} if this was
1944   *          not included in the password policy state JSON object.
1945   *
1946   * @throws  LDAPException  If a problem occurs while trying to parse the
1947   *                         recent login history for the user.
1948   */
1949  @Nullable()
1950  public RecentLoginHistory getRecentLoginHistory()
1951         throws LDAPException
1952  {
1953    final JSONObject o = passwordPolicyStateObject.getFieldAsObject(
1954         RECENT_LOGIN_HISTORY.getFieldName());
1955    if (o == null)
1956    {
1957      return null;
1958    }
1959    else
1960    {
1961      return new RecentLoginHistory(o);
1962    }
1963  }
1964
1965
1966
1967  /**
1968   * Retrieves the maximum number of recent successful login attempts the server
1969   * should maintain for a user.
1970   *
1971   * @return  The maximum number of recent successful login attempts the server
1972   *          should maintain for a user, or {@code null}if this was not
1973   *          included in the password policy state JSON object.
1974   */
1975  @Nullable()
1976  public Integer getMaximumRecentLoginHistorySuccessfulAuthenticationCount()
1977  {
1978    return passwordPolicyStateObject.getFieldAsInteger(
1979         MAXIMUM_RECENT_LOGIN_HISTORY_SUCCESSFUL_AUTHENTICATION_COUNT.
1980              getFieldName());
1981  }
1982
1983
1984
1985  /**
1986   * Retrieves the maximum age in seconds of recent successful login attempts
1987   * the server should maintain for a user.
1988   *
1989   * @return  The maximum age in seconds of recent successful login attempts the
1990   *          server should maintain for a user, or {@code null}if this was not
1991   *          included in the password policy state JSON object.
1992   */
1993  @Nullable()
1994  public Integer
1995       getMaximumRecentLoginHistorySuccessfulAuthenticationDurationSeconds()
1996  {
1997    return passwordPolicyStateObject.getFieldAsInteger(
1998         MAXIMUM_RECENT_LOGIN_HISTORY_SUCCESSFUL_AUTHENTICATION_DURATION_SECONDS
1999              .getFieldName());
2000  }
2001
2002
2003
2004  /**
2005   * Retrieves the maximum number of recent failed login attempts the server
2006   * should maintain for a user.
2007   *
2008   * @return  The maximum number of recent failed login attempts the server
2009   *          should maintain for a user, or {@code null}if this was not
2010   *          included in the password policy state JSON object.
2011   */
2012  @Nullable()
2013  public Integer getMaximumRecentLoginHistoryFailedAuthenticationCount()
2014  {
2015    return passwordPolicyStateObject.getFieldAsInteger(
2016         MAXIMUM_RECENT_LOGIN_HISTORY_FAILED_AUTHENTICATION_COUNT.
2017              getFieldName());
2018  }
2019
2020
2021
2022  /**
2023   * Retrieves the maximum age in seconds of recent failed login attempts
2024   * the server should maintain for a user.
2025   *
2026   * @return  The maximum age in seconds of recent failed login attempts the
2027   *          server should maintain for a user, or {@code null}if this was not
2028   *          included in the password policy state JSON object.
2029   */
2030  @Nullable()
2031  public Integer
2032       getMaximumRecentLoginHistoryFailedAuthenticationDurationSeconds()
2033  {
2034    return passwordPolicyStateObject.getFieldAsInteger(
2035         MAXIMUM_RECENT_LOGIN_HISTORY_FAILED_AUTHENTICATION_DURATION_SECONDS.
2036              getFieldName());
2037  }
2038
2039
2040
2041  /**
2042   * Retrieves the list of quality requirements that must be satisfied for
2043   * passwords included in new entries that are added using the same password
2044   * policy as the associated entry.
2045   *
2046   * @return  The list of password quality requirements that will be enforced
2047   *          for adds using the same password policy as the associated entry,
2048   *          or an empty list if no requirements will be imposed.
2049   */
2050  @NotNull()
2051  public List<PasswordQualityRequirement> getAddPasswordQualityRequirements()
2052  {
2053    return getPasswordQualityRequirements(REQUIREMENT_FIELD_APPLIES_TO_ADD);
2054  }
2055
2056
2057
2058  /**
2059   * Retrieves the list of quality requirements that must be satisfied when the
2060   * associated user attempts to change their own password.
2061   *
2062   * @return  The list of password quality requirements that will be enforced
2063   *          for self password changes, or an empty list if no requirements
2064   *          will be imposed.
2065   */
2066    @NotNull()
2067  public List<PasswordQualityRequirement>
2068            getSelfChangePasswordQualityRequirements()
2069  {
2070    return getPasswordQualityRequirements(
2071         REQUIREMENT_FIELD_APPLIES_TO_SELF_CHANGE);
2072  }
2073
2074
2075
2076  /**
2077   * Retrieves the list of quality requirements that must be satisfied when an
2078   * administrator attempts to change the user's password.
2079   *
2080   * @return  The list of password quality requirements that will be enforced
2081   *          for administrative password resets, or an empty list if no
2082   *          requirements will be imposed.
2083   */
2084  @NotNull()
2085  public List<PasswordQualityRequirement>
2086            getAdministrativeResetPasswordQualityRequirements()
2087  {
2088    return getPasswordQualityRequirements(
2089         REQUIREMENT_FIELD_APPLIES_TO_ADMIN_RESET);
2090  }
2091
2092
2093
2094  /**
2095   * Retrieves the list of quality requirements that must be satisfied when the
2096   * associated user authenticates in a manner that makes the clear-text
2097   * password available to the server.
2098   *
2099   * @return  The list of password quality requirements that will be enforced
2100   *          for binds, or an empty list if no requirements will be imposed.
2101   */
2102  @NotNull()
2103  public List<PasswordQualityRequirement> getBindPasswordQualityRequirements()
2104  {
2105    return getPasswordQualityRequirements(REQUIREMENT_FIELD_APPLIES_TO_BIND);
2106  }
2107
2108
2109
2110  /**
2111   * Retrieves a list of the password quality requirements that are contained in
2112   * the JSON object in which the indicated Boolean field is present and set to
2113   * {@code true}.
2114   *
2115   * @param  booleanFieldName  The name of the field that is expected to be
2116   *                           present with a Boolean value of true for each
2117   *                           requirement to be included in the list that is
2118   *                           returned.
2119   *
2120   * @return  The appropriate list of password quality requirements, or an empty
2121   *          list if no requirements will be imposed.
2122   */
2123  @NotNull()
2124  private List<PasswordQualityRequirement> getPasswordQualityRequirements(
2125       @NotNull final String booleanFieldName)
2126  {
2127    final List<JSONValue> requirementObjectLst =
2128         passwordPolicyStateObject.getFieldAsArray(
2129              PASSWORD_QUALITY_REQUIREMENTS.getFieldName());
2130    if ((requirementObjectLst == null) || requirementObjectLst.isEmpty())
2131    {
2132      return Collections.emptyList();
2133    }
2134
2135    final List<PasswordQualityRequirement> requirements =
2136         new ArrayList<>(requirementObjectLst.size());
2137    for (final JSONValue requirementObjectValue : requirementObjectLst)
2138    {
2139      if (! (requirementObjectValue instanceof JSONObject))
2140      {
2141        continue;
2142      }
2143
2144      final JSONObject requirementObject = (JSONObject) requirementObjectValue;
2145      final Boolean include = requirementObject.getFieldAsBoolean(
2146           booleanFieldName);
2147      if ((include == null) || (! include.booleanValue()))
2148      {
2149        continue;
2150      }
2151
2152      final String description =
2153           requirementObject.getFieldAsString(REQUIREMENT_FIELD_DESCRIPTION);
2154      if (description == null)
2155      {
2156        continue;
2157      }
2158
2159      final String clientSideValidationType =
2160           requirementObject.getFieldAsString(
2161                REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_TYPE);
2162
2163      final Map<String,String> clientSideValidationProperties =
2164           new LinkedHashMap<>();
2165      final List<JSONValue> propertyValues = requirementObject.getFieldAsArray(
2166           REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_PROPERTIES);
2167      if (propertyValues != null)
2168      {
2169        for (final JSONValue propertyValue : propertyValues)
2170        {
2171          if (! (propertyValue instanceof JSONObject))
2172          {
2173            continue;
2174          }
2175
2176          final JSONObject propertyObject = (JSONObject) propertyValue;
2177          final String name = propertyObject.getFieldAsString(
2178               REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_PROPERTY_NAME);
2179          final String value = propertyObject.getFieldAsString(
2180               REQUIREMENT_FIELD_CLIENT_SIDE_VALIDATION_PROPERTY_VALUE);
2181          if ((name != null) && (value != null))
2182          {
2183            clientSideValidationProperties.put(name, value);
2184          }
2185        }
2186      }
2187
2188      requirements.add(new PasswordQualityRequirement(description,
2189           clientSideValidationType, clientSideValidationProperties));
2190    }
2191
2192    return requirements;
2193  }
2194
2195
2196
2197  /**
2198   * Retrieves the value of the specified field as a {@code Date}.
2199   *
2200   * @param  field  The field whose value is to be retrieved and parsed as a
2201   *                {@code Date}.
2202   *
2203   * @return  The value of the specified field as a {@code Date}, or
2204   *          {@code null} if the field is not contained in the JSON object or
2205   *          if its value cannot be parsed as a {@code Date}.
2206   */
2207  @Nullable()
2208  private Date getDate(@NotNull final PasswordPolicyStateJSONField field)
2209  {
2210    final String stringValue =
2211         passwordPolicyStateObject.getFieldAsString(field.getFieldName());
2212    if (stringValue == null)
2213    {
2214      return null;
2215    }
2216
2217    try
2218    {
2219      return StaticUtils.decodeRFC3339Time(stringValue);
2220    }
2221    catch (final Exception e)
2222    {
2223      Debug.debugException(e);
2224      return null;
2225    }
2226  }
2227
2228
2229
2230  /**
2231   * Retrieves a string representation of the password policy state information.
2232   *
2233   * @return  A string representation of the password policy state information.
2234   */
2235  @Override()
2236  @NotNull()
2237  public String toString()
2238  {
2239    return passwordPolicyStateObject.toSingleLineString();
2240  }
2241}