/* * 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-2023 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(); } }