Skip to content

Commit

Permalink
Update ds-pwp-state-json for non-current PW enc
Browse files Browse the repository at this point in the history
Updated support for the Ping Identity Directory Server's
ds-pwp-state-json virtual attribute to include fields pertaining to
support for passwords encoded in a manner that doesn't reflect the
current configuration for the associated password storage scheme.
  • Loading branch information
dirmgr committed Aug 17, 2023
1 parent 1ca86ec commit b73ca07
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 3 deletions.
8 changes: 8 additions & 0 deletions docs/release-notes.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ <h3>Version 6.0.10</h3>
control.
<br><br>
</li>

<li>
Updated support for the Ping Identity Directory Server's ds-pwp-state-json
virtual attribute to include fields pertaining to support for passwords encoded
in a manner that doesn't reflect the current configuration for the associated
password storage scheme.
<br><br>
</li>
</ul>

<p></p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,24 @@ public final class PasswordPolicyStateJSON



/**
* The name of the field that will be used to hold the name of a password
* storage scheme for a password that is encoded with non-current settings.
*/
@NotNull private static final String NON_CURRENT_ENCODING_FIELD_SCHEME =
"scheme";



/**
* The name of the field that will be used to hold the set of explanations for
* a password that is encoded with non-current settings.
*/
@NotNull private static final String NON_CURRENT_ENCODING_FIELD_EXPLANATIONS =
"explanations";



