001    /*
002     * Copyright 2011-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2015 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.ldap.sdk.unboundidds.tasks;
022    
023    
024    
025    import java.util.ArrayList;
026    import java.util.Arrays;
027    import java.util.Collections;
028    import java.util.Date;
029    import java.util.LinkedHashMap;
030    import java.util.LinkedList;
031    import java.util.List;
032    import java.util.Map;
033    
034    import com.unboundid.ldap.sdk.Attribute;
035    import com.unboundid.ldap.sdk.Entry;
036    import com.unboundid.ldap.sdk.Filter;
037    import com.unboundid.ldap.sdk.LDAPException;
038    import com.unboundid.util.NotMutable;
039    import com.unboundid.util.StaticUtils;
040    import com.unboundid.util.ThreadSafety;
041    import com.unboundid.util.ThreadSafetyLevel;
042    
043    import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
044    import static com.unboundid.util.Validator.*;
045    
046    
047    
048    /**
049     * <BLOCKQUOTE>
050     *   <B>NOTE:</B>  This class is part of the Commercial Edition of the UnboundID
051     *   LDAP SDK for Java.  It is not available for use in applications that
052     *   include only the Standard Edition of the LDAP SDK, and is not supported for
053     *   use in conjunction with non-UnboundID products.
054     * </BLOCKQUOTE>
055     * This class defines a Directory Server task that can be used to cause the
056     * server to initiate a data security audit, which can look for potential
057     * issues in the environment that can impact the security of the directory
058     * environment.
059     * <BR><BR>
060     * The properties that are available for use with this type of task include:
061     * <UL>
062     *   <LI>The names of the auditors to include or exclude from the audit.  This
063     *       is optional, and if it is not provided, then all enabled auditors will
064     *       be used.</LI>
065     *   <LI>The backend IDs for the backends containing the data to be audited.
066     *       This is optional, and if it is not provided then the server will run
067     *       the audit in all backends that support this capability.</LI>
068     *   <LI>A set of filters which identify the entries that should be examined by
069     *       the audit.  This is optional, and if it is not provided, then all
070     *       entries in the selected backends will be included.</LI>
071     *   <LI>The path to the directory in which the output files should be
072     *       generated.  This is optional, and if it is not provided then the server
073     *       will use a default output directory.</LI>
074     * </UL>
075     */
076    @NotMutable()
077    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
078    public final class AuditDataSecurityTask
079           extends Task
080    {
081      /**
082       * The fully-qualified name of the Java class that is used for the audit data
083       * security task.
084       */
085      static final String AUDIT_DATA_SECURITY_TASK_CLASS =
086           "com.unboundid.directory.server.tasks.AuditDataSecurityTask";
087    
088    
089    
090      /**
091       * The name of the attribute used to specify the set of auditors to use to
092       * examine the data.
093       */
094      private static final String ATTR_INCLUDE_AUDITOR =
095           "ds-task-audit-data-security-include-auditor";
096    
097    
098    
099      /**
100       * The name of the attribute used to specify the set of auditors that should
101       * not be used when examining the data.
102       */
103      private static final String ATTR_EXCLUDE_AUDITOR =
104           "ds-task-audit-data-security-exclude-auditor";
105    
106    
107    
108      /**
109       * The name of the attribute used to the backend IDs for the backends in which
110       * the audit should be performed.
111       */
112      private static final String ATTR_BACKEND_ID =
113           "ds-task-audit-data-security-backend-id";
114    
115    
116    
117      /**
118       * The name of the attribute used to specify a set of filters that should be
119       * used to identify entries to include in the audit.
120       */
121      private static final String ATTR_REPORT_FILTER =
122           "ds-task-audit-data-security-report-filter";
123    
124    
125    
126      /**
127       * The name of the attribute used to specify the directory in which the report
128       * output files should be written.
129       */
130      private static final String ATTR_OUTPUT_DIRECTORY =
131           "ds-task-audit-data-security-output-directory";
132    
133    
134    
135      /**
136       * The name of the object class used in audit data security task entries.
137       */
138      private static final String OC_AUDIT_DATA_SECURITY_TASK =
139           "ds-task-audit-data-security";
140    
141    
142    
143      /**
144       * The task property that will be used for the included set of auditors.
145       */
146      private static final TaskProperty PROPERTY_INCLUDE_AUDITOR =
147           new TaskProperty(ATTR_INCLUDE_AUDITOR,
148                INFO_AUDIT_DATA_SECURITY_DISPLAY_NAME_INCLUDE_AUDITOR.get(),
149                INFO_AUDIT_DATA_SECURITY_DESCRIPTION_INCLUDE_AUDITOR.get(),
150                String.class, false, true, false);
151    
152    
153    
154      /**
155       * The task property that will be used for the excluded set of auditors.
156       */
157      private static final TaskProperty PROPERTY_EXCLUDE_AUDITOR =
158           new TaskProperty(ATTR_EXCLUDE_AUDITOR,
159                INFO_AUDIT_DATA_SECURITY_DISPLAY_NAME_EXCLUDE_AUDITOR.get(),
160                INFO_AUDIT_DATA_SECURITY_DESCRIPTION_EXCLUDE_AUDITOR.get(),
161                String.class, false, true, false);
162    
163    
164    
165      /**
166       * The task property that will be used for the backend IDs.
167       */
168      private static final TaskProperty PROPERTY_BACKEND_ID =
169           new TaskProperty(ATTR_BACKEND_ID,
170                INFO_AUDIT_DATA_SECURITY_DISPLAY_NAME_BACKEND_ID.get(),
171                INFO_AUDIT_DATA_SECURITY_DESCRIPTION_BACKEND_ID.get(),
172                String.class, false, true, false);
173    
174    
175    
176      /**
177       * The task property that will be used for the report filters.
178       */
179      private static final TaskProperty PROPERTY_REPORT_FILTER =
180           new TaskProperty(ATTR_REPORT_FILTER,
181                INFO_AUDIT_DATA_SECURITY_DISPLAY_NAME_REPORT_FILTER.get(),
182                INFO_AUDIT_DATA_SECURITY_DESCRIPTION_REPORT_FILTER.get(),
183                String.class, false, true, false);
184    
185    
186    
187      /**
188       * The task property that will be used for the output directory.
189       */
190      private static final TaskProperty PROPERTY_OUTPUT_DIRECTORY =
191           new TaskProperty(ATTR_OUTPUT_DIRECTORY,
192                INFO_AUDIT_DATA_SECURITY_DISPLAY_NAME_OUTPUT_DIR.get(),
193                INFO_AUDIT_DATA_SECURITY_DESCRIPTION_OUTPUT_DIR.get(),
194                String.class, false, false, false);
195    
196    
197    
198      /**
199       * The serial version UID for this serializable class.
200       */
201      private static final long serialVersionUID = -4994621474763299632L;
202    
203    
204    
205      // The backend IDs of the backends in which the audit should be performed.
206      private final List<String> backendIDs;
207    
208      // The names of the excluded auditors to use in the audit.
209      private final List<String> excludeAuditors;
210    
211      // The names of the included auditors to use in the audit.
212      private final List<String> includeAuditors;
213    
214      // The report filters to select entries to audit.
215      private final List<String> reportFilters;
216    
217      // The path of the output directory to use for report data files.
218      private final String outputDirectory;
219    
220    
221    
222      /**
223       * Creates a new uninitialized audit data security task instance which should
224       * only be used for obtaining general information about this task, including
225       * the task name, description, and supported properties.  Attempts to use a
226       * task created with this constructor for any other reason will likely fail.
227       */
228      public AuditDataSecurityTask()
229      {
230        excludeAuditors = null;
231        includeAuditors = null;
232        backendIDs      = null;
233        reportFilters   = null;
234        outputDirectory = null;
235      }
236    
237    
238    
239      /**
240       * Creates a new audit data security task with the provided information and
241       * default settings for all general task properties.
242       *
243       * @param  includeAuditors  The names of the auditors that should be used to
244       *                          examine the data.  It may be {@code null} or empty
245       *                          if an exclude list should be provided, or if all
246       *                          enabled auditors should be invoked.  You must not
247       *                          provide both include and exclude auditors.
248       * @param  excludeAuditors  The names of the auditors that should be excluded
249       *                          when examining the data.  It may be {@code null}
250       *                          or empty if an include list should be provided, or
251       *                          if all enabled auditors should be invoked.  You
252       *                          must not provide both include and exclude
253       *                          auditors.
254       * @param  backendIDs       The backend IDs of the backends containing the
255       *                          data to examine.  It may be {@code null} or empty
256       *                          if all supported backends should be selected.
257       * @param  reportFilters    A set of filters which identify entries that
258       *                          should be examined.  It may be {@code null} or
259       *                          empty if all entries should be examined.
260       * @param  outputDirectory  The path to the output directory (on the server
261       *                          filesystem) in which report data files should be
262       *                          written.  It may be {@code null} if a default
263       *                          output directory should be used.
264       */
265      public AuditDataSecurityTask(final List<String> includeAuditors,
266                                   final List<String> excludeAuditors,
267                                   final List<String> backendIDs,
268                                   final List<String> reportFilters,
269                                   final String outputDirectory)
270      {
271        this(null, includeAuditors, excludeAuditors, backendIDs, reportFilters,
272             outputDirectory, null, null, null, null, null);
273      }
274    
275    
276    
277      /**
278       * Creates a new audit data security task with the provided information.
279       *
280       * @param  taskID                  The task ID to use for this task.  If it is
281       *                                 {@code null} then a UUID will be generated
282       *                                 for use as the task ID.
283       * @param  includeAuditors         The names of the auditors that should be
284       *                                 used to examine the data.  It may be
285       *                                 {@code null} or empty if an exclude list
286       *                                 should be provided, or if all enabled
287       *                                 auditors should be invoked.  You must not
288       *                                 provide both include and exclude auditors.
289       * @param  excludeAuditors         The names of the auditors that should be
290       *                                 excluded when examining the data.  It may
291       *                                 be {@code null} or empty if an include list
292       *                                 should be provided, or if all enabled
293       *                                 auditors should be invoked.  You must not
294       *                                 provide both include and exclude auditors.
295       * @param  backendIDs              The backend IDs of the backends containing
296       *                                 the data to examine.  It may be
297       *                                 {@code null} or empty if all supported
298       *                                 backends should be selected.
299       * @param  reportFilters           A set of filters which identify entries
300       *                                 that should be examined.  It may be
301       *                                 {@code null} or empty if all entries should
302       *                                 be examined.
303       * @param  outputDirectory         The path to the output directory (on the
304       *                                 server filesystem) in which report data
305       *                                 files should be written.  It may be
306       *                                 {@code null} if a default output directory
307       *                                 should be used.
308       * @param  scheduledStartTime      The time that this task should start
309       *                                 running.
310       * @param  dependencyIDs           The list of task IDs that will be required
311       *                                 to complete before this task will be
312       *                                 eligible to start.
313       * @param  failedDependencyAction  Indicates what action should be taken if
314       *                                 any of the dependencies for this task do
315       *                                 not complete successfully.
316       * @param  notifyOnCompletion      The list of e-mail addresses of individuals
317       *                                 that should be notified when this task
318       *                                 completes.
319       * @param  notifyOnError           The list of e-mail addresses of individuals
320       *                                 that should be notified if this task does
321       *                                 not complete successfully.
322       */
323      public AuditDataSecurityTask(final String taskID,
324                  final List<String> includeAuditors,
325                  final List<String> excludeAuditors, final List<String> backendIDs,
326                  final List<String> reportFilters, final String outputDirectory,
327                  final Date scheduledStartTime, final List<String> dependencyIDs,
328                  final FailedDependencyAction failedDependencyAction,
329                  final List<String> notifyOnCompletion,
330                  final List<String> notifyOnError)
331      {
332        super(taskID, AUDIT_DATA_SECURITY_TASK_CLASS, scheduledStartTime,
333             dependencyIDs, failedDependencyAction, notifyOnCompletion,
334             notifyOnError);
335    
336        this.includeAuditors = getStringList(includeAuditors);
337        this.excludeAuditors = getStringList(excludeAuditors);
338        this.backendIDs      = getStringList(backendIDs);
339        this.reportFilters   = getStringList(reportFilters);
340        this.outputDirectory = outputDirectory;
341    
342        ensureTrue(
343             (this.includeAuditors.isEmpty() || this.excludeAuditors.isEmpty()),
344             "You cannot request both include and exclude auditors.");
345      }
346    
347    
348    
349      /**
350       * Creates a new audit data security task from the provided entry.
351       *
352       * @param  entry  The entry to use to create this audit data security task.
353       *
354       * @throws  TaskException  If the provided entry cannot be parsed as an audit
355       *                         data security task entry.
356       */
357      public AuditDataSecurityTask(final Entry entry)
358             throws TaskException
359      {
360        super(entry);
361    
362        includeAuditors = Collections.unmodifiableList(StaticUtils.toNonNullList(
363             entry.getAttributeValues(ATTR_INCLUDE_AUDITOR)));
364        excludeAuditors = Collections.unmodifiableList(StaticUtils.toNonNullList(
365             entry.getAttributeValues(ATTR_EXCLUDE_AUDITOR)));
366        backendIDs = Collections.unmodifiableList(StaticUtils.toNonNullList(
367             entry.getAttributeValues(ATTR_BACKEND_ID)));
368        reportFilters = Collections.unmodifiableList(StaticUtils.toNonNullList(
369             entry.getAttributeValues(ATTR_REPORT_FILTER)));
370        outputDirectory = entry.getAttributeValue(ATTR_OUTPUT_DIRECTORY);
371      }
372    
373    
374    
375      /**
376       * Creates a new audit data security task from the provided set of task
377       * properties.
378       *
379       * @param  properties  The set of task properties and their corresponding
380       *                     values to use for the task.  It must not be
381       *                     {@code null}.
382       *
383       * @throws  TaskException  If the provided set of properties cannot be used to
384       *                         create a valid audit data security task.
385       */
386      public AuditDataSecurityTask(final Map<TaskProperty,List<Object>> properties)
387             throws TaskException
388      {
389        super(AUDIT_DATA_SECURITY_TASK_CLASS, properties);
390    
391        String outputDir = null;
392        final LinkedList<String> includeAuditorsList = new LinkedList<String>();
393        final LinkedList<String> excludeAuditorsList = new LinkedList<String>();
394        final LinkedList<String> backendIDList       = new LinkedList<String>();
395        final LinkedList<String> reportFilterList    = new LinkedList<String>();
396        for (final Map.Entry<TaskProperty,List<Object>> entry :
397             properties.entrySet())
398        {
399          final TaskProperty p = entry.getKey();
400          final String attrName = StaticUtils.toLowerCase(p.getAttributeName());
401          final List<Object> values = entry.getValue();
402    
403          if (attrName.equals(ATTR_INCLUDE_AUDITOR))
404          {
405            final String[] s = parseStrings(p, values, null);
406            if (s != null)
407            {
408              includeAuditorsList.addAll(Arrays.asList(s));
409            }
410          }
411          else if (attrName.equals(ATTR_EXCLUDE_AUDITOR))
412          {
413            final String[] s = parseStrings(p, values, null);
414            if (s != null)
415            {
416              excludeAuditorsList.addAll(Arrays.asList(s));
417            }
418          }
419          else if (attrName.equals(ATTR_BACKEND_ID))
420          {
421            final String[] s = parseStrings(p, values, null);
422            if (s != null)
423            {
424              backendIDList.addAll(Arrays.asList(s));
425            }
426          }
427          else if (attrName.equals(ATTR_REPORT_FILTER))
428          {
429            final String[] s = parseStrings(p, values, null);
430            if (s != null)
431            {
432              reportFilterList.addAll(Arrays.asList(s));
433            }
434          }
435          else if (attrName.equals(ATTR_OUTPUT_DIRECTORY))
436          {
437            outputDir = parseString(p, values, null);
438          }
439        }
440    
441        includeAuditors = Collections.unmodifiableList(includeAuditorsList);
442        excludeAuditors = Collections.unmodifiableList(excludeAuditorsList);
443        backendIDs      = Collections.unmodifiableList(backendIDList);
444        reportFilters   = Collections.unmodifiableList(reportFilterList);
445        outputDirectory = outputDir;
446    
447        if ((! includeAuditors.isEmpty()) && (! excludeAuditors.isEmpty()))
448        {
449          throw new TaskException(
450               ERR_AUDIT_DATA_SECURITY_BOTH_INCLUDE_AND_EXCLUDE_AUDITORS.get());
451        }
452      }
453    
454    
455    
456      /**
457       * {@inheritDoc}
458       */
459      @Override()
460      public String getTaskName()
461      {
462        return INFO_TASK_NAME_AUDIT_DATA_SECURITY.get();
463      }
464    
465    
466    
467      /**
468       * {@inheritDoc}
469       */
470      @Override()
471      public String getTaskDescription()
472      {
473        return INFO_TASK_DESCRIPTION_AUDIT_DATA_SECURITY.get();
474      }
475    
476    
477    
478      /**
479       * Retrieves the names of the auditors that should be invoked during the
480       * data security audit.
481       *
482       * @return  The names of the include auditors that should be used for the
483       *          task, or an empty list if either an exclude list should be used or
484       *          all enabled auditors should be used.
485       */
486      public List<String> getIncludeAuditors()
487      {
488        return includeAuditors;
489      }
490    
491    
492    
493      /**
494       * Retrieves the names of the auditors that should not be invoked during the
495       * audit.
496       *
497       * @return  The names of the exclude auditors that should be used for the
498       *          task, or an empty list if either an include list should be used or
499       *          all enabled auditors should be used.
500       */
501      public List<String> getExcludeAuditors()
502      {
503        return excludeAuditors;
504      }
505    
506    
507    
508      /**
509       * Retrieves the backend IDs of the backends that should be examined during
510       * the course of the audit.
511       *
512       * @return  The backend IDs of the backends that should be examined during the
513       *          course of the audit, or an empty list if all backends that support
514       *          this capability should be used.
515       */
516      public List<String> getBackendIDs()
517      {
518        return backendIDs;
519      }
520    
521    
522    
523      /**
524       * Retrieves the string representations of the report filters that should be
525       * used to identify which entries should be examined during the course of the
526       * audit.
527       *
528       * @return  The string representations of the report filters that should be
529       *          used to identify which entries should be examined during the
530       *          course of the audit, or an empty list if all entries should be
531       *          examined.
532       */
533      public List<String> getReportFilterStrings()
534      {
535        return reportFilters;
536      }
537    
538    
539    
540      /**
541       * Retrieves the parsed report filters that should be used to identify which
542       * entries should be examined during the course of the audit.
543       *
544       * @return  The parsed report filters that should be used to identify which
545       *          entries should be examined during the course of the audit, or an
546       *          empty list if all entries should be examined.
547       *
548       * @throws  LDAPException  If any of the filter strings cannot be parsed as a
549       *                         valid filter.
550       */
551      public List<Filter> getReportFilters()
552             throws LDAPException
553      {
554        if (reportFilters.isEmpty())
555        {
556          return Collections.emptyList();
557        }
558    
559        final ArrayList<Filter> filterList =
560             new ArrayList<Filter>(reportFilters.size());
561        for (final String filter : reportFilters)
562        {
563          filterList.add(Filter.create(filter));
564        }
565        return Collections.unmodifiableList(filterList);
566      }
567    
568    
569    
570      /**
571       * Retrieves the path to the directory on the server filesystem in which the
572       * report output files should be written.
573       *
574       * @return  The path to the directory on the server filesystem in which the
575       *          report output files should be written.
576       */
577      public String getOutputDirectory()
578      {
579        return outputDirectory;
580      }
581    
582    
583    
584      /**
585       * {@inheritDoc}
586       */
587      @Override()
588      protected List<String> getAdditionalObjectClasses()
589      {
590        return Arrays.asList(OC_AUDIT_DATA_SECURITY_TASK);
591      }
592    
593    
594    
595      /**
596       * {@inheritDoc}
597       */
598      @Override()
599      protected List<Attribute> getAdditionalAttributes()
600      {
601        final LinkedList<Attribute> attrList = new LinkedList<Attribute>();
602    
603        if (! includeAuditors.isEmpty())
604        {
605          attrList.add(new Attribute(ATTR_INCLUDE_AUDITOR, includeAuditors));
606        }
607    
608        if (! excludeAuditors.isEmpty())
609        {
610          attrList.add(new Attribute(ATTR_EXCLUDE_AUDITOR, excludeAuditors));
611        }
612    
613        if (! backendIDs.isEmpty())
614        {
615          attrList.add(new Attribute(ATTR_BACKEND_ID, backendIDs));
616        }
617    
618        if (! reportFilters.isEmpty())
619        {
620          attrList.add(new Attribute(ATTR_REPORT_FILTER, reportFilters));
621        }
622    
623        if (outputDirectory != null)
624        {
625          attrList.add(new Attribute(ATTR_OUTPUT_DIRECTORY, outputDirectory));
626        }
627    
628        return attrList;
629      }
630    
631    
632    
633      /**
634       * {@inheritDoc}
635       */
636      @Override()
637      public List<TaskProperty> getTaskSpecificProperties()
638      {
639        return Collections.unmodifiableList(Arrays.asList(
640             PROPERTY_INCLUDE_AUDITOR,
641             PROPERTY_EXCLUDE_AUDITOR,
642             PROPERTY_BACKEND_ID,
643             PROPERTY_REPORT_FILTER,
644             PROPERTY_OUTPUT_DIRECTORY));
645      }
646    
647    
648    
649      /**
650       * {@inheritDoc}
651       */
652      @Override()
653      public Map<TaskProperty,List<Object>> getTaskPropertyValues()
654      {
655        final LinkedHashMap<TaskProperty,List<Object>> props =
656             new LinkedHashMap<TaskProperty,List<Object>>(5);
657    
658        if (! includeAuditors.isEmpty())
659        {
660          props.put(PROPERTY_INCLUDE_AUDITOR,
661               Collections.<Object>unmodifiableList(includeAuditors));
662        }
663    
664        if (! excludeAuditors.isEmpty())
665        {
666          props.put(PROPERTY_EXCLUDE_AUDITOR,
667               Collections.<Object>unmodifiableList(excludeAuditors));
668        }
669    
670        if (! backendIDs.isEmpty())
671        {
672          props.put(PROPERTY_BACKEND_ID,
673               Collections.<Object>unmodifiableList(backendIDs));
674        }
675    
676        if (! reportFilters.isEmpty())
677        {
678          props.put(PROPERTY_REPORT_FILTER,
679               Collections.<Object>unmodifiableList(reportFilters));
680        }
681    
682        if (outputDirectory != null)
683        {
684          props.put(PROPERTY_OUTPUT_DIRECTORY,
685               Collections.<Object>unmodifiableList(Arrays.asList(
686                    outputDirectory)));
687        }
688    
689        return Collections.unmodifiableMap(props);
690      }
691    
692    
693    
694      /**
695       * Retrieves an unmodifiable list using information from the provided list.
696       * If the given list is {@code null}, then an empty list will be returned.
697       * Otherwise, an unmodifiable version of the provided list will be returned.
698       *
699       * @param  l  The list to be processed.
700       *
701       * @return  The resulting string list.
702       */
703      private static List<String> getStringList(final List<String> l)
704      {
705        if (l == null)
706        {
707          return Collections.emptyList();
708        }
709        else
710        {
711          return Collections.unmodifiableList(l);
712        }
713      }
714    }