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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.core; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.concurrent.ConcurrentHashMap; 033 import java.util.concurrent.CopyOnWriteArraySet; 034 035 import org.opends.server.api.ChangeNotificationListener; 036 import org.opends.server.api.ClientConnection; 037 import org.opends.server.types.DisconnectReason; 038 import org.opends.server.types.DN; 039 import org.opends.server.types.Entry; 040 import org.opends.server.types.operation.PostResponseAddOperation; 041 import org.opends.server.types.operation.PostResponseDeleteOperation; 042 import org.opends.server.types.operation.PostResponseModifyOperation; 043 import org.opends.server.types.operation.PostResponseModifyDNOperation; 044 045 import static org.opends.messages.CoreMessages.*; 046 /** 047 * This class provides a data structure which maps an authenticated user DN to 048 * the set of client connections authenticated as that user. Note that a single 049 * client connection may be registered with two different user DNs if the client 050 * has different authentication and authorization identities. 051 * <BR><BR> 052 * This class also provides a mechanism for detecting changes to authenticated 053 * user entries and notifying the corresponding client connections so that they 054 * can update their cached versions. 055 */ 056 public class AuthenticatedUsers 057 implements ChangeNotificationListener 058 { 059 // The mapping between authenticated user DNs and the associated client 060 // connection objects. 061 private ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>> 062 userMap; 063 064 065 066 /** 067 * Creates a new instance of this authenticated users object. 068 */ 069 public AuthenticatedUsers() 070 { 071 userMap = new ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>>(); 072 073 DirectoryServer.registerChangeNotificationListener(this); 074 } 075 076 077 078 /** 079 * Registers the provided user DN and client connection with this object. 080 * 081 * @param userDN The DN of the user associated with the provided 082 * client connection. 083 * @param clientConnection The client connection over which the user is 084 * authenticated. 085 */ 086 public synchronized void put(DN userDN, ClientConnection clientConnection) 087 { 088 CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN); 089 if (connectionSet == null) 090 { 091 connectionSet = new CopyOnWriteArraySet<ClientConnection>(); 092 connectionSet.add(clientConnection); 093 userMap.put(userDN, connectionSet); 094 } 095 else 096 { 097 connectionSet.add(clientConnection); 098 } 099 } 100 101 102 103 /** 104 * Deregisters the provided user DN and client connection with this object. 105 * 106 * @param userDN The DN of the user associated with the provided 107 * client connection. 108 * @param clientConnection The client connection over which the user is 109 * authenticated. 110 */ 111 public synchronized void remove(DN userDN, ClientConnection clientConnection) 112 { 113 CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN); 114 if (connectionSet != null) 115 { 116 connectionSet.remove(clientConnection); 117 if (connectionSet.isEmpty()) 118 { 119 userMap.remove(userDN); 120 } 121 } 122 } 123 124 125 126 /** 127 * Retrieves the set of client connections authenticated as the specified 128 * user. This method is only intended for internal testing use and should not 129 * be called for any other purpose. 130 * 131 * @param userDN The DN of the user for which to retrieve the corresponding 132 * set of client connections. 133 * 134 * @return The set of client connections authenticated as the specified user, 135 * or {@code null} if there are none. 136 */ 137 synchronized CopyOnWriteArraySet<ClientConnection> get(DN userDN) 138 { 139 return userMap.get(userDN); 140 } 141 142 143 144 /** 145 * Performs any processing that may be required after an add 146 * operation. 147 * 148 * @param addOperation The add operation that was performed in the 149 * server. 150 * @param entry The entry that was added to the server. 151 */ 152 public void handleAddOperation( 153 PostResponseAddOperation addOperation, 154 Entry entry) 155 { 156 // No implementation is required for add operations, since a connection 157 // can't be authenticated as a user that doesn't exist yet. 158 } 159 160 161 162 /** 163 * Performs any processing that may be required after a delete 164 * operation. 165 * 166 * @param deleteOperation The delete operation that was performed 167 * in the server. 168 * @param entry The entry that was removed from the 169 * server. 170 */ 171 public void handleDeleteOperation( 172 PostResponseDeleteOperation deleteOperation, 173 Entry entry) 174 { 175 // Identify any client connections that may be authenticated or 176 // authorized as the user whose entry has been deleted and terminate them. 177 CopyOnWriteArraySet<ClientConnection> connectionSet = 178 userMap.remove(entry.getDN()); 179 if (connectionSet != null) 180 { 181 for (ClientConnection conn : connectionSet) 182 { 183 Message message = WARN_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE.get( 184 String.valueOf(entry.getDN())); 185 186 conn.disconnect(DisconnectReason.OTHER, true, message); 187 } 188 } 189 } 190 191 192 193 /** 194 * Performs any processing that may be required after a modify 195 * operation. 196 * 197 * @param modifyOperation The modify operation that was performed 198 * in the server. 199 * @param oldEntry The entry before it was updated. 200 * @param newEntry The entry after it was updated. 201 */ 202 public void handleModifyOperation( 203 PostResponseModifyOperation modifyOperation, 204 Entry oldEntry, Entry newEntry) 205 { 206 // Identify any client connections that may be authenticated or authorized 207 // as the user whose entry has been modified and update them with the latest 208 // version of the entry. 209 CopyOnWriteArraySet<ClientConnection> connectionSet = 210 userMap.get(oldEntry.getDN()); 211 if (connectionSet != null) 212 { 213 for (ClientConnection conn : connectionSet) 214 { 215 conn.updateAuthenticationInfo(oldEntry, newEntry); 216 } 217 } 218 } 219 220 221 222 /** 223 * Performs any processing that may be required after a modify DN 224 * operation. 225 * 226 * @param modifyDNOperation The modify DN operation that was 227 * performed in the server. 228 * @param oldEntry The entry before it was updated. 229 * @param newEntry The entry after it was updated. 230 */ 231 public void handleModifyDNOperation( 232 PostResponseModifyDNOperation modifyDNOperation, 233 Entry oldEntry, Entry newEntry) 234 { 235 // Identify any client connections that may be authenticated or authorized 236 // as the user whose entry has been modified and update them with the latest 237 // version of the entry. 238 CopyOnWriteArraySet<ClientConnection> connectionSet = 239 userMap.remove(oldEntry.getDN()); 240 if (connectionSet != null) 241 { 242 synchronized (this) 243 { 244 CopyOnWriteArraySet<ClientConnection> existingNewSet = 245 userMap.get(newEntry.getDN()); 246 if (existingNewSet == null) 247 { 248 userMap.put(newEntry.getDN(), connectionSet); 249 } 250 else 251 { 252 existingNewSet.addAll(connectionSet); 253 } 254 } 255 256 for (ClientConnection conn : connectionSet) 257 { 258 conn.updateAuthenticationInfo(oldEntry, newEntry); 259 } 260 } 261 } 262 } 263