/**
* The serial version UID for this serializable class.
*/
Expand Down Expand Up @@ -2194,6 +2212,86 @@ private List<PasswordQualityRequirement> getPasswordQualityRequirements(



/**
* Indicates whether the user has a static password that is encoded with
* settings that don't match the current configuration for the associated
* password storage scheme.
*
* @return {@code Boolean.TRUE} if the account has a static password that
* is encoded with non-current settings, {@code Boolean.FALSE} if the
* account does not have a static password that is encoded with
* non-current settings, or {@code null} if this flag was not
* included in the password policy state JSON object.
*/
@Nullable()
public Boolean hasPasswordEncodedWithNonCurrentSettings()
{
return passwordPolicyStateObject.getFieldAsBoolean(
HAS_PASSWORD_ENCODED_WITH_NON_CURRENT_SETTINGS.getFieldName());
}



/**
* Retrieves a map with information about the reasons that a password may not
* be encoded with the current settings for the associated password storage
* scheme. The keys of the map will the name of the storage scheme, and the
* values will be a possibly-empty list of explanations that describe why a
* password encoded with that scheme is encoded with non-current settings.
*
* @return A map with information about the reasons that a password may not
* be encoded with the current settings for the associated password
* storage scheme, or an empty map if this was not included in the
* password policy state JSON object.
*/
@NotNull()
public Map<String,List<String>>
getNonCurrentPasswordStorageSchemeSettingsExplanations()
{
final Map<String,List<String>> explanationsMap = new LinkedHashMap<>();

final List<JSONValue> values = passwordPolicyStateObject.getFieldAsArray(
NON_CURRENT_PASSWORD_STORAGE_SCHEME_SETTINGS_EXPLANATIONS.
getFieldName());
if (values != null)
{
for (final JSONValue value : values)
{
if (value instanceof JSONObject)
{
final JSONObject valueObject = (JSONObject) value;
final String schemeName = valueObject.getFieldAsString(
NON_CURRENT_ENCODING_FIELD_SCHEME);
if (schemeName == null)
{
continue;
}

final List<String> explanationStrings = new ArrayList<>();
final List<JSONValue> explanationValues = valueObject.getFieldAsArray(
NON_CURRENT_ENCODING_FIELD_EXPLANATIONS);
if (explanationValues != null)
{
for (final JSONValue explanationValue : explanationValues)
{
if (explanationValue instanceof JSONString)
{
explanationStrings.add(
((JSONString) explanationValue).stringValue());
}
}
}

explanationsMap.put(schemeName, explanationStrings);
}
}
}

return Collections.unmodifiableMap(explanationsMap);
}



/**
* Retrieves the value of the specified field as a {@code Date}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -774,10 +774,30 @@ public enum PasswordPolicyStateJSONField


/**
* The field used to hold information about the requirements that passwords
* will be required to satisfy.
* The field (password-quality-requirements) used to hold information about
* the requirements that passwords will be required to satisfy.
*/
PASSWORD_QUALITY_REQUIREMENTS("password-quality-requirements");
PASSWORD_QUALITY_REQUIREMENTS("password-quality-requirements"),



/**
* The field (has-password-encoded-with-non-current-settings) used to indicate
* whether the user has a password that is encoded with settings that don't
* match the current configuration for the associated password storage scheme.
*/
HAS_PASSWORD_ENCODED_WITH_NON_CURRENT_SETTINGS(
"has-password-encoded-with-non-current-settings"),



/**
* The field (non-current-password-storage-scheme-settings-explanations) used
* to hold information about the reasons that a password may not be encoded
* with the current settings for the associated password storage scheme.
*/
NON_CURRENT_PASSWORD_STORAGE_SCHEME_SETTINGS_EXPLANATIONS(
"non-current-password-storage-scheme-settings-explanations");



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2358,6 +2358,109 @@ public void testGetPasswordQualityRequirementsPropertyMissingValue()



/**
* Tests the behavior for fields related to passwords encoded with non-current
* settings.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testPasswordEncodedWithNonCurrentSettings()
throws Exception
{
// Test with a state that represents a user in which the password is encoded
// with current settings.
PasswordPolicyStateJSON state = createState(StaticUtils.mapOf(
HAS_PASSWORD_ENCODED_WITH_NON_CURRENT_SETTINGS, JSONBoolean.FALSE));
assertEquals(state.hasPasswordEncodedWithNonCurrentSettings(),
Boolean.FALSE);
assertNotNull(
state.getNonCurrentPasswordStorageSchemeSettingsExplanations());
assertTrue(state.
getNonCurrentPasswordStorageSchemeSettingsExplanations().isEmpty());


// Test with a state that represents a user in which the password is
// encoded with non-current settings but no explanations.
state = createState(StaticUtils.mapOf(
HAS_PASSWORD_ENCODED_WITH_NON_CURRENT_SETTINGS, JSONBoolean.TRUE,
NON_CURRENT_PASSWORD_STORAGE_SCHEME_SETTINGS_EXPLANATIONS,
new JSONArray(
createNonCurrentSchemeSettingsExplanationsObject(
"SSHA256"))));
assertEquals(state.hasPasswordEncodedWithNonCurrentSettings(),
Boolean.TRUE);
assertNotNull(
state.getNonCurrentPasswordStorageSchemeSettingsExplanations());
assertEquals(
state.getNonCurrentPasswordStorageSchemeSettingsExplanations().size(),
1);
assertTrue(state.getNonCurrentPasswordStorageSchemeSettingsExplanations().
containsKey("SSHA256"));
assertTrue(state.getNonCurrentPasswordStorageSchemeSettingsExplanations().
get("SSHA256").isEmpty());


// Test with a state that represents a user in which the password is
// encoded with non-current settings and has explanations.
state = createState(StaticUtils.mapOf(
HAS_PASSWORD_ENCODED_WITH_NON_CURRENT_SETTINGS, JSONBoolean.TRUE,
NON_CURRENT_PASSWORD_STORAGE_SCHEME_SETTINGS_EXPLANATIONS,
new JSONArray(
createNonCurrentSchemeSettingsExplanationsObject(
"SSHA256", "explanation1", "explanation2"))));
assertEquals(state.hasPasswordEncodedWithNonCurrentSettings(),
Boolean.TRUE);
assertNotNull(
state.getNonCurrentPasswordStorageSchemeSettingsExplanations());
assertEquals(
state.getNonCurrentPasswordStorageSchemeSettingsExplanations().size(),
1);
assertTrue(state.getNonCurrentPasswordStorageSchemeSettingsExplanations().
containsKey("SSHA256"));
assertEquals(
state.getNonCurrentPasswordStorageSchemeSettingsExplanations().get(
"SSHA256"),
Arrays.asList("explanation1", "explanation2"));
}



/**
* Creates a JSON object with information about a password that is encoded
* with non-current scheme settings.
*
* @param schemeName The name of the associated password storage scheme.
* It must not be {@code null}.
* @param explanations An optional set of explanation values. This may be
* empty but must not be {@code null}.
*
* @return The JSON object that was created.
*/
private static JSONObject createNonCurrentSchemeSettingsExplanationsObject(
final String schemeName,
final String... explanations)
{
final Map<String,JSONValue> fields = new LinkedHashMap<>();
fields.put("scheme", new JSONString(schemeName));

if (explanations.length > 0)
{
final List<JSONValue> explanationValues =
new ArrayList<>(explanations.length);
for (final String explanation : explanations)
{
explanationValues.add(new JSONString(explanation));
}

fields.put("explanations", new JSONArray(explanationValues));
}

return new JSONObject(fields);
}



/**
* Creates a password policy state JSON object with the provided fields.
*
Expand Down

0 comments on commit b73ca07

Please sign in to comment.