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