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