/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* docs/licenses/cddl.txt
* or http://www.opensource.org/licenses/cddl1.php.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* docs/licenses/cddl.txt. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2022-2024 Ping Identity Corporation
*/
package com.unboundid.directory.sdk.examples;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import com.unboundid.directory.sdk.common.types.Entry;
import com.unboundid.directory.sdk.ds.api.DataSecurityAuditor;
import com.unboundid.directory.sdk.ds.config.DataSecurityAuditorConfig;
import com.unboundid.directory.sdk.ds.types.AuditSeverity;
import com.unboundid.directory.sdk.ds.types.DataSecurityAuditorEntryReporter;
import com.unboundid.directory.sdk.ds.types.DataSecurityAuditorSummaryReporter;
import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.unboundidds.PasswordPolicyStateJSON;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
/**
* This class provides a simple example of a data security auditor that can be
* used to identify accounts with outstanding authentication failures (that is,
* one or more failed bind attempts since the most recent successful attempt).
* This auditor requires failure lockout to be enabled in the associated
* password policy, as that enables tracking of outstanding authentication
* failures. It does not require any special configuration properties.
*/
public final class ExampleDataSecurityAuditor
extends DataSecurityAuditor
{
/**
* The name of the attribute that will be included in report entries to
* indicate the number of outstanding authentication failures for the
* associated entry.
*/
@NotNull private static final String REPORT_ATTR_NUM_OUTSTANDING_FAILURES =
"ds-audit-report-number-of-outstanding-authentication-failures";
/**
* The name of the attribute that will be included in summary entries to
* indicate the total number of entries with outstanding authentication
* failures.
*/
@NotNull private static final String
SUMMARY_ATTR_ENTRIES_WITH_OUTSTANDING_FAILURES =
"ds-audit-summary-entries-with-outstanding-authentication-failures";
/**
* The set of object classes that will be included in report entries generated
* by this data security auditor.
*/
@NotNull private static final String[] REPORT_ENTRY_OBJECT_CLASSES =
{
"ds-audit-report-outstanding-authentication-failures",
"extensibleObject"
};
/**
* The set of object classes that will be included in summary entries
* generated by this data security auditor.
*/
@NotNull private static final String[] SUMMARY_ENTRY_OBJECT_CLASSES =
{
"ds-audit-summary-outstanding-authentication-failures",
"extensibleObject"
};
// A counter that will be used to keep track of the number of entries with
// outstanding authentication failures.
@NotNull private final AtomicLong entriesWithOustandingAuthFailures;
/**
* Creates a new instance of this data security auditor. All data security
* auditor implementations must include a default constructor, but any
* initialization should generally be done in the
* {@code initializeDataSecurityAuditor} method.
*/
public ExampleDataSecurityAuditor()
{
entriesWithOustandingAuthFailures = new AtomicLong(0L);
}
/**
* Retrieves a human-readable name for this extension.
*
* @return A human-readable name for this extension.
*/
@Override()
@NotNull()
public String getExtensionName()
{
return "Example Data Security Auditor";
}
/**
* Retrieves a human-readable description for this extension. Each element
* of the array that is returned will be considered a separate paragraph in
* generated documentation.
*
* @return A human-readable description for this extension, or {@code null}
* or an empty array if no description should be available.
*/
@Override()
@Nullable()
public String[] getExtensionDescription()
{
return new String[]
{
"This data security auditor can be used to identify user accounts with " +
"outstanding authentication failures."
};
}
/**
* Updates the provided argument parser to define any configuration arguments
* which may be used by this extension. The argument parser may also be
* updated to define relationships between arguments (e.g., to specify
* required, exclusive, or dependent argument sets).
*
* @param parser The argument parser to be updated with the configuration
* arguments which may be used by this extension.
*
* @throws ArgumentException If a problem is encountered while updating the
* provided argument parser.
*/
@Override()
public void defineConfigArguments(@NotNull final ArgumentParser parser)
throws ArgumentException
{
// No arguments will be allowed by default.
}
/**
* Initializes this data security auditor before beginning processing in the
* specified backend.
*
* @param serverContext A handle to the server context for the server in
* which this extension is running.
* @param config The general configuration for this data security
* auditor.
* @param parser The argument parser which has been initialized from
* the configuration for this data security auditor.
* @param backendID The backend ID for the backend in which processing
* will be performed.
*
* @throws LDAPException If a problem occurs while initializing this data
* security auditor.
*/
@Override()
public void initializeDataSecurityAuditorForBackend(
@NotNull final DirectoryServerContext serverContext,
@NotNull final DataSecurityAuditorConfig config,
@NotNull final ArgumentParser parser,
@NotNull final String backendID)
throws LDAPException
{
entriesWithOustandingAuthFailures.set(0L);
}
/**
* Performs any cleanup that may be necessary when this data security auditor
* ends processing in a backend.
*/
@Override()
public void finalizeDataSecurityAuditor()
{
// No implementation is required.
}
/**
* Examines the provided entry to determine whether any data security issues
* should be reported. If any such issues are found, then the provided
* reporter should be used to report them.
*
* @param entry The entry to examine.
* @param passwordPolicyState The password policy state for the account
* with which the provided entry is associated.
* @param reporter A reporter whose {@code reportEntry} method
* may be used to indicate that the provided
* entry has one or more identified issues.
*
* @throws IOException If a problem is encountered while the reporter is
* attempting to add an entry to the report file.
*/
@Override()
public void examineEntry(
@NotNull final Entry entry,
@NotNull final PasswordPolicyStateJSON passwordPolicyState,
@NotNull final DataSecurityAuditorEntryReporter reporter)
throws IOException
{
final Integer outstandingAuthenticationFailures =
passwordPolicyState.getCurrentAuthenticationFailureCount();
if ((outstandingAuthenticationFailures != null) &&
(outstandingAuthenticationFailures > 0))
{
entriesWithOustandingAuthFailures.incrementAndGet();
reporter.reportEntry(entry, AuditSeverity.WARNING,
REPORT_ENTRY_OBJECT_CLASSES,
new Attribute(REPORT_ATTR_NUM_OUTSTANDING_FAILURES,
outstandingAuthenticationFailures.toString()));
}
}
/**
* Reports a summary of the results obtained from processing this data
* security auditor in the associated backend.
*
* @param reporter The reporter that may be used to provide the summary of
* processing performed by this data security auditor in the
* associated backend.
*
* @throws IOException If a problem is encountered while the reporter is
* attempting to add an entry to the report file.
*/
@Override()
public void reportSummary(
@NotNull final DataSecurityAuditorSummaryReporter reporter)
throws IOException
{
reporter.reportSummary(SUMMARY_ENTRY_OBJECT_CLASSES,
new Attribute(SUMMARY_ATTR_ENTRIES_WITH_OUTSTANDING_FAILURES,
entriesWithOustandingAuthFailures.toString()));
}
/**
* Retrieves a map containing examples of configurations that may be used for
* this extension. The map key should be a list of sample arguments, and the
* corresponding value should be a description of the behavior that will be
* exhibited by the extension when used with that configuration.
*
* @return A map containing examples of configurations that may be used for
* this extension. It may be {@code null} or empty if there should
* not be any example argument sets.
*/
@Nullable()
public Map<List<String>,String> getExamplesArgumentSets()
{
return Collections.emptyMap();
}
}