001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2007-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2012-2015 ForgeRock AS 026 */ 027package org.opends.admin.ads; 028 029import static org.forgerock.util.Utils.*; 030import static org.opends.messages.QuickSetupMessages.*; 031 032import java.io.File; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.LinkedHashSet; 036import java.util.LinkedList; 037import java.util.Map; 038import java.util.Set; 039import java.util.SortedSet; 040import java.util.TreeSet; 041 042import javax.naming.CompositeName; 043import javax.naming.InvalidNameException; 044import javax.naming.NameAlreadyBoundException; 045import javax.naming.NameNotFoundException; 046import javax.naming.NamingEnumeration; 047import javax.naming.NamingException; 048import javax.naming.NoPermissionException; 049import javax.naming.NotContextException; 050import javax.naming.directory.Attribute; 051import javax.naming.directory.Attributes; 052import javax.naming.directory.BasicAttribute; 053import javax.naming.directory.BasicAttributes; 054import javax.naming.directory.DirContext; 055import javax.naming.directory.SearchControls; 056import javax.naming.directory.SearchResult; 057import javax.naming.ldap.Control; 058import javax.naming.ldap.InitialLdapContext; 059import javax.naming.ldap.LdapContext; 060import javax.naming.ldap.LdapName; 061import javax.naming.ldap.Rdn; 062 063import org.forgerock.i18n.LocalizableMessage; 064import org.forgerock.i18n.slf4j.LocalizedLogger; 065import org.opends.admin.ads.ADSContextException.ErrorType; 066import org.opends.admin.ads.util.ConnectionUtils; 067import org.opends.quicksetup.Constants; 068import org.opends.server.schema.SchemaConstants; 069 070/** Class used to update and read the contents of the Administration Data. */ 071public class ADSContext 072{ 073 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 074 075 /** 076 * Enumeration containing the different server properties syntaxes that could 077 * be stored in the ADS. 078 */ 079 public enum ADSPropertySyntax 080 { 081 /** String syntax. */ 082 STRING, 083 /** Integer syntax. */ 084 INTEGER, 085 /** Boolean syntax. */ 086 BOOLEAN, 087 /** Certificate;binary syntax. */ 088 CERTIFICATE_BINARY 089 } 090 091 /** Enumeration containing the different server properties that are stored in the ADS. */ 092 public enum ServerProperty 093 { 094 /** The ID used to identify the server. */ 095 ID("id",ADSPropertySyntax.STRING), 096 /** The host name of the server. */ 097 HOST_NAME("hostname",ADSPropertySyntax.STRING), 098 /** The LDAP port of the server. */ 099 LDAP_PORT("ldapport",ADSPropertySyntax.INTEGER), 100 /** The JMX port of the server. */ 101 JMX_PORT("jmxport",ADSPropertySyntax.INTEGER), 102 /** The JMX secure port of the server. */ 103 JMXS_PORT("jmxsport",ADSPropertySyntax.INTEGER), 104 /** The LDAPS port of the server. */ 105 LDAPS_PORT("ldapsport",ADSPropertySyntax.INTEGER), 106 /** The administration connector port of the server. */ 107 ADMIN_PORT("adminport",ADSPropertySyntax.INTEGER), 108 /** The certificate used by the server. */ 109 CERTIFICATE("certificate",ADSPropertySyntax.STRING), 110 /** The path where the server is installed. */ 111 INSTANCE_PATH("instancepath",ADSPropertySyntax.STRING), 112 /** The description of the server. */ 113 DESCRIPTION("description",ADSPropertySyntax.STRING), 114 /** The OS of the machine where the server is installed. */ 115 HOST_OS("os",ADSPropertySyntax.STRING), 116 /** Whether LDAP is enabled or not. */ 117 LDAP_ENABLED("ldapEnabled",ADSPropertySyntax.BOOLEAN), 118 /** Whether LDAPS is enabled or not. */ 119 LDAPS_ENABLED("ldapsEnabled",ADSPropertySyntax.BOOLEAN), 120 /** Whether ADMIN is enabled or not. */ 121 ADMIN_ENABLED("adminEnabled",ADSPropertySyntax.BOOLEAN), 122 /** Whether StartTLS is enabled or not. */ 123 STARTTLS_ENABLED("startTLSEnabled",ADSPropertySyntax.BOOLEAN), 124 /** Whether JMX is enabled or not. */ 125 JMX_ENABLED("jmxEnabled",ADSPropertySyntax.BOOLEAN), 126 /** Whether JMX is enabled or not. */ 127 JMXS_ENABLED("jmxsEnabled",ADSPropertySyntax.BOOLEAN), 128 /** The location of the server. */ 129 LOCATION("location",ADSPropertySyntax.STRING), 130 /** The groups to which this server belongs. */ 131 GROUPS("memberofgroups",ADSPropertySyntax.STRING), 132 /** The unique name of the instance key public-key certificate. */ 133 INSTANCE_KEY_ID("ds-cfg-key-id",ADSPropertySyntax.STRING), 134 /** 135 * The instance key-pair public-key certificate. Note: This attribute 136 * belongs to an instance key entry, separate from the server entry and 137 * named by the ds-cfg-key-id attribute from the server entry. 138 */ 139 INSTANCE_PUBLIC_KEY_CERTIFICATE("ds-cfg-public-key-certificate", ADSPropertySyntax.CERTIFICATE_BINARY); 140 141 private String attrName; 142 private ADSPropertySyntax attSyntax; 143 144 /** 145 * Private constructor. 146 * 147 * @param n 148 * the name of the attribute. 149 * @param s 150 * the name of the syntax. 151 */ 152 private ServerProperty(String n, ADSPropertySyntax s) 153 { 154 attrName = n; 155 attSyntax = s; 156 } 157 158 /** 159 * Returns the attribute name. 160 * 161 * @return the attribute name. 162 */ 163 public String getAttributeName() 164 { 165 return attrName; 166 } 167 168 /** 169 * Returns the attribute syntax. 170 * 171 * @return the attribute syntax. 172 */ 173 public ADSPropertySyntax getAttributeSyntax() 174 { 175 return attSyntax; 176 } 177 } 178 179 /** Default global admin UID. */ 180 public static final String GLOBAL_ADMIN_UID = "admin"; 181 182 private static Map<String, ServerProperty> NAME_TO_SERVER_PROPERTY; 183 184 /** 185 * Get a ServerProperty associated to a name. 186 * 187 * @param name 188 * The name of the property to retrieve. 189 * @return The corresponding ServerProperty or null if name doesn't match with 190 * an existing property. 191 */ 192 public static ServerProperty getServerPropFromName(String name) 193 { 194 if (NAME_TO_SERVER_PROPERTY == null) 195 { 196 NAME_TO_SERVER_PROPERTY = new HashMap<>(); 197 for (ServerProperty s : ServerProperty.values()) 198 { 199 NAME_TO_SERVER_PROPERTY.put(s.getAttributeName(), s); 200 } 201 } 202 return NAME_TO_SERVER_PROPERTY.get(name); 203 } 204 205 /** The list of server properties that are multivalued. */ 206 private static final Set<ServerProperty> MULTIVALUED_SERVER_PROPERTIES = new HashSet<>(); 207 static 208 { 209 MULTIVALUED_SERVER_PROPERTIES.add(ServerProperty.GROUPS); 210 } 211 212 /** The default server group which will contain all registered servers. */ 213 public static final String ALL_SERVERGROUP_NAME = "all-servers"; 214 215 /** Enumeration containing the different server group properties that are stored in the ADS. */ 216 public enum ServerGroupProperty 217 { 218 /** The UID of the server group. */ 219 UID("cn"), 220 /** The description of the server group. */ 221 DESCRIPTION("description"), 222 /** The members of the server group. */ 223 MEMBERS("uniqueMember"); 224 225 private String attrName; 226 227 /** 228 * Private constructor. 229 * 230 * @param n 231 * the attribute name. 232 */ 233 private ServerGroupProperty(String n) 234 { 235 attrName = n; 236 } 237 238 /** 239 * Returns the attribute name. 240 * 241 * @return the attribute name. 242 */ 243 public String getAttributeName() 244 { 245 return attrName; 246 } 247 } 248 249 /** The list of server group properties that are multivalued. */ 250 private static final Set<ServerGroupProperty> MULTIVALUED_SERVER_GROUP_PROPERTIES = new HashSet<>(); 251 static 252 { 253 MULTIVALUED_SERVER_GROUP_PROPERTIES.add(ServerGroupProperty.MEMBERS); 254 } 255 256 /** The enumeration containing the different Administrator properties. */ 257 public enum AdministratorProperty 258 { 259 /** The UID of the administrator. */ 260 UID("id", ADSPropertySyntax.STRING), 261 /** The password of the administrator. */ 262 PASSWORD("password", ADSPropertySyntax.STRING), 263 /** The description of the administrator. */ 264 DESCRIPTION("description", ADSPropertySyntax.STRING), 265 /** The DN of the administrator. */ 266 ADMINISTRATOR_DN("administrator dn", ADSPropertySyntax.STRING), 267 /** The administrator privilege. */ 268 PRIVILEGE("privilege", ADSPropertySyntax.STRING); 269 270 private String attrName; 271 private ADSPropertySyntax attrSyntax; 272 273 /** 274 * Private constructor. 275 * 276 * @param n 277 * the name of the attribute. 278 * @param s 279 * the name of the syntax. 280 */ 281 private AdministratorProperty(String n, ADSPropertySyntax s) 282 { 283 attrName = n; 284 attrSyntax = s; 285 } 286 287 /** 288 * Returns the attribute name. 289 * 290 * @return the attribute name. 291 */ 292 public String getAttributeName() 293 { 294 return attrName; 295 } 296 297 /** 298 * Returns the attribute syntax. 299 * 300 * @return the attribute syntax. 301 */ 302 public ADSPropertySyntax getAttributeSyntax() 303 { 304 return attrSyntax; 305 } 306 } 307 308 private static HashMap<String, AdministratorProperty> nameToAdminUserProperty; 309 310 /** 311 * Get a AdministratorProperty associated to a name. 312 * 313 * @param name 314 * The name of the property to retrieve. 315 * @return The corresponding AdministratorProperty or null if name doesn't 316 * match with an existing property. 317 */ 318 public static AdministratorProperty getAdminUserPropFromName(String name) 319 { 320 if (nameToAdminUserProperty == null) 321 { 322 nameToAdminUserProperty = new HashMap<>(); 323 for (AdministratorProperty u : AdministratorProperty.values()) 324 { 325 nameToAdminUserProperty.put(u.getAttributeName(), u); 326 } 327 } 328 return nameToAdminUserProperty.get(name); 329 } 330 331 /** The context used to retrieve information. */ 332 private final InitialLdapContext dirContext; 333 334 /** 335 * Constructor of the ADSContext. 336 * 337 * @param dirContext 338 * the DirContext that must be used to retrieve information. 339 */ 340 public ADSContext(InitialLdapContext dirContext) 341 { 342 this.dirContext = dirContext; 343 } 344 345 /** 346 * Returns the DirContext used to retrieve information by this ADSContext. 347 * 348 * @return the DirContext used to retrieve information by this ADSContext. 349 */ 350 public InitialLdapContext getDirContext() 351 { 352 return dirContext; 353 } 354 355 /** 356 * Method called to register a server in the ADS. 357 * 358 * @param serverProperties 359 * the properties of the server. 360 * @throws ADSContextException 361 * if the server could not be registered. 362 */ 363 public void registerServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException 364 { 365 LdapName dn = makeDNFromServerProperties(serverProperties); 366 BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties, true); 367 try 368 { 369 // This check is required because by default the server container entry 370 // does not exist. 371 if (!isExistingEntry(nameFromDN(getServerContainerDN()))) 372 { 373 createContainerEntry(getServerContainerDN()); 374 } 375 dirContext.createSubcontext(dn, attrs).close(); 376 if (serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) 377 { 378 registerInstanceKeyCertificate(serverProperties, dn); 379 } 380 381 // register this server into "all" groups 382 Map<ServerGroupProperty, Object> serverGroupProperties = new HashMap<>(); 383 Set<String> memberList = getServerGroupMemberList(ALL_SERVERGROUP_NAME); 384 if (memberList == null) 385 { 386 memberList = new HashSet<>(); 387 } 388 String newMember = "cn=" + Rdn.escapeValue(serverProperties.get(ServerProperty.ID)); 389 390 memberList.add(newMember); 391 serverGroupProperties.put(ServerGroupProperty.MEMBERS, memberList); 392 393 updateServerGroup(ALL_SERVERGROUP_NAME, serverGroupProperties); 394 395 // Update the server property "GROUPS" 396 Set<?> rawGroupList = (Set<?>) serverProperties.get(ServerProperty.GROUPS); 397 Set<String> groupList = new HashSet<>(); 398 if (rawGroupList != null) 399 { 400 for (Object elm : rawGroupList) 401 { 402 groupList.add(elm.toString()); 403 } 404 } 405 groupList.add(ALL_SERVERGROUP_NAME); 406 serverProperties.put(ServerProperty.GROUPS, groupList); 407 updateServer(serverProperties, null); 408 } 409 catch (ADSContextException ace) 410 { 411 throw ace; 412 } 413 catch (NameAlreadyBoundException x) 414 { 415 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 416 } 417 catch (Exception x) 418 { 419 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 420 } 421 } 422 423 /** 424 * Method called to update the properties of a server in the ADS. 425 * 426 * @param serverProperties 427 * the new properties of the server. 428 * @param newServerId 429 * The new server Identifier, or null. 430 * @throws ADSContextException 431 * if the server could not be registered. 432 */ 433 public void updateServer(Map<ServerProperty, Object> serverProperties, String newServerId) throws ADSContextException 434 { 435 LdapName dn = makeDNFromServerProperties(serverProperties); 436 437 try 438 { 439 if (newServerId != null) 440 { 441 Map<ServerProperty, Object> newServerProps = new HashMap<>(serverProperties); 442 newServerProps.put(ServerProperty.ID, newServerId); 443 LdapName newDn = makeDNFromServerProperties(newServerProps); 444 dirContext.rename(dn, newDn); 445 dn = newDn; 446 serverProperties.put(ServerProperty.ID, newServerId); 447 } 448 BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties, false); 449 dirContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attrs); 450 if (serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) 451 { 452 registerInstanceKeyCertificate(serverProperties, dn); 453 } 454 } 455 catch (ADSContextException ace) 456 { 457 throw ace; 458 } 459 catch (NameNotFoundException x) 460 { 461 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 462 } 463 catch (Exception x) 464 { 465 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 466 } 467 } 468 469 /** 470 * Method called to unregister a server in the ADS. Note that the server's 471 * instance key-pair public-key certificate entry (created in 472 * <tt>registerServer()</tt>) is left untouched. 473 * 474 * @param serverProperties 475 * the properties of the server. 476 * @throws ADSContextException 477 * if the server could not be unregistered. 478 */ 479 public void unregisterServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException 480 { 481 LdapName dn = makeDNFromServerProperties(serverProperties); 482 try 483 { 484 // Unregister the server from the server groups. 485 String member = "cn=" + Rdn.escapeValue(serverProperties.get(ServerProperty.ID)); 486 Set<Map<ServerGroupProperty, Object>> serverGroups = readServerGroupRegistry(); 487 for (Map<ServerGroupProperty, Object> serverGroup : serverGroups) 488 { 489 Set<?> memberList = (Set<?>) serverGroup.get(ServerGroupProperty.MEMBERS); 490 if (memberList != null && memberList.remove(member)) 491 { 492 Map<ServerGroupProperty, Object> serverGroupProperties = new HashMap<>(); 493 serverGroupProperties.put(ServerGroupProperty.MEMBERS, memberList); 494 String groupName = (String) serverGroup.get(ServerGroupProperty.UID); 495 updateServerGroup(groupName, serverGroupProperties); 496 } 497 } 498 499 dirContext.destroySubcontext(dn); 500 } 501 catch (NameNotFoundException x) 502 { 503 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 504 } 505 catch (NamingException x) 506 { 507 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 508 } 509 510 // Unregister the server in server groups 511 NamingEnumeration<SearchResult> ne = null; 512 try 513 { 514 SearchControls sc = new SearchControls(); 515 516 String serverID = getServerID(serverProperties); 517 if (serverID != null) 518 { 519 String memberAttrName = ServerGroupProperty.MEMBERS.getAttributeName(); 520 String filter = "(" + memberAttrName + "=cn=" + serverID + ")"; 521 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 522 ne = dirContext.search(getServerGroupContainerDN(), filter, sc); 523 while (ne.hasMore()) 524 { 525 SearchResult sr = ne.next(); 526 String groupDn = sr.getNameInNamespace(); 527 BasicAttribute newAttr = new BasicAttribute(memberAttrName); 528 NamingEnumeration<? extends Attribute> attrs = sr.getAttributes().getAll(); 529 try 530 { 531 while (attrs.hasMore()) 532 { 533 Attribute attr = attrs.next(); 534 String attrID = attr.getID(); 535 536 if (attrID.equalsIgnoreCase(memberAttrName)) 537 { 538 NamingEnumeration<?> ae = attr.getAll(); 539 try 540 { 541 while (ae.hasMore()) 542 { 543 String value = (String) ae.next(); 544 if (!value.equalsIgnoreCase("cn=" + serverID)) 545 { 546 newAttr.add(value); 547 } 548 } 549 } 550 finally 551 { 552 handleCloseNamingEnumeration(ae); 553 } 554 } 555 } 556 } 557 finally 558 { 559 handleCloseNamingEnumeration(attrs); 560 } 561 BasicAttributes newAttrs = new BasicAttributes(); 562 newAttrs.put(newAttr); 563 if (newAttr.size() > 0) 564 { 565 dirContext.modifyAttributes(groupDn, DirContext.REPLACE_ATTRIBUTE, newAttrs); 566 } 567 else 568 { 569 dirContext.modifyAttributes(groupDn, DirContext.REMOVE_ATTRIBUTE, newAttrs); 570 } 571 } 572 } 573 } 574 catch (NameNotFoundException x) 575 { 576 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 577 } 578 catch (NoPermissionException x) 579 { 580 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 581 } 582 catch (NamingException x) 583 { 584 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 585 } 586 finally 587 { 588 handleCloseNamingEnumeration(ne); 589 } 590 } 591 592 /** 593 * Returns whether a given server is already registered or not. 594 * 595 * @param serverProperties 596 * the server properties. 597 * @return <CODE>true</CODE> if the server was registered and 598 * <CODE>false</CODE> otherwise. 599 * @throws ADSContextException 600 * if something went wrong. 601 */ 602 public boolean isServerAlreadyRegistered(Map<ServerProperty, Object> serverProperties) throws ADSContextException 603 { 604 return isExistingEntry(makeDNFromServerProperties(serverProperties)); 605 } 606 607 /** 608 * Returns whether a given administrator is already registered or not. 609 * 610 * @param uid 611 * the administrator UID. 612 * @return <CODE>true</CODE> if the administrator was registered and 613 * <CODE>false</CODE> otherwise. 614 * @throws ADSContextException 615 * if something went wrong. 616 */ 617 public boolean isAdministratorAlreadyRegistered(String uid) throws ADSContextException 618 { 619 return isExistingEntry(makeDNFromAdministratorProperties(uid)); 620 } 621 622 /** 623 * A convenience method that takes some server properties as parameter and if 624 * there is no server registered associated with those properties, registers 625 * it and if it is already registered, updates it. 626 * 627 * @param serverProperties 628 * the server properties. 629 * @return 0 if the server was registered; 1 if updated (i.e., the server 630 * entry was already in ADS). 631 * @throws ADSContextException 632 * if something goes wrong. 633 */ 634 public int registerOrUpdateServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException 635 { 636 try 637 { 638 registerServer(serverProperties); 639 return 0; 640 } 641 catch (ADSContextException x) 642 { 643 if (x.getError() == ErrorType.ALREADY_REGISTERED) 644 { 645 updateServer(serverProperties, null); 646 return 1; 647 } 648 649 throw x; 650 } 651 } 652 653 /** 654 * Returns the member list of a group of server. 655 * 656 * @param serverGroupId 657 * The group name. 658 * @return the member list of a group of server. 659 * @throws ADSContextException 660 * if something goes wrong. 661 */ 662 public Set<String> getServerGroupMemberList(String serverGroupId) throws ADSContextException 663 { 664 LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN()); 665 666 Set<String> result = new HashSet<>(); 667 NamingEnumeration<SearchResult> srs = null; 668 NamingEnumeration<? extends Attribute> ne = null; 669 try 670 { 671 SearchControls sc = new SearchControls(); 672 sc.setSearchScope(SearchControls.OBJECT_SCOPE); 673 srs = getDirContext().search(dn, "(objectclass=*)", sc); 674 675 if (!srs.hasMore()) 676 { 677 return result; 678 } 679 Attributes attrs = srs.next().getAttributes(); 680 ne = attrs.getAll(); 681 while (ne.hasMore()) 682 { 683 Attribute attr = ne.next(); 684 String attrID = attr.getID(); 685 686 if (!attrID.toLowerCase().equals(ServerGroupProperty.MEMBERS.getAttributeName().toLowerCase())) 687 { 688 continue; 689 } 690 691 // We have the members list 692 NamingEnumeration<?> ae = attr.getAll(); 693 try 694 { 695 while (ae.hasMore()) 696 { 697 result.add((String) ae.next()); 698 } 699 } 700 finally 701 { 702 handleCloseNamingEnumeration(ae); 703 } 704 break; 705 } 706 } 707 catch (NameNotFoundException x) 708 { 709 result = new HashSet<>(); 710 } 711 catch (NoPermissionException x) 712 { 713 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 714 } 715 catch (NamingException x) 716 { 717 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 718 } 719 finally 720 { 721 handleCloseNamingEnumeration(srs); 722 handleCloseNamingEnumeration(ne); 723 } 724 return result; 725 } 726 727 /** 728 * Returns a set containing the servers that are registered in the ADS. 729 * 730 * @return a set containing the servers that are registered in the ADS. 731 * @throws ADSContextException 732 * if something goes wrong. 733 */ 734 public Set<Map<ServerProperty, Object>> readServerRegistry() throws ADSContextException 735 { 736 Set<Map<ServerProperty, Object>> result = new HashSet<>(); 737 NamingEnumeration<SearchResult> ne = null; 738 try 739 { 740 SearchControls sc = new SearchControls(); 741 742 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 743 ne = dirContext.search(getServerContainerDN(), "(objectclass=*)", sc); 744 while (ne.hasMore()) 745 { 746 SearchResult sr = ne.next(); 747 Map<ServerProperty, Object> properties = makePropertiesFromServerAttrs(sr.getAttributes()); 748 Object keyId = properties.get(ServerProperty.INSTANCE_KEY_ID); 749 if (keyId != null) 750 { 751 NamingEnumeration<SearchResult> ne2 = null; 752 try 753 { 754 SearchControls sc1 = new SearchControls(); 755 sc1.setSearchScope(SearchControls.ONELEVEL_SCOPE); 756 final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" }; 757 sc1.setReturningAttributes(attrIDs); 758 759 ne2 = dirContext.search(getInstanceKeysContainerDN(), "(ds-cfg-key-id=" + keyId + ")", sc); 760 boolean found = false; 761 while (ne2.hasMore()) 762 { 763 SearchResult certEntry = ne2.next(); 764 Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]); 765 properties.put(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, certAttr.get()); 766 found = true; 767 } 768 if (!found) 769 { 770 logger.warn(LocalizableMessage.raw("Could not find public key for " + properties)); 771 } 772 } 773 catch (NameNotFoundException x) 774 { 775 logger.warn(LocalizableMessage.raw("Could not find public key for " + properties)); 776 } 777 finally 778 { 779 handleCloseNamingEnumeration(ne2); 780 } 781 } 782 result.add(properties); 783 } 784 } 785 catch (NameNotFoundException x) 786 { 787 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 788 } 789 catch (NoPermissionException x) 790 { 791 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 792 } 793 catch (NamingException x) 794 { 795 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 796 } 797 finally 798 { 799 handleCloseNamingEnumeration(ne); 800 } 801 802 return result; 803 } 804 805 /** 806 * Creates a Server Group in the ADS. 807 * 808 * @param serverGroupProperties 809 * the properties of the server group to be created. 810 * @throws ADSContextException 811 * if something goes wrong. 812 */ 813 public void createServerGroup(Map<ServerGroupProperty, Object> serverGroupProperties) throws ADSContextException 814 { 815 LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties); 816 BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); 817 // Add the objectclass attribute value 818 Attribute oc = new BasicAttribute("objectclass"); 819 oc.add("top"); 820 oc.add("groupOfUniqueNames"); 821 attrs.put(oc); 822 try 823 { 824 DirContext ctx = dirContext.createSubcontext(dn, attrs); 825 ctx.close(); 826 } 827 catch (NameAlreadyBoundException x) 828 { 829 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 830 } 831 catch (NamingException x) 832 { 833 throw new ADSContextException(ErrorType.BROKEN_INSTALL, x); 834 } 835 } 836 837 /** 838 * Updates the properties of a Server Group in the ADS. 839 * 840 * @param serverGroupProperties 841 * the new properties of the server group to be updated. 842 * @param groupID 843 * The group name. 844 * @throws ADSContextException 845 * if something goes wrong. 846 */ 847 public void updateServerGroup(String groupID, Map<ServerGroupProperty, Object> serverGroupProperties) 848 throws ADSContextException 849 { 850 LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," + getServerGroupContainerDN()); 851 try 852 { 853 // Entry renaming ? 854 if (serverGroupProperties.containsKey(ServerGroupProperty.UID)) 855 { 856 String newGroupId = serverGroupProperties.get(ServerGroupProperty.UID).toString(); 857 if (!newGroupId.equals(groupID)) 858 { 859 // Rename to entry 860 LdapName newDN = nameFromDN("cn=" + Rdn.escapeValue(newGroupId) + "," + getServerGroupContainerDN()); 861 dirContext.rename(dn, newDN); 862 dn = newDN; 863 } 864 865 // In any case, we remove the "cn" attribute. 866 serverGroupProperties.remove(ServerGroupProperty.UID); 867 } 868 if (serverGroupProperties.isEmpty()) 869 { 870 return; 871 } 872 873 BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); 874 // attribute modification 875 dirContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attrs); 876 } 877 catch (NameNotFoundException x) 878 { 879 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 880 } 881 catch (NameAlreadyBoundException x) 882 { 883 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 884 } 885 catch (NamingException x) 886 { 887 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 888 } 889 } 890 891 /** 892 * Updates the properties of a Server Group in the ADS. 893 * 894 * @param serverGroupProperties 895 * the new properties of the server group to be updated. 896 * @param groupID 897 * The group name. 898 * @throws ADSContextException 899 * if something goes wrong. 900 */ 901 public void removeServerGroupProp(String groupID, Set<ServerGroupProperty> serverGroupProperties) 902 throws ADSContextException 903 { 904 LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," + getServerGroupContainerDN()); 905 BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); 906 try 907 { 908 dirContext.modifyAttributes(dn, DirContext.REMOVE_ATTRIBUTE, attrs); 909 } 910 catch (NameAlreadyBoundException x) 911 { 912 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 913 } 914 catch (NamingException x) 915 { 916 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 917 } 918 } 919 920 /** 921 * Deletes a Server Group in the ADS. 922 * 923 * @param serverGroupProperties 924 * the properties of the server group to be deleted. 925 * @throws ADSContextException 926 * if something goes wrong. 927 */ 928 public void deleteServerGroup(Map<ServerGroupProperty, Object> serverGroupProperties) throws ADSContextException 929 { 930 LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties); 931 try 932 { 933 dirContext.destroySubcontext(dn); 934 } 935 catch (NamingException x) 936 { 937 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 938 } 939 } 940 941 /** 942 * Returns a set containing the server groups that are defined in the ADS. 943 * 944 * @return a set containing the server groups that are defined in the ADS. 945 * @throws ADSContextException 946 * if something goes wrong. 947 */ 948 public Set<Map<ServerGroupProperty, Object>> readServerGroupRegistry() throws ADSContextException 949 { 950 Set<Map<ServerGroupProperty, Object>> result = new HashSet<>(); 951 NamingEnumeration<SearchResult> ne = null; 952 try 953 { 954 SearchControls sc = new SearchControls(); 955 956 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 957 ne = dirContext.search(getServerGroupContainerDN(), "(objectclass=*)", sc); 958 while (ne.hasMore()) 959 { 960 SearchResult sr = ne.next(); 961 Map<ServerGroupProperty, Object> properties = makePropertiesFromServerGroupAttrs(sr.getAttributes()); 962 result.add(properties); 963 } 964 } 965 catch (NameNotFoundException x) 966 { 967 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 968 } 969 catch (NoPermissionException x) 970 { 971 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 972 } 973 catch (NamingException x) 974 { 975 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 976 } 977 finally 978 { 979 handleCloseNamingEnumeration(ne); 980 } 981 return result; 982 } 983 984 /** 985 * Returns a set containing the administrators that are defined in the ADS. 986 * 987 * @return a set containing the administrators that are defined in the ADS. 988 * @throws ADSContextException 989 * if something goes wrong. 990 */ 991 public Set<Map<AdministratorProperty, Object>> readAdministratorRegistry() throws ADSContextException 992 { 993 Set<Map<AdministratorProperty, Object>> result = new HashSet<>(); 994 NamingEnumeration<SearchResult> ne = null; 995 try 996 { 997 SearchControls sc = new SearchControls(); 998 999 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 1000 String[] attList = { "cn", "userpassword", "ds-privilege-name", "description" }; 1001 sc.setReturningAttributes(attList); 1002 ne = dirContext.search(getAdministratorContainerDN(), "(objectclass=*)", sc); 1003 while (ne.hasMore()) 1004 { 1005 SearchResult sr = ne.next(); 1006 Map<AdministratorProperty, Object> properties = 1007 makePropertiesFromAdministratorAttrs(getRdn(sr.getName()), sr.getAttributes()); 1008 result.add(properties); 1009 } 1010 } 1011 catch (NameNotFoundException x) 1012 { 1013 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 1014 } 1015 catch (NoPermissionException x) 1016 { 1017 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1018 } 1019 catch (NamingException x) 1020 { 1021 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1022 } 1023 finally 1024 { 1025 handleCloseNamingEnumeration(ne); 1026 } 1027 1028 return result; 1029 } 1030 1031 /** 1032 * Creates the Administration Data in the server. The call to this method 1033 * assumes that OpenDJ.jar has already been loaded. 1034 * 1035 * @param backendName 1036 * the backend name which will handle admin information. 1037 * <CODE>null</CODE> to use the default backend name for the admin 1038 * information. 1039 * @throws ADSContextException 1040 * if something goes wrong. 1041 */ 1042 public void createAdminData(String backendName) throws ADSContextException 1043 { 1044 // Add the administration suffix 1045 createAdministrationSuffix(backendName); 1046 createAdminDataContainers(); 1047 } 1048 1049 /** Create container entries. */ 1050 private void createAdminDataContainers() throws ADSContextException 1051 { 1052 // Create the DIT below the administration suffix 1053 if (!isExistingEntry(nameFromDN(getAdministrationSuffixDN()))) 1054 { 1055 createTopContainerEntry(); 1056 } 1057 if (!isExistingEntry(nameFromDN(getAdministratorContainerDN()))) 1058 { 1059 createAdministratorContainerEntry(); 1060 } 1061 if (!isExistingEntry(nameFromDN(getServerContainerDN()))) 1062 { 1063 createContainerEntry(getServerContainerDN()); 1064 } 1065 if (!isExistingEntry(nameFromDN(getServerGroupContainerDN()))) 1066 { 1067 createContainerEntry(getServerGroupContainerDN()); 1068 } 1069 1070 // Add the default "all-servers" group 1071 if (!isExistingEntry(nameFromDN(getAllServerGroupDN()))) 1072 { 1073 Map<ServerGroupProperty, Object> allServersGroupsMap = new HashMap<>(); 1074 allServersGroupsMap.put(ServerGroupProperty.UID, ALL_SERVERGROUP_NAME); 1075 createServerGroup(allServersGroupsMap); 1076 } 1077 1078 // Create the CryptoManager instance key DIT below the administration suffix 1079 if (!isExistingEntry(nameFromDN(getInstanceKeysContainerDN()))) 1080 { 1081 createContainerEntry(getInstanceKeysContainerDN()); 1082 } 1083 1084 // Create the CryptoManager secret key DIT below the administration suffix 1085 if (!isExistingEntry(nameFromDN(getSecretKeysContainerDN()))) 1086 { 1087 createContainerEntry(getSecretKeysContainerDN()); 1088 } 1089 } 1090 1091 /** 1092 * Removes the administration data. 1093 * 1094 * @param removeAdministrators 1095 * {@code true} if administrators should be removed. It may not be 1096 * possible to remove administrators if the operation is being 1097 * performed by one of the administrators because it will cause the 1098 * administrator to be disconnected. 1099 * @throws ADSContextException 1100 * if something goes wrong. 1101 */ 1102 public void removeAdminData(boolean removeAdministrators) throws ADSContextException 1103 { 1104 String[] dns = { getServerContainerDN(), getServerGroupContainerDN(), 1105 removeAdministrators ? getAdministratorContainerDN() : null }; 1106 try 1107 { 1108 Control[] controls = new Control[] { new SubtreeDeleteControl() }; 1109 LdapContext tmpContext = dirContext.newInstance(controls); 1110 try 1111 { 1112 for (String dn : dns) 1113 { 1114 if (dn != null) 1115 { 1116 LdapName ldapName = nameFromDN(dn); 1117 if (isExistingEntry(ldapName)) 1118 { 1119 tmpContext.destroySubcontext(dn); 1120 } 1121 } 1122 } 1123 } 1124 finally 1125 { 1126 try 1127 { 1128 tmpContext.close(); 1129 } 1130 catch (Exception ex) 1131 { 1132 logger.warn(LocalizableMessage.raw("Error while closing LDAP connection after removing admin data", ex)); 1133 } 1134 } 1135 // Recreate the container entries: 1136 createAdminDataContainers(); 1137 } 1138 catch (NamingException x) 1139 { 1140 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1141 } 1142 } 1143 1144 /** 1145 * Returns <CODE>true</CODE> if the server contains Administration Data and 1146 * <CODE>false</CODE> otherwise. 1147 * 1148 * @return <CODE>true</CODE> if the server contains Administration Data and 1149 * <CODE>false</CODE> otherwise. 1150 * @throws ADSContextException 1151 * if something goes wrong. 1152 */ 1153 public boolean hasAdminData() throws ADSContextException 1154 { 1155 String[] dns = { getAdministratorContainerDN(), getAllServerGroupDN(), getServerContainerDN(), 1156 getInstanceKeysContainerDN(), getSecretKeysContainerDN() }; 1157 boolean hasAdminData = true; 1158 for (int i = 0; i < dns.length && hasAdminData; i++) 1159 { 1160 hasAdminData = isExistingEntry(nameFromDN(dns[i])); 1161 } 1162 return hasAdminData; 1163 } 1164 1165 /** 1166 * Returns the DN of the administrator for a given UID. 1167 * 1168 * @param uid 1169 * the UID to be used to generate the DN. 1170 * @return the DN of the administrator for the given UID: 1171 */ 1172 public static String getAdministratorDN(String uid) 1173 { 1174 return "cn=" + Rdn.escapeValue(uid) + "," + getAdministratorContainerDN(); 1175 } 1176 1177 /** 1178 * Creates an Administrator in the ADS. 1179 * 1180 * @param adminProperties 1181 * the properties of the administrator to be created. 1182 * @throws ADSContextException 1183 * if something goes wrong. 1184 */ 1185 public void createAdministrator(Map<AdministratorProperty, Object> adminProperties) throws ADSContextException 1186 { 1187 LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); 1188 BasicAttributes attrs = makeAttrsFromAdministratorProperties(adminProperties, true, null); 1189 1190 try 1191 { 1192 DirContext ctx = dirContext.createSubcontext(dnCentralAdmin, attrs); 1193 ctx.close(); 1194 } 1195 catch (NameAlreadyBoundException x) 1196 { 1197 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 1198 } 1199 catch (NoPermissionException x) 1200 { 1201 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1202 } 1203 catch (NamingException x) 1204 { 1205 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1206 } 1207 } 1208 1209 /** 1210 * Deletes the administrator in the ADS. 1211 * 1212 * @param adminProperties 1213 * the properties of the administrator to be deleted. 1214 * @throws ADSContextException 1215 * if something goes wrong. 1216 */ 1217 public void deleteAdministrator(Map<AdministratorProperty, Object> adminProperties) throws ADSContextException 1218 { 1219 LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); 1220 1221 try 1222 { 1223 dirContext.destroySubcontext(dnCentralAdmin); 1224 } 1225 catch (NameNotFoundException | NotContextException x) 1226 { 1227 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 1228 } 1229 catch (NoPermissionException x) 1230 { 1231 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1232 } 1233 catch (NamingException x) 1234 { 1235 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1236 } 1237 } 1238 1239 /** 1240 * Updates and administrator registered in the ADS. 1241 * 1242 * @param adminProperties 1243 * the new properties of the administrator. 1244 * @param newAdminUserId 1245 * The new admin user Identifier, or null. 1246 * @throws ADSContextException 1247 * if something goes wrong. 1248 */ 1249 public void updateAdministrator(Map<AdministratorProperty, Object> adminProperties, String newAdminUserId) 1250 throws ADSContextException 1251 { 1252 LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); 1253 1254 boolean updatePassword = adminProperties.containsKey(AdministratorProperty.PASSWORD); 1255 1256 NamingEnumeration<?> currentPrivileges = null; 1257 try 1258 { 1259 // Entry renaming 1260 if (newAdminUserId != null) 1261 { 1262 Map<AdministratorProperty, Object> newAdminUserProps = new HashMap<>(adminProperties); 1263 newAdminUserProps.put(AdministratorProperty.UID, newAdminUserId); 1264 LdapName newDn = makeDNFromAdministratorProperties(newAdminUserProps); 1265 dirContext.rename(dnCentralAdmin, newDn); 1266 dnCentralAdmin = newDn; 1267 adminProperties.put(AdministratorProperty.UID, newAdminUserId); 1268 } 1269 1270 // if modification includes 'privilege', we have to get first the 1271 // current privileges list. 1272 if (adminProperties.containsKey(AdministratorProperty.PRIVILEGE)) 1273 { 1274 SearchControls sc = new SearchControls(); 1275 sc.setSearchScope(SearchControls.OBJECT_SCOPE); 1276 String[] attList = { "ds-privilege-name" }; 1277 sc.setReturningAttributes(attList); 1278 NamingEnumeration<SearchResult> ne = dirContext.search(dnCentralAdmin, "(objectclass=*)", sc); 1279 try 1280 { 1281 while (ne.hasMore()) 1282 { 1283 currentPrivileges = ne.next().getAttributes().get("ds-privilege-name").getAll(); 1284 } 1285 } 1286 finally 1287 { 1288 handleCloseNamingEnumeration(ne); 1289 } 1290 } 1291 1292 // Replace properties, if needed. 1293 if (adminProperties.size() > 1) 1294 { 1295 BasicAttributes attrs = 1296 makeAttrsFromAdministratorProperties(adminProperties, updatePassword, currentPrivileges); 1297 dirContext.modifyAttributes(dnCentralAdmin, DirContext.REPLACE_ATTRIBUTE, attrs); 1298 } 1299 } 1300 catch (NameNotFoundException x) 1301 { 1302 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 1303 } 1304 catch (NoPermissionException x) 1305 { 1306 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1307 } 1308 catch (NamingException x) 1309 { 1310 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1311 } 1312 finally 1313 { 1314 handleCloseNamingEnumeration(currentPrivileges); 1315 } 1316 } 1317 1318 /** 1319 * Returns the DN of the suffix that contains the administration data. 1320 * 1321 * @return the DN of the suffix that contains the administration data. 1322 */ 1323 public static String getAdministrationSuffixDN() 1324 { 1325 return "cn=admin data"; 1326 } 1327 1328 /** 1329 * This method returns the DN of the entry that corresponds to the given host 1330 * name and installation path. 1331 * 1332 * @param hostname 1333 * the host name. 1334 * @param ipath 1335 * the installation path. 1336 * @return the DN of the entry that corresponds to the given host name and 1337 * installation path. 1338 * @throws ADSContextException 1339 * if something goes wrong. 1340 */ 1341 private static LdapName makeDNFromHostnameAndPath(String hostname, String ipath) throws ADSContextException 1342 { 1343 return nameFromDN("cn=" + Rdn.escapeValue(hostname + "@" + ipath) + "," + getServerContainerDN()); 1344 } 1345 1346 /** 1347 * This method returns the DN of the entry that corresponds to the given host 1348 * name port representation. 1349 * 1350 * @param serverUniqueId 1351 * the host name and port. 1352 * @return the DN of the entry that corresponds to the given host name and 1353 * port. 1354 * @throws ADSContextException 1355 * if something goes wrong. 1356 */ 1357 private static LdapName makeDNFromServerUniqueId(String serverUniqueId) throws ADSContextException 1358 { 1359 return nameFromDN("cn=" + Rdn.escapeValue(serverUniqueId) + "," + getServerContainerDN()); 1360 } 1361 1362 /** 1363 * This method returns the DN of the entry that corresponds to the given 1364 * server group properties. 1365 * 1366 * @param serverGroupProperties 1367 * the server group properties 1368 * @return the DN of the entry that corresponds to the given server group 1369 * properties. 1370 * @throws ADSContextException 1371 * if something goes wrong. 1372 */ 1373 private static LdapName makeDNFromServerGroupProperties(Map<ServerGroupProperty, Object> serverGroupProperties) 1374 throws ADSContextException 1375 { 1376 String serverGroupId = (String) serverGroupProperties.get(ServerGroupProperty.UID); 1377 if (serverGroupId == null) 1378 { 1379 throw new ADSContextException(ErrorType.MISSING_NAME); 1380 } 1381 return nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN()); 1382 } 1383 1384 /** 1385 * This method returns the DN of the entry that corresponds to the given 1386 * server properties. 1387 * 1388 * @param serverProperties 1389 * the server properties. 1390 * @return the DN of the entry that corresponds to the given server 1391 * properties. 1392 * @throws ADSContextException 1393 * if something goes wrong. 1394 */ 1395 private static LdapName makeDNFromServerProperties(Map<ServerProperty, Object> serverProperties) 1396 throws ADSContextException 1397 { 1398 String serverID = getServerID(serverProperties); 1399 if (serverID != null) 1400 { 1401 return makeDNFromServerUniqueId(serverID); 1402 } 1403 1404 String hostname = getHostname(serverProperties); 1405 try 1406 { 1407 String ipath = getInstallPath(serverProperties); 1408 return makeDNFromHostnameAndPath(hostname, ipath); 1409 } 1410 catch (ADSContextException ace) 1411 { 1412 ServerDescriptor s = ServerDescriptor.createStandalone(serverProperties); 1413 return makeDNFromServerUniqueId(s.getHostPort(true)); 1414 } 1415 } 1416 1417 /** 1418 * This method returns the DN of the entry that corresponds to the given 1419 * server properties. 1420 * 1421 * @param serverProperties 1422 * the server properties. 1423 * @return the DN of the entry that corresponds to the given server 1424 * properties. 1425 * @throws ADSContextException 1426 * if something goes wrong. 1427 */ 1428 public static String getServerIdFromServerProperties(Map<ServerProperty, Object> serverProperties) 1429 throws ADSContextException 1430 { 1431 LdapName ldapName = makeDNFromServerProperties(serverProperties); 1432 String rdn = ldapName.get(ldapName.size() - 1); 1433 int pos = rdn.indexOf("="); 1434 return rdn.substring(pos + 1); 1435 } 1436 1437 /** 1438 * This method returns the DN of the entry that corresponds to the given 1439 * administrator properties. 1440 * 1441 * @param adminProperties 1442 * the administrator properties. 1443 * @return the DN of the entry that corresponds to the given administrator 1444 * properties. 1445 * @throws ADSContextException 1446 * if something goes wrong. 1447 */ 1448 private static LdapName makeDNFromAdministratorProperties(Map<AdministratorProperty, Object> adminProperties) 1449 throws ADSContextException 1450 { 1451 return makeDNFromAdministratorProperties(getAdministratorUID(adminProperties)); 1452 } 1453 1454 /** 1455 * This method returns the DN of the entry that corresponds to the given 1456 * administrator properties. 1457 * 1458 * @param adminUid 1459 * the administrator uid. 1460 * @return the DN of the entry that corresponds to the given administrator 1461 * properties. 1462 * @throws ADSContextException 1463 * if something goes wrong. 1464 */ 1465 private static LdapName makeDNFromAdministratorProperties(String adminUid) throws ADSContextException 1466 { 1467 return nameFromDN(getAdministratorDN(adminUid)); 1468 } 1469 1470 /** 1471 * Returns the attributes for some administrator properties. 1472 * 1473 * @param adminProperties 1474 * the administrator properties. 1475 * @param passwordRequired 1476 * Indicates if the properties should include the password. 1477 * @param currentPrivileges 1478 * The current privilege list or null. 1479 * @return the attributes for the given administrator properties. 1480 * @throws ADSContextException 1481 * if something goes wrong. 1482 */ 1483 private static BasicAttributes makeAttrsFromAdministratorProperties( 1484 Map<AdministratorProperty, Object> adminProperties, boolean passwordRequired, 1485 NamingEnumeration<?> currentPrivileges) throws ADSContextException 1486 { 1487 BasicAttributes attrs = new BasicAttributes(); 1488 Attribute oc = new BasicAttribute("objectclass"); 1489 if (passwordRequired) 1490 { 1491 attrs.put("userPassword", getAdministratorPassword(adminProperties)); 1492 } 1493 oc.add("top"); 1494 oc.add("person"); 1495 attrs.put(oc); 1496 attrs.put("sn", GLOBAL_ADMIN_UID); 1497 if (adminProperties.containsKey(AdministratorProperty.DESCRIPTION)) 1498 { 1499 attrs.put("description", adminProperties.get(AdministratorProperty.DESCRIPTION)); 1500 } 1501 Attribute privilegeAtt; 1502 if (adminProperties.containsKey(AdministratorProperty.PRIVILEGE)) 1503 { 1504 // We assume that privilege strings provided in 1505 // AdministratorProperty.PRIVILEGE 1506 // are valid privileges represented as a LinkedList of string. 1507 privilegeAtt = new BasicAttribute("ds-privilege-name"); 1508 if (currentPrivileges != null) 1509 { 1510 while (currentPrivileges.hasMoreElements()) 1511 { 1512 privilegeAtt.add(currentPrivileges.nextElement().toString()); 1513 } 1514 } 1515 1516 LinkedList<?> privileges = (LinkedList<?>) adminProperties.get(AdministratorProperty.PRIVILEGE); 1517 for (Object o : privileges) 1518 { 1519 String p = o.toString(); 1520 if (p.startsWith("-")) 1521 { 1522 privilegeAtt.remove(p.substring(1)); 1523 } 1524 else 1525 { 1526 privilegeAtt.add(p); 1527 } 1528 } 1529 } 1530 else 1531 { 1532 privilegeAtt = addRootPrivileges(); 1533 } 1534 attrs.put(privilegeAtt); 1535 1536 // Add the RootDNs Password policy so the password do not expire. 1537 attrs.put("ds-pwp-password-policy-dn", "cn=Root Password Policy,cn=Password Policies,cn=config"); 1538 1539 return attrs; 1540 } 1541 1542 /** 1543 * Builds an attribute which contains 'root' privileges. 1544 * 1545 * @return The attribute which contains 'root' privileges. 1546 */ 1547 private static Attribute addRootPrivileges() 1548 { 1549 Attribute privilege = new BasicAttribute("ds-privilege-name"); 1550 privilege.add("bypass-acl"); 1551 privilege.add("modify-acl"); 1552 privilege.add("config-read"); 1553 privilege.add("config-write"); 1554 privilege.add("ldif-import"); 1555 privilege.add("ldif-export"); 1556 privilege.add("backend-backup"); 1557 privilege.add("backend-restore"); 1558 privilege.add("server-shutdown"); 1559 privilege.add("server-restart"); 1560 privilege.add("disconnect-client"); 1561 privilege.add("cancel-request"); 1562 privilege.add("password-reset"); 1563 privilege.add("update-schema"); 1564 privilege.add("privilege-change"); 1565 privilege.add("unindexed-search"); 1566 privilege.add("subentry-write"); 1567 privilege.add("changelog-read"); 1568 return privilege; 1569 } 1570 1571 /** 1572 * Returns the attributes for some server properties. 1573 * 1574 * @param serverProperties 1575 * the server properties. 1576 * @param addObjectClass 1577 * Indicates if the object class has to be added. 1578 * @return the attributes for the given server properties. 1579 */ 1580 private static BasicAttributes makeAttrsFromServerProperties(Map<ServerProperty, Object> serverProperties, 1581 boolean addObjectClass) 1582 { 1583 BasicAttributes result = new BasicAttributes(); 1584 1585 // Transform 'properties' into 'attributes' 1586 for (ServerProperty prop : serverProperties.keySet()) 1587 { 1588 Attribute attr = makeAttrFromServerProperty(prop, serverProperties.get(prop)); 1589 if (attr != null) 1590 { 1591 result.put(attr); 1592 } 1593 } 1594 if (addObjectClass) 1595 { 1596 // Add the objectclass attribute value 1597 // TODO: use another structural objectclass 1598 Attribute oc = new BasicAttribute("objectclass"); 1599 oc.add("top"); 1600 oc.add("ds-cfg-branch"); 1601 oc.add("extensibleobject"); 1602 result.put(oc); 1603 } 1604 return result; 1605 } 1606 1607 /** 1608 * Returns the attribute for a given server property. 1609 * 1610 * @param property 1611 * the server property. 1612 * @param value 1613 * the value. 1614 * @return the attribute for a given server property. 1615 */ 1616 private static Attribute makeAttrFromServerProperty(ServerProperty property, Object value) 1617 { 1618 Attribute result; 1619 1620 switch (property) 1621 { 1622 case INSTANCE_PUBLIC_KEY_CERTIFICATE: 1623 result = null; // used in separate instance key entry 1624 break; 1625 case GROUPS: 1626 result = new BasicAttribute(ServerProperty.GROUPS.getAttributeName()); 1627 for (Object o : ((Set<?>) value)) 1628 { 1629 result.add(o); 1630 } 1631 break; 1632 default: 1633 result = new BasicAttribute(property.getAttributeName(), value); 1634 } 1635 return result; 1636 } 1637 1638 /** 1639 * Returns the attributes for some server group properties. 1640 * 1641 * @param serverGroupProperties 1642 * the server group properties. 1643 * @return the attributes for the given server group properties. 1644 */ 1645 private static BasicAttributes makeAttrsFromServerGroupProperties( 1646 Map<ServerGroupProperty, Object> serverGroupProperties) 1647 { 1648 BasicAttributes result = new BasicAttributes(); 1649 1650 // Transform 'properties' into 'attributes' 1651 for (ServerGroupProperty prop : serverGroupProperties.keySet()) 1652 { 1653 Attribute attr = makeAttrFromServerGroupProperty(prop, serverGroupProperties.get(prop)); 1654 if (attr != null) 1655 { 1656 result.put(attr); 1657 } 1658 } 1659 return result; 1660 } 1661 1662 /** 1663 * Returns the attributes for some server group properties. 1664 * 1665 * @param serverGroupProperties 1666 * the server group properties. 1667 * @return the attributes for the given server group properties. 1668 */ 1669 private static BasicAttributes makeAttrsFromServerGroupProperties(Set<ServerGroupProperty> serverGroupProperties) 1670 { 1671 BasicAttributes result = new BasicAttributes(); 1672 1673 // Transform 'properties' into 'attributes' 1674 for (ServerGroupProperty prop : serverGroupProperties) 1675 { 1676 Attribute attr = makeAttrFromServerGroupProperty(prop, null); 1677 if (attr != null) 1678 { 1679 result.put(attr); 1680 } 1681 } 1682 return result; 1683 } 1684 1685 /** 1686 * Returns the attribute for a given server group property. 1687 * 1688 * @param property 1689 * the server group property. 1690 * @param value 1691 * the value. 1692 * @return the attribute for a given server group property. 1693 */ 1694 private static Attribute makeAttrFromServerGroupProperty(ServerGroupProperty property, Object value) 1695 { 1696 switch (property) 1697 { 1698 case MEMBERS: 1699 Attribute result = new BasicAttribute(ServerGroupProperty.MEMBERS.getAttributeName()); 1700 for (Object o : ((Set<?>) value)) 1701 { 1702 result.add(o); 1703 } 1704 return result; 1705 default: 1706 return new BasicAttribute(property.getAttributeName(), value); 1707 } 1708 } 1709 1710 /** 1711 * Returns the properties of a server group for some LDAP attributes. 1712 * 1713 * @param attrs 1714 * the LDAP attributes. 1715 * @return the properties of a server group for some LDAP attributes. 1716 * @throws ADSContextException 1717 * if something goes wrong. 1718 */ 1719 private Map<ServerGroupProperty, Object> makePropertiesFromServerGroupAttrs(Attributes attrs) 1720 throws ADSContextException 1721 { 1722 Map<ServerGroupProperty, Object> result = new HashMap<>(); 1723 try 1724 { 1725 for (ServerGroupProperty prop : ServerGroupProperty.values()) 1726 { 1727 Attribute attr = attrs.get(prop.getAttributeName()); 1728 if (attr == null) 1729 { 1730 continue; 1731 } 1732 Object value; 1733 1734 if (attr.size() >= 1 && MULTIVALUED_SERVER_GROUP_PROPERTIES.contains(prop)) 1735 { 1736 Set<String> set = new HashSet<>(); 1737 NamingEnumeration<?> ae = attr.getAll(); 1738 try 1739 { 1740 while (ae.hasMore()) 1741 { 1742 set.add((String) ae.next()); 1743 } 1744 } 1745 finally 1746 { 1747 ae.close(); 1748 } 1749 value = set; 1750 } 1751 else 1752 { 1753 value = attr.get(0); 1754 } 1755 1756 result.put(prop, value); 1757 } 1758 } 1759 catch (NamingException x) 1760 { 1761 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1762 } 1763 return result; 1764 } 1765 1766 /** 1767 * Returns the properties of a server for some LDAP attributes. 1768 * 1769 * @param attrs 1770 * the LDAP attributes. 1771 * @return the properties of a server for some LDAP attributes. 1772 * @throws ADSContextException 1773 * if something goes wrong. 1774 */ 1775 private Map<ServerProperty, Object> makePropertiesFromServerAttrs(Attributes attrs) throws ADSContextException 1776 { 1777 Map<ServerProperty, Object> result = new HashMap<>(); 1778 try 1779 { 1780 NamingEnumeration<? extends Attribute> ne = attrs.getAll(); 1781 while (ne.hasMore()) 1782 { 1783 Attribute attr = ne.next(); 1784 String attrID = attr.getID(); 1785 Object value; 1786 1787 if (attrID.endsWith(";binary")) 1788 { 1789 attrID = attrID.substring(0, attrID.lastIndexOf(";binary")); 1790 } 1791 1792 ServerProperty prop = null; 1793 ServerProperty[] props = ServerProperty.values(); 1794 for (int i = 0; i < props.length && prop == null; i++) 1795 { 1796 String v = props[i].getAttributeName(); 1797 if (attrID.equalsIgnoreCase(v)) 1798 { 1799 prop = props[i]; 1800 } 1801 } 1802 if (prop == null) 1803 { 1804 // Do not handle it 1805 } 1806 else 1807 { 1808 if (attr.size() >= 1 && MULTIVALUED_SERVER_PROPERTIES.contains(prop)) 1809 { 1810 Set<String> set = new HashSet<>(); 1811 NamingEnumeration<?> ae = attr.getAll(); 1812 try 1813 { 1814 while (ae.hasMore()) 1815 { 1816 set.add((String) ae.next()); 1817 } 1818 } 1819 finally 1820 { 1821 ae.close(); 1822 } 1823 value = set; 1824 } 1825 else 1826 { 1827 value = attr.get(0); 1828 } 1829 1830 result.put(prop, value); 1831 } 1832 } 1833 } 1834 catch (NamingException x) 1835 { 1836 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1837 } 1838 return result; 1839 } 1840 1841 /** 1842 * Returns the properties of an administrator for some rdn and LDAP 1843 * attributes. 1844 * 1845 * @param rdn 1846 * the RDN. 1847 * @param attrs 1848 * the LDAP attributes. 1849 * @return the properties of an administrator for the given rdn and LDAP 1850 * attributes. 1851 * @throws ADSContextException 1852 * if something goes wrong. 1853 */ 1854 private Map<AdministratorProperty, Object> makePropertiesFromAdministratorAttrs(String rdn, Attributes attrs) 1855 throws ADSContextException 1856 { 1857 Map<AdministratorProperty, Object> result = new HashMap<>(); 1858 LdapName nameObj; 1859 nameObj = nameFromDN(rdn); 1860 String dn = nameObj + "," + getAdministratorContainerDN(); 1861 result.put(AdministratorProperty.ADMINISTRATOR_DN, dn); 1862 NamingEnumeration<? extends Attribute> ne = null; 1863 try 1864 { 1865 ne = attrs.getAll(); 1866 while (ne.hasMore()) 1867 { 1868 Attribute attr = ne.next(); 1869 String attrID = attr.getID(); 1870 Object value; 1871 1872 if ("cn".equalsIgnoreCase(attrID)) 1873 { 1874 value = attr.get(0); 1875 result.put(AdministratorProperty.UID, value); 1876 } 1877 else if ("userpassword".equalsIgnoreCase(attrID)) 1878 { 1879 value = new String((byte[]) attr.get()); 1880 result.put(AdministratorProperty.PASSWORD, value); 1881 } 1882 else if ("description".equalsIgnoreCase(attrID)) 1883 { 1884 value = attr.get(0); 1885 result.put(AdministratorProperty.DESCRIPTION, value); 1886 } 1887 else if ("ds-privilege-name".equalsIgnoreCase(attrID)) 1888 { 1889 LinkedHashSet<String> privileges = new LinkedHashSet<>(); 1890 NamingEnumeration<?> attValueList = attr.getAll(); 1891 while (attValueList.hasMoreElements()) 1892 { 1893 privileges.add(attValueList.next().toString()); 1894 } 1895 result.put(AdministratorProperty.PRIVILEGE, privileges); 1896 } 1897 } 1898 } 1899 catch (NamingException x) 1900 { 1901 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1902 } 1903 finally 1904 { 1905 handleCloseNamingEnumeration(ne); 1906 } 1907 1908 return result; 1909 } 1910 1911 /** 1912 * Returns the parent entry of the server entries. 1913 * 1914 * @return the parent entry of the server entries. 1915 */ 1916 public static String getServerContainerDN() 1917 { 1918 return "cn=Servers," + getAdministrationSuffixDN(); 1919 } 1920 1921 /** 1922 * Returns the parent entry of the administrator entries. 1923 * 1924 * @return the parent entry of the administrator entries. 1925 */ 1926 public static String getAdministratorContainerDN() 1927 { 1928 return "cn=Administrators," + getAdministrationSuffixDN(); 1929 } 1930 1931 /** 1932 * Returns the parent entry of the server group entries. 1933 * 1934 * @return the parent entry of the server group entries. 1935 */ 1936 public static String getServerGroupContainerDN() 1937 { 1938 return "cn=Server Groups," + getAdministrationSuffixDN(); 1939 } 1940 1941 /** 1942 * Returns the all server group entry DN. 1943 * 1944 * @return the all server group entry DN. 1945 */ 1946 private static String getAllServerGroupDN() 1947 { 1948 return "cn=" + Rdn.escapeValue(ALL_SERVERGROUP_NAME) + "," + getServerGroupContainerDN(); 1949 } 1950 1951 /** 1952 * Returns the host name for the given properties. 1953 * 1954 * @param serverProperties 1955 * the server properties. 1956 * @return the host name for the given properties. 1957 * @throws ADSContextException 1958 * if the host name could not be found or its value is not valid. 1959 */ 1960 private static String getHostname(Map<ServerProperty, Object> serverProperties) throws ADSContextException 1961 { 1962 String result = (String) serverProperties.get(ServerProperty.HOST_NAME); 1963 if (result == null) 1964 { 1965 throw new ADSContextException(ErrorType.MISSING_HOSTNAME); 1966 } 1967 else if (result.length() == 0) 1968 { 1969 throw new ADSContextException(ErrorType.NOVALID_HOSTNAME); 1970 } 1971 return result; 1972 } 1973 1974 /** 1975 * Returns the Server ID for the given properties. 1976 * 1977 * @param serverProperties 1978 * the server properties. 1979 * @return the server ID for the given properties or null. 1980 */ 1981 private static String getServerID(Map<ServerProperty, Object> serverProperties) 1982 { 1983 String result = (String) serverProperties.get(ServerProperty.ID); 1984 if (result != null && result.length() == 0) 1985 { 1986 result = null; 1987 } 1988 return result; 1989 } 1990 1991 /** 1992 * Returns the install path for the given properties. 1993 * 1994 * @param serverProperties 1995 * the server properties. 1996 * @return the install path for the given properties. 1997 * @throws ADSContextException 1998 * if the install path could not be found or its value is not valid. 1999 */ 2000 private static String getInstallPath(Map<ServerProperty, Object> serverProperties) throws ADSContextException 2001 { 2002 String result = (String) serverProperties.get(ServerProperty.INSTANCE_PATH); 2003 if (result == null) 2004 { 2005 throw new ADSContextException(ErrorType.MISSING_IPATH); 2006 } 2007 else if (result.length() == 0) 2008 { 2009 throw new ADSContextException(ErrorType.NOVALID_IPATH); 2010 } 2011 return result; 2012 } 2013 2014 /** 2015 * Returns the Administrator UID for the given properties. 2016 * 2017 * @param adminProperties 2018 * the server properties. 2019 * @return the Administrator UID for the given properties. 2020 * @throws ADSContextException 2021 * if the administrator UID could not be found. 2022 */ 2023 private static String getAdministratorUID(Map<AdministratorProperty, Object> adminProperties) 2024 throws ADSContextException 2025 { 2026 String result = (String) adminProperties.get(AdministratorProperty.UID); 2027 if (result == null) 2028 { 2029 throw new ADSContextException(ErrorType.MISSING_ADMIN_UID); 2030 } 2031 return result; 2032 } 2033 2034 /** 2035 * Returns the Administrator password for the given properties. 2036 * 2037 * @param adminProperties 2038 * the server properties. 2039 * @return the Administrator password for the given properties. 2040 * @throws ADSContextException 2041 * if the administrator password could not be found. 2042 */ 2043 private static String getAdministratorPassword(Map<AdministratorProperty, Object> adminProperties) 2044 throws ADSContextException 2045 { 2046 String result = (String) adminProperties.get(AdministratorProperty.PASSWORD); 2047 if (result == null) 2048 { 2049 throw new ADSContextException(ErrorType.MISSING_ADMIN_PASSWORD); 2050 } 2051 return result; 2052 } 2053 2054 // LDAP utilities 2055 /** 2056 * Returns the LdapName object for the given dn. 2057 * 2058 * @param dn 2059 * the DN. 2060 * @return the LdapName object for the given dn. 2061 * @throws ADSContextException 2062 * if a valid LdapName could not be retrieved for the given dn. 2063 */ 2064 private static LdapName nameFromDN(String dn) throws ADSContextException 2065 { 2066 try 2067 { 2068 return new LdapName(dn); 2069 } 2070 catch (InvalidNameException x) 2071 { 2072 logger.error(LocalizableMessage.raw("Error parsing dn " + dn, x)); 2073 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2074 } 2075 } 2076 2077 /** 2078 * Returns the String rdn for the given search result name. 2079 * 2080 * @param rdnName 2081 * the search result name. 2082 * @return the String rdn for the given search result name. 2083 * @throws ADSContextException 2084 * if a valid String rdn could not be retrieved for the given result 2085 * name. 2086 */ 2087 private static String getRdn(String rdnName) throws ADSContextException 2088 { 2089 // Transform the JNDI name into a RDN string 2090 try 2091 { 2092 return new CompositeName(rdnName).get(0); 2093 } 2094 catch (InvalidNameException x) 2095 { 2096 logger.error(LocalizableMessage.raw("Error parsing rdn " + rdnName, x)); 2097 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2098 } 2099 } 2100 2101 /** 2102 * Tells whether an entry with the provided DN exists. 2103 * 2104 * @param dn 2105 * the DN to check. 2106 * @return <CODE>true</CODE> if the entry exists and <CODE>false</CODE> if it 2107 * does not. 2108 * @throws ADSContextException 2109 * if an error occurred while checking if the entry exists or not. 2110 */ 2111 private boolean isExistingEntry(LdapName dn) throws ADSContextException 2112 { 2113 try 2114 { 2115 SearchControls sc = new SearchControls(); 2116 2117 sc.setSearchScope(SearchControls.OBJECT_SCOPE); 2118 sc.setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); 2119 NamingEnumeration<SearchResult> sr = getDirContext().search(dn, "(objectclass=*)", sc); 2120 boolean result = false; 2121 try 2122 { 2123 while (sr.hasMore()) 2124 { 2125 sr.next(); 2126 result = true; 2127 } 2128 } 2129 finally 2130 { 2131 sr.close(); 2132 } 2133 return result; 2134 } 2135 catch (NameNotFoundException x) 2136 { 2137 return false; 2138 } 2139 catch (NoPermissionException x) 2140 { 2141 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 2142 } 2143 catch (javax.naming.NamingException x) 2144 { 2145 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2146 } 2147 } 2148 2149 /** 2150 * Creates a container entry with the given dn. 2151 * 2152 * @param dn 2153 * the entry of the new entry to be created. 2154 * @throws ADSContextException 2155 * if the entry could not be created. 2156 */ 2157 private void createContainerEntry(String dn) throws ADSContextException 2158 { 2159 BasicAttributes attrs = new BasicAttributes(); 2160 Attribute oc = new BasicAttribute("objectclass"); 2161 oc.add("top"); 2162 oc.add("ds-cfg-branch"); 2163 attrs.put(oc); 2164 createEntry(dn, attrs); 2165 } 2166 2167 /** 2168 * Creates the administrator container entry. 2169 * 2170 * @throws ADSContextException 2171 * if the entry could not be created. 2172 */ 2173 private void createAdministratorContainerEntry() throws ADSContextException 2174 { 2175 BasicAttributes attrs = new BasicAttributes(); 2176 Attribute oc = new BasicAttribute("objectclass"); 2177 oc.add("groupofurls"); 2178 attrs.put(oc); 2179 attrs.put("memberURL", "ldap:///" + getAdministratorContainerDN() + "??one?(objectclass=*)"); 2180 attrs.put("description", "Group of identities which have full access."); 2181 createEntry(getAdministratorContainerDN(), attrs); 2182 } 2183 2184 /** 2185 * Creates the top container entry. 2186 * 2187 * @throws ADSContextException 2188 * if the entry could not be created. 2189 */ 2190 private void createTopContainerEntry() throws ADSContextException 2191 { 2192 BasicAttributes attrs = new BasicAttributes(); 2193 Attribute oc = new BasicAttribute("objectclass"); 2194 oc.add("top"); 2195 oc.add("ds-cfg-branch"); 2196 attrs.put(oc); 2197 createEntry(getAdministrationSuffixDN(), attrs); 2198 } 2199 2200 /** 2201 * Creates an entry with the provided dn and attributes. 2202 * 2203 * @param dn 2204 * the dn of the entry. 2205 * @param attrs 2206 * the attributes of the entry. 2207 * @throws ADSContextException 2208 * if the entry could not be created. 2209 */ 2210 private void createEntry(String dn, Attributes attrs) throws ADSContextException 2211 { 2212 try 2213 { 2214 DirContext ctx = getDirContext().createSubcontext(nameFromDN(dn), attrs); 2215 ctx.close(); 2216 } 2217 catch (NamingException x) 2218 { 2219 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2220 } 2221 } 2222 2223 /** 2224 * Creates the Administration Suffix. 2225 * 2226 * @param backendName 2227 * the backend name to be used for the Administration Suffix. If this 2228 * value is null the default backendName for the Administration 2229 * Suffix will be used. 2230 * @throws ADSContextException 2231 * if something goes wrong. 2232 */ 2233 public void createAdministrationSuffix(String backendName) throws ADSContextException 2234 { 2235 ADSContextHelper helper = new ADSContextHelper(); 2236 String ben = backendName; 2237 if (backendName == null) 2238 { 2239 ben = getDefaultBackendName(); 2240 } 2241 helper.createAdministrationSuffix(getDirContext(), ben); 2242 } 2243 2244 /** 2245 * Returns the default backend name of the administration data. 2246 * 2247 * @return the default backend name of the administration data. 2248 */ 2249 public static String getDefaultBackendName() 2250 { 2251 return "adminRoot"; 2252 } 2253 2254 /** 2255 * Returns the LDIF file of the administration data. 2256 * 2257 * @return the LDIF file of the administration data. 2258 */ 2259 public static String getAdminLDIFFile() 2260 { 2261 return "config" + File.separator + "admin-backend.ldif"; 2262 } 2263 2264 /** CryptoManager related types, fields, and methods. */ 2265 2266 /** 2267 * Returns the parent entry of the server key entries in ADS. 2268 * 2269 * @return the parent entry of the server key entries in ADS. 2270 */ 2271 public static String getInstanceKeysContainerDN() 2272 { 2273 return "cn=instance keys," + getAdministrationSuffixDN(); 2274 } 2275 2276 /** 2277 * Returns the parent entry of the secret key entries in ADS. 2278 * 2279 * @return the parent entry of the secret key entries in ADS. 2280 */ 2281 public static String getSecretKeysContainerDN() 2282 { 2283 return "cn=secret keys," + getAdministrationSuffixDN(); 2284 } 2285 2286 /** 2287 * Tells whether the provided server is registered in the registry. 2288 * 2289 * @param server 2290 * the server. 2291 * @param registry 2292 * the registry. 2293 * @return <CODE>true</CODE> if the server is registered in the registry and 2294 * <CODE>false</CODE> otherwise. 2295 */ 2296 public static boolean isRegistered(ServerDescriptor server, Set<Map<ADSContext.ServerProperty, Object>> registry) 2297 { 2298 for (Map<ADSContext.ServerProperty, Object> s : registry) 2299 { 2300 ServerDescriptor servInRegistry = ServerDescriptor.createStandalone(s); 2301 if (servInRegistry.getId().equals(server.getId())) 2302 { 2303 return true; 2304 } 2305 } 2306 return false; 2307 } 2308 2309 /** 2310 * Register instance key-pair public-key certificate provided in 2311 * serverProperties: generate a key-id attribute if one is not provided (as 2312 * expected); add an instance key public-key certificate entry for the key 2313 * certificate; and associate the certificate entry with the server entry via 2314 * the key ID attribute. 2315 * 2316 * @param serverProperties 2317 * Properties of the server being registered to which the instance 2318 * key entry belongs. 2319 * @param serverEntryDn 2320 * The server's ADS entry DN. 2321 * @throws NamingException 2322 * In case some JNDI operation fails. 2323 * @throws CryptoManager.CryptoManagerException 2324 * In case there is a problem getting the instance public key 2325 * certificate ID. 2326 */ 2327 private void registerInstanceKeyCertificate(Map<ServerProperty, Object> serverProperties, LdapName serverEntryDn) 2328 throws ADSContextException 2329 { 2330 ADSContextHelper helper = new ADSContextHelper(); 2331 helper.registerInstanceKeyCertificate(dirContext, serverProperties, serverEntryDn); 2332 } 2333 2334 /** 2335 * Return the set of valid (i.e., not tagged as compromised) instance key-pair 2336 * public-key certificate entries in ADS. NOTE: calling this method assumes 2337 * that all the jar files are present in the classpath. 2338 * 2339 * @return The set of valid (i.e., not tagged as compromised) instance 2340 * key-pair public-key certificate entries in ADS represented as a Map 2341 * from ds-cfg-key-id value to ds-cfg-public-key-certificate;binary 2342 * value. Note that the collection might be empty. 2343 * @throws ADSContextException 2344 * in case of problems with the entry search. 2345 * @see org.opends.server.crypto.CryptoManagerImpl#getTrustedCertificates 2346 */ 2347 public Map<String, byte[]> getTrustedCertificates() throws ADSContextException 2348 { 2349 final Map<String, byte[]> certificateMap = new HashMap<>(); 2350 final String baseDNStr = getInstanceKeysContainerDN(); 2351 try 2352 { 2353 ADSContextHelper helper = new ADSContextHelper(); 2354 final LdapName baseDN = new LdapName(baseDNStr); 2355 final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + helper.getOcCryptoInstanceKey() + ")"; 2356 final String FILTER_NOT_COMPROMISED = "(!(" + helper.getAttrCryptoKeyCompromisedTime() + "=*))"; 2357 final String searchFilter = "(&" + FILTER_OC_INSTANCE_KEY + FILTER_NOT_COMPROMISED + ")"; 2358 final SearchControls searchControls = new SearchControls(); 2359 searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); 2360 final String attrIDs[] = 2361 { ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(), 2362 ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName() + ";binary" }; 2363 searchControls.setReturningAttributes(attrIDs); 2364 NamingEnumeration<SearchResult> keyEntries = dirContext.search(baseDN, searchFilter, searchControls); 2365 try 2366 { 2367 while (keyEntries.hasMore()) 2368 { 2369 final SearchResult entry = keyEntries.next(); 2370 final Attributes attrs = entry.getAttributes(); 2371 final Attribute keyIDAttr = attrs.get(attrIDs[0]); 2372 final Attribute keyCertAttr = attrs.get(attrIDs[1]); 2373 if (null == keyIDAttr || null == keyCertAttr) 2374 { 2375 continue;// schema viol. 2376 } 2377 certificateMap.put((String) keyIDAttr.get(), (byte[]) keyCertAttr.get()); 2378 } 2379 } 2380 finally 2381 { 2382 try 2383 { 2384 keyEntries.close(); 2385 } 2386 catch (Exception ex) 2387 { 2388 logger.warn(LocalizableMessage.raw("Unexpected error closing enumeration on ADS key pairs", ex)); 2389 } 2390 } 2391 } 2392 catch (NamingException x) 2393 { 2394 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2395 } 2396 return certificateMap; 2397 } 2398 2399 /** 2400 * Merge the contents of this ADSContext with the contents of the provided 2401 * ADSContext. Note that only the contents of this ADSContext will be updated. 2402 * 2403 * @param adsCtx 2404 * the other ADSContext to merge the contents with. 2405 * @throws ADSContextException 2406 * if there was an error during the merge. 2407 */ 2408 public void mergeWithRegistry(ADSContext adsCtx) throws ADSContextException 2409 { 2410 try 2411 { 2412 mergeAdministrators(adsCtx); 2413 mergeServerGroups(adsCtx); 2414 mergeServers(adsCtx); 2415 } 2416 catch (ADSContextException adce) 2417 { 2418 LocalizableMessage msg = ERR_ADS_MERGE.get(ConnectionUtils.getHostPort(getDirContext()), 2419 ConnectionUtils.getHostPort(adsCtx.getDirContext()), adce.getMessageObject()); 2420 throw new ADSContextException(ErrorType.ERROR_MERGING, msg, adce); 2421 } 2422 } 2423 2424 /** 2425 * Merge the administrator contents of this ADSContext with the contents of 2426 * the provided ADSContext. Note that only the contents of this ADSContext 2427 * will be updated. 2428 * 2429 * @param adsCtx 2430 * the other ADSContext to merge the contents with. 2431 * @throws ADSContextException 2432 * if there was an error during the merge. 2433 */ 2434 private void mergeAdministrators(ADSContext adsCtx) throws ADSContextException 2435 { 2436 Set<Map<AdministratorProperty, Object>> admins2 = adsCtx.readAdministratorRegistry(); 2437 SortedSet<String> notDefinedAdmins = new TreeSet<>(); 2438 for (Map<AdministratorProperty, Object> admin2 : admins2) 2439 { 2440 String uid = (String) admin2.get(AdministratorProperty.UID); 2441 if (!isAdministratorAlreadyRegistered(uid)) 2442 { 2443 notDefinedAdmins.add(uid); 2444 } 2445 } 2446 if (!notDefinedAdmins.isEmpty()) 2447 { 2448 LocalizableMessage msg = ERR_ADS_ADMINISTRATOR_MERGE.get( 2449 ConnectionUtils.getHostPort(adsCtx.getDirContext()), ConnectionUtils.getHostPort(getDirContext()), 2450 joinAsString(Constants.LINE_SEPARATOR, notDefinedAdmins), ConnectionUtils.getHostPort(getDirContext())); 2451 throw new ADSContextException(ErrorType.ERROR_MERGING, msg, null); 2452 } 2453 } 2454 2455 /** 2456 * Merge the groups contents of this ADSContext with the contents of the 2457 * provided ADSContext. Note that only the contents of this ADSContext will be 2458 * updated. 2459 * 2460 * @param adsCtx 2461 * the other ADSContext to merge the contents with. 2462 * @throws ADSContextException 2463 * if there was an error during the merge. 2464 */ 2465 private void mergeServerGroups(ADSContext adsCtx) throws ADSContextException 2466 { 2467 Set<Map<ServerGroupProperty, Object>> serverGroups1 = readServerGroupRegistry(); 2468 Set<Map<ServerGroupProperty, Object>> serverGroups2 = adsCtx.readServerGroupRegistry(); 2469 2470 for (Map<ServerGroupProperty, Object> group2 : serverGroups2) 2471 { 2472 Map<ServerGroupProperty, Object> group1 = null; 2473 String uid2 = (String) group2.get(ServerGroupProperty.UID); 2474 for (Map<ServerGroupProperty, Object> gr : serverGroups1) 2475 { 2476 String uid1 = (String) gr.get(ServerGroupProperty.UID); 2477 if (uid1.equalsIgnoreCase(uid2)) 2478 { 2479 group1 = gr; 2480 break; 2481 } 2482 } 2483 2484 if (group1 != null) 2485 { 2486 // Merge the members, keep the description on this ADS. 2487 Set<String> member1List = getServerGroupMemberList(uid2); 2488 if (member1List == null) 2489 { 2490 member1List = new HashSet<>(); 2491 } 2492 Set<String> member2List = adsCtx.getServerGroupMemberList(uid2); 2493 if (member2List != null && !member2List.isEmpty()) 2494 { 2495 member1List.addAll(member2List); 2496 Map<ServerGroupProperty, Object> newProperties = new HashMap<>(); 2497 newProperties.put(ServerGroupProperty.MEMBERS, member1List); 2498 updateServerGroup(uid2, newProperties); 2499 } 2500 } 2501 else 2502 { 2503 createServerGroup(group2); 2504 } 2505 } 2506 } 2507 2508 /** 2509 * Merge the server contents of this ADSContext with the contents of the 2510 * provided ADSContext. Note that only the contents of this ADSContext will be 2511 * updated. 2512 * 2513 * @param adsCtx 2514 * the other ADSContext to merge the contents with. 2515 * @throws ADSContextException 2516 * if there was an error during the merge. 2517 */ 2518 private void mergeServers(ADSContext adsCtx) throws ADSContextException 2519 { 2520 for (Map<ServerProperty, Object> server2 : adsCtx.readServerRegistry()) 2521 { 2522 if (!isServerAlreadyRegistered(server2)) 2523 { 2524 registerServer(server2); 2525 } 2526 } 2527 } 2528 2529 private void handleCloseNamingEnumeration(NamingEnumeration<?> ne) throws ADSContextException 2530 { 2531 if (ne != null) 2532 { 2533 try 2534 { 2535 ne.close(); 2536 } 2537 catch (NamingException ex) 2538 { 2539 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, ex); 2540 } 2541 } 2542 } 2543}