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