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 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2012-2015 ForgeRock AS 026 */ 027package org.opends.server.admin; 028 029import java.net.InetAddress; 030import java.util.LinkedList; 031import java.util.List; 032 033import org.forgerock.i18n.slf4j.LocalizedLogger; 034import org.forgerock.opendj.ldap.ModificationType; 035import org.forgerock.opendj.ldap.ResultCode; 036import org.forgerock.opendj.ldap.SearchScope; 037import org.opends.server.core.DirectoryServer; 038import org.opends.server.protocols.internal.InternalClientConnection; 039import org.opends.server.protocols.internal.InternalSearchOperation; 040import org.opends.server.protocols.internal.Requests; 041import org.opends.server.protocols.internal.SearchRequest; 042import org.opends.server.types.Attribute; 043import org.opends.server.types.AttributeType; 044import org.opends.server.types.Attributes; 045import org.opends.server.types.DN; 046import org.opends.server.types.DirectoryException; 047import org.opends.server.types.Entry; 048import org.opends.server.types.Modification; 049import org.opends.server.types.SearchResultEntry; 050 051import static org.opends.server.protocols.internal.Requests.*; 052 053/** 054 * Check if information found in "cn=admin data" is coherent with 055 * cn=config. If and inconsistency is detected, we log a warning 056 * message and update "cn=admin data" 057 */ 058public final class AdministrationDataSync 059{ 060 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 061 062 /** The root connection. */ 063 private InternalClientConnection internalConnection; 064 065 /** The attribute name used to store the port. TODO Use the default one. */ 066 private static final String LDAP_PORT = "ds-cfg-listen-port"; 067 068 /** 069 * Create an object that will synchronize configuration and the admin data. 070 * 071 * @param internalConnection 072 * The root connection. 073 */ 074 public AdministrationDataSync(InternalClientConnection internalConnection) 075 { 076 this.internalConnection = internalConnection; 077 } 078 079 /** 080 * Check if information found in "cn=admin data" is coherent with 081 * cn=config. If and inconsistency is detected, we log a warning 082 * message and update "cn=admin data" 083 */ 084 public void synchronize() 085 { 086 // Check if the admin connector is in sync 087 checkAdminConnector(); 088 } 089 090 /** 091 * Check if the admin connector is in sync. The desynchronization 092 * could occurs after the upgrade from 1.0. 093 */ 094 private void checkAdminConnector() 095 { 096 // Look for the server registration in "cn=admin data" 097 DN serverEntryDN = searchServerEntry(); 098 if (serverEntryDN == null) 099 { 100 // Nothing to do 101 return; 102 } 103 104 // Get the admin port 105 String adminPort = getAttr("cn=Administration Connector,cn=config", LDAP_PORT); 106 if (adminPort == null) 107 { 108 // best effort. 109 return; 110 } 111 112 AttributeType attrType1 = DirectoryServer.getAttributeTypeOrDefault("adminport".toLowerCase()); 113 AttributeType attrType2 = DirectoryServer.getAttributeTypeOrDefault("adminEnabled".toLowerCase()); 114 115 LinkedList<Modification> mods = new LinkedList<>(); 116 mods.add(new Modification(ModificationType.REPLACE, Attributes.create(attrType1, adminPort))); 117 mods.add(new Modification(ModificationType.REPLACE, Attributes.create(attrType2, "true"))); 118 119 // Process modification 120 internalConnection.processModify(serverEntryDN, mods); 121 } 122 123 /** 124 * Look for the DN of the local register server. Assumption: default 125 * Connection Handler naming is used. 126 * 127 * @return The DN of the local register server or null. 128 */ 129 private DN searchServerEntry() 130 { 131 DN returnDN = null; 132 133 // Get the LDAP and LDAPS port 134 String ldapPort = getAttr("cn=LDAP Connection Handler,cn=Connection Handlers,cn=config", LDAP_PORT); 135 String ldapsPort = getAttr("cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config", LDAP_PORT); 136 boolean ldapsPortEnable = false; 137 String val = getAttr("cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config", "ds-cfg-enabled"); 138 if (val != null) 139 { 140 ldapsPortEnable = "true".equals(val.toLowerCase()); 141 } 142 if (ldapPort == null && ldapsPort == null) 143 { 144 // best effort (see assumption) 145 return null; 146 } 147 148 // Get the IP address of the local host. 149 String hostName; 150 try 151 { 152 hostName = InetAddress.getLocalHost().getCanonicalHostName(); 153 } 154 catch (Throwable t) 155 { 156 // best effort. 157 return null; 158 } 159 160 // Look for a local server with the Ldap Port. 161 try 162 { 163 SearchRequest request = newSearchRequest(DN.valueOf("cn=Servers,cn=admin data"), SearchScope.SINGLE_LEVEL); 164 InternalSearchOperation op = internalConnection.processSearch(request); 165 if (op.getResultCode() == ResultCode.SUCCESS) 166 { 167 Entry entry = findSameHostAndPort(op.getSearchEntries(), hostName, ldapPort, ldapsPortEnable, ldapsPort); 168 if (entry != null) 169 { 170 returnDN = entry.getName(); 171 } 172 } 173 } 174 catch (DirectoryException e) 175 { 176 // never happens because the filter is always valid. 177 return null; 178 } 179 return returnDN; 180 } 181 182 private Entry findSameHostAndPort(LinkedList<SearchResultEntry> searchResultEntries, 183 String hostName, String ldapPort, boolean ldapsPortEnable, String ldapsPort) 184 { 185 for (Entry currentEntry : searchResultEntries) 186 { 187 String currentHostname = currentEntry.parseAttribute("hostname").asString(); 188 try 189 { 190 String currentIPAddress = InetAddress.getByName(currentHostname).getCanonicalHostName(); 191 if (currentIPAddress.equals(hostName)) 192 { 193 // Check if one of the port match 194 String currentport = currentEntry.parseAttribute("ldapport").asString(); 195 if (currentport.equals(ldapPort)) 196 { 197 return currentEntry; 198 } 199 if (ldapsPortEnable) 200 { 201 currentport = currentEntry.parseAttribute("ldapsport").asString(); 202 if (currentport.equals(ldapsPort)) 203 { 204 return currentEntry; 205 } 206 } 207 } 208 } 209 catch (Exception e) 210 { 211 // best effort. 212 continue; 213 } 214 } 215 return null; 216 } 217 218 /** 219 * Gets an attribute value from an entry. 220 * 221 * @param DN 222 * The DN of the entry. 223 * @param attrName 224 * The attribute name. 225 * @return The attribute value or {@code null} if the value could 226 * not be retrieved. 227 */ 228 private String getAttr(String baseDN, String attrName) 229 { 230 InternalSearchOperation search; 231 try 232 { 233 SearchRequest request = Requests.newSearchRequest(DN.valueOf(baseDN), SearchScope.BASE_OBJECT) 234 .addAttribute(attrName); 235 search = internalConnection.processSearch(request); 236 if (search.getResultCode() != ResultCode.SUCCESS) 237 { 238 // can not happen 239 // best effort. 240 // TODO Log an Error. 241 return null; 242 } 243 } 244 catch (DirectoryException e) 245 { 246 // can not happen 247 // best effort. 248 logger.traceException(e); 249 return null; 250 } 251 252 // Read the port from the PORT attribute 253 SearchResultEntry adminConnectorEntry = null; 254 LinkedList<SearchResultEntry> result = search.getSearchEntries(); 255 if (!result.isEmpty()) 256 { 257 adminConnectorEntry = result.getFirst(); 258 } 259 260 AttributeType attrType = DirectoryServer.getAttributeTypeOrDefault(attrName); 261 List<Attribute> attrs = adminConnectorEntry.getAttribute(attrType); 262 if (attrs != null) 263 { 264 // Get the attribute value 265 return attrs.get(0).iterator().next().toString(); 266 } 267 268 // can not happen 269 // best effort. 270 // TODO Log an Error. 271 return null; 272 } 273}