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