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