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