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 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.api;
028
029
030
031 import java.net.InetAddress;
032 import java.nio.ByteBuffer;
033 import java.nio.channels.Selector;
034 import java.util.Collection;
035 import java.util.HashSet;
036 import java.util.List;
037 import java.util.Set;
038 import java.util.concurrent.CopyOnWriteArrayList;
039
040 import org.opends.messages.Message;
041 import org.opends.server.api.plugin.PluginResult;
042 import org.opends.server.core.DirectoryServer;
043 import org.opends.server.core.PersistentSearch;
044 import org.opends.server.core.PluginConfigManager;
045 import org.opends.server.core.SearchOperation;
046 import org.opends.server.core.NetworkGroup;
047 import org.opends.server.loggers.debug.DebugTracer;
048 import org.opends.server.types.AbstractOperation;
049 import org.opends.server.types.Attribute;
050 import org.opends.server.types.AttributeType;
051 import org.opends.server.types.AttributeValue;
052 import org.opends.server.types.AuthenticationInfo;
053 import org.opends.server.types.CancelRequest;
054 import org.opends.server.types.CancelResult;
055 import org.opends.server.types.DebugLogLevel;
056 import org.opends.server.types.DirectoryException;
057 import org.opends.server.types.DisconnectReason;
058 import org.opends.server.types.DN;
059 import org.opends.server.types.Entry;
060 import org.opends.server.types.IntermediateResponse;
061 import org.opends.server.types.Operation;
062 import org.opends.server.types.Privilege;
063 import org.opends.server.types.SearchResultEntry;
064 import org.opends.server.types.SearchResultReference;
065 import org.opends.server.util.TimeThread;
066
067 import static org.opends.messages.CoreMessages.*;
068 import static org.opends.server.config.ConfigConstants.*;
069 import static org.opends.server.loggers.debug.DebugLogger.*;
070 import static org.opends.server.util.StaticUtils.*;
071
072
073
074 /**
075 * This class defines the set of methods and structures that must be
076 * implemented by a Directory Server client connection.
077 */
078 @org.opends.server.types.PublicAPI(
079 stability=org.opends.server.types.StabilityLevel.VOLATILE,
080 mayInstantiate=true,
081 mayExtend=true,
082 mayInvoke=true)
083 public abstract class ClientConnection
084 {
085 /**
086 * The tracer object for the debug logger.
087 */
088 private static final DebugTracer TRACER = getTracer();
089
090 // The set of authentication information for this client connection.
091 private AuthenticationInfo authenticationInfo;
092
093 // Indicates whether a bind is currently in progress on this client
094 // connection. If so, then no other operations should be allowed
095 // until the bind completes.
096 private boolean bindInProgress;
097
098 // Indicates whether any necessary finalization work has been done
099 // for this client connection.
100 private boolean finalized;
101
102 // The set of privileges assigned to this client connection.
103 private HashSet<Privilege> privileges;
104
105 // The size limit for use with this client connection.
106 private int sizeLimit;
107
108 // The time limit for use with this client connection.
109 private int timeLimit;
110
111 // The lookthrough limit for use with this client connection.
112 private int lookthroughLimit;
113
114 // The time that this client connection was established.
115 private long connectTime;
116
117 // The idle time limit for this client connection.
118 private long idleTimeLimit;
119
120 // The opaque information used for storing intermediate state
121 // information needed across multi-stage SASL binds.
122 private Object saslAuthState;
123
124 // A string representation of the time that this client connection
125 // was established.
126 private String connectTimeString;
127
128 // A set of persistent searches registered for this client.
129 private CopyOnWriteArrayList<PersistentSearch> persistentSearches;
130
131 // The network group to which the connection belongs to.
132 private NetworkGroup networkGroup;
133
134
135
136 /**
137 * Performs the appropriate initialization generic to all client
138 * connections.
139 */
140 protected ClientConnection()
141 {
142 connectTime = TimeThread.getTime();
143 connectTimeString = TimeThread.getGMTTime();
144 authenticationInfo = new AuthenticationInfo();
145 saslAuthState = null;
146 bindInProgress = false;
147 persistentSearches = new CopyOnWriteArrayList<PersistentSearch>();
148 sizeLimit = DirectoryServer.getSizeLimit();
149 timeLimit = DirectoryServer.getTimeLimit();
150 idleTimeLimit = DirectoryServer.getIdleTimeLimit();
151 lookthroughLimit = DirectoryServer.getLookthroughLimit();
152 finalized = false;
153 privileges = new HashSet<Privilege>();
154 networkGroup = NetworkGroup.getDefaultNetworkGroup();
155 }
156
157
158
159 /**
160 * Performs any internal cleanup that may be necessary when this
161 * client connection is disconnected, or if not on disconnec, then
162 * ultimately whenever it is reaped by the garbage collector. In
163 * this case, it will be used to ensure that the connection is
164 * deregistered with the {@code AuthenticatedUsers} manager, and
165 * will then invoke the {@code finalizeClientConnection} method.
166 */
167 @org.opends.server.types.PublicAPI(
168 stability=org.opends.server.types.StabilityLevel.PRIVATE,
169 mayInstantiate=false,
170 mayExtend=false,
171 mayInvoke=true,
172 notes="This method should only be invoked by connection " +
173 "handlers.")
174 protected final void finalizeConnectionInternal()
175 {
176 if (finalized)
177 {
178 return;
179 }
180
181 finalized = true;
182
183 // Deregister with the set of authenticated users.
184 Entry authNEntry = authenticationInfo.getAuthenticationEntry();
185 Entry authZEntry = authenticationInfo.getAuthorizationEntry();
186
187 if (authNEntry != null)
188 {
189 if ((authZEntry == null) ||
190 authZEntry.getDN().equals(authNEntry.getDN()))
191 {
192 DirectoryServer.getAuthenticatedUsers().remove(
193 authNEntry.getDN(), this);
194 }
195 else
196 {
197 DirectoryServer.getAuthenticatedUsers().remove(
198 authNEntry.getDN(), this);
199 DirectoryServer.getAuthenticatedUsers().remove(
200 authZEntry.getDN(), this);
201 }
202 }
203 else if (authZEntry != null)
204 {
205 DirectoryServer.getAuthenticatedUsers().remove(
206 authZEntry.getDN(), this);
207 }
208
209 try
210 {
211 finalizeClientConnection();
212 }
213 catch (Exception e)
214 {
215 if (debugEnabled())
216 {
217 TRACER.debugCaught(DebugLogLevel.ERROR, e);
218 }
219 }
220 }
221
222
223
224 /**
225 * Performs any cleanup work that may be necessary when this client
226 * connection is terminated. By default, no action is taken.
227 * <BR><BR>
228 * If possible, this method will be invoked when the client
229 * connection is disconnected. If it isn't invoked at that time,
230 * then it will be called when the client connection object is
231 * finalized by the garbage collector.
232 */
233 @org.opends.server.types.PublicAPI(
234 stability=org.opends.server.types.StabilityLevel.VOLATILE,
235 mayInstantiate=false,
236 mayExtend=true,
237 mayInvoke=false)
238 protected void finalizeClientConnection()
239 {
240 // No implementation is required by default.
241 }
242
243
244
245 /**
246 * Retrieves the time that this connection was established, measured
247 * in the number of milliseconds since January 1, 1970 UTC.
248 *
249 * @return The time that this connection was established, measured
250 * in the number of milliseconds since January 1, 1970 UTC.
251 */
252 public final long getConnectTime()
253 {
254 return connectTime;
255 }
256
257
258
259 /**
260 * Retrieves a string representation of the time that this
261 * connection was established.
262 *
263 * @return A string representation of the time that this connection
264 * was established.
265 */
266 public final String getConnectTimeString()
267 {
268 return connectTimeString;
269 }
270
271
272
273 /**
274 * Retrieves the unique identifier that has been assigned to this
275 * connection.
276 *
277 * @return The unique identifier that has been assigned to this
278 * connection.
279 */
280 public abstract long getConnectionID();
281
282
283
284 /**
285 * Retrieves the connection handler that accepted this client
286 * connection.
287 *
288 * @return The connection handler that accepted this client
289 * connection.
290 */
291 public abstract ConnectionHandler getConnectionHandler();
292
293
294
295 /**
296 * Retrieves the protocol that the client is using to communicate
297 * with the Directory Server.
298 *
299 * @return The protocol that the client is using to communicate
300 * with the Directory Server.
301 */
302 public abstract String getProtocol();
303
304
305
306 /**
307 * Retrieves a string representation of the address of the client.
308 *
309 * @return A string representation of the address of the client.
310 */
311 public abstract String getClientAddress();
312
313
314
315 /**
316 * Retrieves a string representation of the address on the server to
317 * which the client connected.
318 *
319 * @return A string representation of the address on the server to
320 * which the client connected.
321 */
322 public abstract String getServerAddress();
323
324
325
326 /**
327 * Retrieves the {@code java.net.InetAddress} associated with the
328 * remote client system.
329 *
330 * @return The {@code java.net.InetAddress} associated with the
331 * remote client system. It may be {@code null} if the
332 * client is not connected over an IP-based connection.
333 */
334 public abstract InetAddress getRemoteAddress();
335
336
337
338 /**
339 * Retrieves the {@code java.net.InetAddress} for the Directory
340 * Server system to which the client has established the connection.
341 *
342 * @return The {@code java.net.InetAddress} for the Directory
343 * Server system to which the client has established the
344 * connection. It may be {@code null} if the client is not
345 * connected over an IP-based connection.
346 */
347 public abstract InetAddress getLocalAddress();
348
349
350
351 /**
352 * Indicates whether this client connection is currently using a
353 * secure mechanism to communicate with the server. Note that this
354 * may change over time based on operations performed by the client
355 * or server (e.g., it may go from {@code false} to {@code true} if
356 * if the client uses the StartTLS extended operation).
357 *
358 * @return {@code true} if the client connection is currently using
359 * a secure mechanism to communicate with the server, or
360 * {@code false} if not.
361 */
362 public abstract boolean isSecure();
363
364
365
366 /**
367 * Retrieves the connection security provider for this client
368 * connection.
369 *
370 * @return The connection security provider for this client
371 * connection.
372 */
373 public abstract ConnectionSecurityProvider
374 getConnectionSecurityProvider();
375
376
377
378 /**
379 * Specifies the connection security provider for this client
380 * connection.
381 *
382 * @param securityProvider The connection security provider to use
383 * for communication on this client
384 * connection.
385 */
386 public abstract void setConnectionSecurityProvider(
387 ConnectionSecurityProvider
388 securityProvider);
389
390
391
392 /**
393 * Retrieves the human-readable name of the security mechanism that
394 * is used to protect communication with this client.
395 *
396 * @return The human-readable name of the security mechanism that
397 * is used to protect communication with this client, or
398 * {@code null} if no security is in place.
399 */
400 public abstract String getSecurityMechanism();
401
402
403
404 /**
405 * Retrieves a {@code Selector} that may be used to ensure that
406 * write operations complete in a timely manner, or terminate the
407 * connection in the event that they fail to do so. This is an
408 * optional method for client connections, and the default
409 * implementation returns {@code null} to indicate that the maximum
410 * blocked write time limit is not supported for this connection.
411 * Subclasses that do wish to support this functionality should
412 * return a valid {@code Selector} object.
413 *
414 * @return The {@code Selector} that may be used to ensure that
415 * write operations complete in a timely manner, or
416 * {@code null} if this client connection does not support
417 * maximum blocked write time limit functionality.
418 */
419 public Selector getWriteSelector()
420 {
421 // There will not be a write selector in the default
422 // implementation.
423 return null;
424 }
425
426
427
428 /**
429 * Retrieves the maximum length of time in milliseconds that
430 * attempts to write data to the client should be allowed to block.
431 * A value of zero indicates there should be no limit.
432 *
433 * @return The maximum length of time in milliseconds that attempts
434 * to write data to the client should be allowed to block,
435 * or zero if there should be no limit.
436 */
437 public long getMaxBlockedWriteTimeLimit()
438 {
439 // By default, we'll return 0, which indicates that there should
440 // be no maximum time limit. Subclasses should override this if
441 // they want to support a maximum blocked write time limit.
442 return 0L;
443 }
444
445
446
447 /**
448 * Indicates that the data in the provided buffer has been read from
449 * the client and should be processed. The contents of the provided
450 * buffer will be in clear-text (the data may have been passed
451 * through a connection security provider to obtain the clear-text
452 * version), and may contain part or all of one or more client
453 * requests.
454 *
455 * @param buffer The byte buffer containing the data available for
456 * reading.
457 *
458 * @return {@code true} if all the data in the provided buffer was
459 * processed and the client connection can remain
460 * established, or {@code false} if a decoding error
461 * occurred and requests from this client should no longer
462 * be processed. Note that if this method does return
463 * {@code false}, then it must have already disconnected
464 * the client.
465 */
466 public abstract boolean processDataRead(ByteBuffer buffer);
467
468
469
470 /**
471 * Sends a response to the client based on the information in the
472 * provided operation.
473 *
474 * @param operation The operation for which to send the response.
475 */
476 public abstract void sendResponse(Operation operation);
477
478
479
480 /**
481 * Sends the provided search result entry to the client.
482 *
483 * @param searchOperation The search operation with which the
484 * entry is associated.
485 * @param searchEntry The search result entry to be sent to
486 * the client.
487 *
488 * @throws DirectoryException If a problem occurs while attempting
489 * to send the entry to the client and
490 * the search should be terminated.
491 */
492 public abstract void sendSearchEntry(
493 SearchOperation searchOperation,
494 SearchResultEntry searchEntry)
495 throws DirectoryException;
496
497
498
499 /**
500 * Sends the provided search result reference to the client.
501 *
502 * @param searchOperation The search operation with which the
503 * reference is associated.
504 * @param searchReference The search result reference to be sent
505 * to the client.
506 *
507 * @return {@code true} if the client is able to accept referrals,
508 * or {@code false} if the client cannot handle referrals
509 * and no more attempts should be made to send them for the
510 * associated search operation.
511 *
512 * @throws DirectoryException If a problem occurs while attempting
513 * to send the reference to the client
514 * and the search should be terminated.
515 */
516 public abstract boolean sendSearchReference(
517 SearchOperation searchOperation,
518 SearchResultReference searchReference)
519 throws DirectoryException;
520
521
522
523 /**
524 * Invokes the intermediate response plugins on the provided
525 * response message and sends it to the client.
526 *
527 * @param intermediateResponse The intermediate response message
528 * to be sent.
529 *
530 * @return {@code true} if processing on the associated operation
531 * should continue, or {@code false} if not.
532 */
533 public final boolean sendIntermediateResponse(
534 IntermediateResponse intermediateResponse)
535 {
536 // Invoke the intermediate response plugins for the response
537 // message.
538 PluginConfigManager pluginConfigManager =
539 DirectoryServer.getPluginConfigManager();
540 PluginResult.IntermediateResponse pluginResult =
541 pluginConfigManager.invokeIntermediateResponsePlugins(
542 intermediateResponse);
543
544 boolean continueProcessing = true;
545 if (pluginResult.sendResponse())
546 {
547 continueProcessing =
548 sendIntermediateResponseMessage(intermediateResponse);
549 }
550
551 return (continueProcessing && pluginResult.continueProcessing());
552 }
553
554
555
556
557 /**
558 * Sends the provided intermediate response message to the client.
559 *
560 * @param intermediateResponse The intermediate response message
561 * to be sent.
562 *
563 * @return {@code true} if processing on the associated operation
564 * should continue, or {@code false} if not.
565 */
566 protected abstract boolean
567 sendIntermediateResponseMessage(
568 IntermediateResponse intermediateResponse);
569
570
571
572 /**
573 * Closes the connection to the client, optionally sending it a
574 * message indicating the reason for the closure. Note that the
575 * ability to send a notice of disconnection may not be available
576 * for all protocols or under all circumstances. Also note that
577 * when attempting to disconnect a client connection as a part of
578 * operation processing (e.g., within a plugin or other extension),
579 * the {@code disconnectClient} method within that operation should
580 * be called rather than invoking this method directly.
581 * <BR><BR>
582 * All subclasses must invoke the {@code finalizeConnectionInternal}
583 * method during the course of processing this method.
584 *
585 * @param disconnectReason The disconnect reason that provides the
586 * generic cause for the disconnect.
587 * @param sendNotification Indicates whether to try to provide
588 * notification to the client that the
589 * connection will be closed.
590 * @param message The message to send to the client. It
591 * may be {@code null} if no notification
592 * is to be sent.
593 */
594 public abstract void disconnect(DisconnectReason disconnectReason,
595 boolean sendNotification,
596 Message message);
597
598
599
600 /**
601 * Indicates whether a bind operation is in progress on this client
602 * connection. If so, then no new operations should be allowed
603 * until the bind has completed.
604 *
605 * @return {@code true} if a bind operation is in progress on this
606 * connection, or {@code false} if not.
607 */
608 public boolean bindInProgress()
609 {
610 return bindInProgress;
611 }
612
613
614
615 /**
616 * Specifies whether a bind operation is in progress on this client
617 * connection. If so, then no new operations should be allowed
618 * until the bind has completed.
619 *
620 * @param bindInProgress Specifies whether a bind operation is in
621 * progress on this client connection.
622 */
623 public void setBindInProgress(boolean bindInProgress)
624 {
625 this.bindInProgress = bindInProgress;
626 }
627
628
629
630 /**
631 * Indicates whether the user associated with this client connection
632 * must change their password before they will be allowed to do
633 * anything else.
634 *
635 * @return {@code true} if the user associated with this client
636 * connection must change their password before they will
637 * be allowed to do anything else, or {@code false} if not.
638 */
639 public final boolean mustChangePassword()
640 {
641 if (authenticationInfo == null)
642 {
643 return false;
644 }
645 else
646 {
647 return authenticationInfo.mustChangePassword();
648 }
649 }
650
651
652
653 /**
654 * Specifies whether the user associated with this client connection
655 * must change their password before they will be allowed to do
656 * anything else.
657 *
658 * @param mustChangePassword Specifies whether the user associated
659 * with this client connection must
660 * change their password before they
661 * will be allowed to do anything else.
662 */
663 public final void setMustChangePassword(boolean mustChangePassword)
664 {
665 if (authenticationInfo == null)
666 {
667 setAuthenticationInfo(new AuthenticationInfo());
668 }
669
670 authenticationInfo.setMustChangePassword(mustChangePassword);
671 }
672
673
674
675 /**
676 * Retrieves the set of operations in progress for this client
677 * connection. This list must not be altered by any caller.
678 *
679 * @return The set of operations in progress for this client
680 * connection.
681 */
682 public abstract Collection<AbstractOperation>
683 getOperationsInProgress();
684
685
686
687 /**
688 * Retrieves the operation in progress with the specified message
689 * ID.
690 *
691 * @param messageID The message ID of the operation to retrieve.
692 *
693 * @return The operation in progress with the specified message ID,
694 * or {@code null} if no such operation could be found.
695 */
696 public abstract AbstractOperation
697 getOperationInProgress(int messageID);
698
699
700
701 /**
702 * Removes the provided operation from the set of operations in
703 * progress for this client connection. Note that this does not
704 * make any attempt to cancel any processing that may already be in
705 * progress for the operation.
706 *
707 * @param messageID The message ID of the operation to remove from
708 * the set of operations in progress.
709 *
710 * @return {@code true} if the operation was found and removed from
711 * the set of operations in progress, or {@code false} if
712 * not.
713 */
714 public abstract boolean removeOperationInProgress(int messageID);
715
716
717
718 /**
719 * Retrieves the set of persistent searches registered for this
720 * client.
721 *
722 * @return The set of persistent searches registered for this
723 * client.
724 */
725 public final CopyOnWriteArrayList<PersistentSearch>
726 getPersistentSearches()
727 {
728 return persistentSearches;
729 }
730
731
732
733 /**
734 * Registers the provided persistent search for this client. Note
735 * that this should only be called by
736 * {@code DirectoryServer.registerPersistentSearch} and not through
737 * any other means.
738 *
739 * @param persistentSearch The persistent search to register for
740 * this client.
741 */
742 @org.opends.server.types.PublicAPI(
743 stability=org.opends.server.types.StabilityLevel.PRIVATE,
744 mayInstantiate=false,
745 mayExtend=false,
746 mayInvoke=false)
747 public final void registerPersistentSearch(PersistentSearch
748 persistentSearch)
749 {
750 persistentSearches.add(persistentSearch);
751 }
752
753
754
755 /**
756 * Deregisters the provided persistent search for this client. Note
757 * that this should only be called by
758 * {@code DirectoryServer.deregisterPersistentSearch} and not
759 * through any other means.
760 *
761 * @param persistentSearch The persistent search to deregister for
762 * this client.
763 */
764 @org.opends.server.types.PublicAPI(
765 stability=org.opends.server.types.StabilityLevel.PRIVATE,
766 mayInstantiate=false,
767 mayExtend=false,
768 mayInvoke=false)
769 public final void deregisterPersistentSearch(PersistentSearch
770 persistentSearch)
771 {
772 persistentSearches.remove(persistentSearch);
773 }
774
775
776
777 /**
778 * Attempts to cancel the specified operation.
779 *
780 * @param messageID The message ID of the operation to cancel.
781 * @param cancelRequest An object providing additional information
782 * about how the cancel should be processed.
783 *
784 * @return A cancel result that either indicates that the cancel
785 * was successful or provides a reason that it was not.
786 */
787 public abstract CancelResult cancelOperation(int messageID,
788 CancelRequest cancelRequest);
789
790
791
792 /**
793 * Attempts to cancel all operations in progress on this connection.
794 *
795 * @param cancelRequest An object providing additional information
796 * about how the cancel should be processed.
797 */
798 public abstract void cancelAllOperations(
799 CancelRequest cancelRequest);
800
801
802
803 /**
804 * Attempts to cancel all operations in progress on this connection
805 * except the operation with the specified message ID.
806 *
807 * @param cancelRequest An object providing additional information
808 * about how the cancel should be processed.
809 * @param messageID The message ID of the operation that
810 * should not be canceled.
811 */
812 public abstract void cancelAllOperationsExcept(
813 CancelRequest cancelRequest,
814 int messageID);
815
816
817
818 /**
819 * Retrieves information about the authentication that has been
820 * performed for this connection.
821 *
822 * @return Information about the user that is currently
823 * authenticated on this connection.
824 */
825 public AuthenticationInfo getAuthenticationInfo()
826 {
827 return authenticationInfo;
828 }
829
830
831
832 /**
833 * Specifies information about the authentication that has been
834 * performed for this connection.
835 *
836 * @param authenticationInfo Information about the authentication
837 * that has been performed for this
838 * connection. It should not be
839 * {@code null}.
840 */
841 public void setAuthenticationInfo(AuthenticationInfo
842 authenticationInfo)
843 {
844 if (this.authenticationInfo != null)
845 {
846 Entry authNEntry =
847 this.authenticationInfo.getAuthenticationEntry();
848 Entry authZEntry =
849 this.authenticationInfo.getAuthorizationEntry();
850
851 if (authNEntry != null)
852 {
853 if ((authZEntry == null) ||
854 authZEntry.getDN().equals(authNEntry.getDN()))
855 {
856 DirectoryServer.getAuthenticatedUsers().remove(
857 authNEntry.getDN(), this);
858 }
859 else
860 {
861 DirectoryServer.getAuthenticatedUsers().remove(
862 authNEntry.getDN(), this);
863 DirectoryServer.getAuthenticatedUsers().remove(
864 authZEntry.getDN(), this);
865 }
866 }
867 else if (authZEntry != null)
868 {
869 DirectoryServer.getAuthenticatedUsers().remove(
870 authZEntry.getDN(), this);
871 }
872 }
873
874 if (authenticationInfo == null)
875 {
876 this.authenticationInfo = new AuthenticationInfo();
877 updatePrivileges(null, false);
878 }
879 else
880 {
881 this.authenticationInfo = authenticationInfo;
882
883 Entry authNEntry = authenticationInfo.getAuthenticationEntry();
884 Entry authZEntry = authenticationInfo.getAuthorizationEntry();
885
886 if (authNEntry != null)
887 {
888 if ((authZEntry == null) ||
889 authZEntry.getDN().equals(authNEntry.getDN()))
890 {
891 DirectoryServer.getAuthenticatedUsers().put(
892 authNEntry.getDN(), this);
893 }
894 else
895 {
896 DirectoryServer.getAuthenticatedUsers().put(
897 authNEntry.getDN(), this);
898 DirectoryServer.getAuthenticatedUsers().put(
899 authZEntry.getDN(), this);
900 }
901 }
902 else
903 {
904 if (authZEntry != null)
905 {
906 DirectoryServer.getAuthenticatedUsers().put(
907 authZEntry.getDN(), this);
908 }
909 }
910
911 updatePrivileges(authZEntry, authenticationInfo.isRoot());
912 }
913 }
914
915
916
917 /**
918 * Updates the cached entry associated with either the
919 * authentication and/or authorization identity with the provided
920 * version.
921 *
922 * @param oldEntry The user entry currently serving as the
923 * authentication and/or authorization identity.
924 * @param newEntry The updated entry that should replace the
925 * existing entry. It may optionally have a
926 * different DN than the old entry.
927 */
928 public final void updateAuthenticationInfo(Entry oldEntry,
929 Entry newEntry)
930 {
931 Entry authNEntry = authenticationInfo.getAuthenticationEntry();
932 Entry authZEntry = authenticationInfo.getAuthorizationEntry();
933
934 if ((authNEntry != null) &&
935 authNEntry.getDN().equals(oldEntry.getDN()))
936 {
937 if ((authZEntry == null) ||
938 (! authZEntry.getDN().equals(authNEntry.getDN())))
939 {
940 setAuthenticationInfo(
941 authenticationInfo.duplicate(newEntry, authZEntry));
942 updatePrivileges(newEntry, authenticationInfo.isRoot());
943 }
944 else
945 {
946 setAuthenticationInfo(
947 authenticationInfo.duplicate(newEntry, newEntry));
948 updatePrivileges(newEntry, authenticationInfo.isRoot());
949 }
950 }
951 else if ((authZEntry != null) &&
952 (authZEntry.getDN().equals(oldEntry.getDN())))
953 {
954 setAuthenticationInfo(
955 authenticationInfo.duplicate(authNEntry, newEntry));
956 }
957 }
958
959
960
961 /**
962 * Sets properties in this client connection to indicate that the
963 * client is unauthenticated. This includes setting the
964 * authentication info structure to an empty default, as well as
965 * setting the size and time limit values to their defaults.
966 */
967 public void setUnauthenticated()
968 {
969 setAuthenticationInfo(new AuthenticationInfo());
970 this.sizeLimit = DirectoryServer.getSizeLimit();
971 this.timeLimit = DirectoryServer.getTimeLimit();
972 }
973
974
975
976 /**
977 * Indicates whether the authenticated client has the specified
978 * privilege.
979 *
980 * @param privilege The privilege for which to make the
981 * determination.
982 * @param operation The operation being processed which needs to
983 * make the privilege determination, or
984 * {@code null} if there is no associated
985 * operation.
986 *
987 * @return {@code true} if the authenticated client has the
988 * specified privilege, or {@code false} if not.
989 */
990 public boolean hasPrivilege(Privilege privilege,
991 Operation operation)
992 {
993 if (privilege == Privilege.PROXIED_AUTH)
994 {
995 // This determination should always be made against the
996 // authentication identity rather than the authorization
997 // identity.
998 Entry authEntry = authenticationInfo.getAuthenticationEntry();
999 boolean isRoot = authenticationInfo.isRoot();
1000 return getPrivileges(authEntry,
1001 isRoot).contains(Privilege.PROXIED_AUTH) ||
1002 DirectoryServer.isDisabled(Privilege.PROXIED_AUTH);
1003 }
1004
1005 boolean result;
1006 if (operation == null)
1007 {
1008 result = privileges.contains(privilege);
1009 if (debugEnabled())
1010 {
1011 DN authDN = authenticationInfo.getAuthenticationDN();
1012
1013 Message message = INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGE
1014 .get(getConnectionID(), -1L,
1015 String.valueOf(authDN),
1016 privilege.getName(), result);
1017 TRACER.debugMessage(DebugLogLevel.INFO, message.toString());
1018 }
1019 }
1020 else
1021 {
1022 if (operation.getAuthorizationDN().equals(
1023 authenticationInfo.getAuthorizationDN()) ||
1024 (operation.getAuthorizationDN().equals(DN.NULL_DN) &&
1025 !authenticationInfo.isAuthenticated())) {
1026 result = privileges.contains(privilege) ||
1027 DirectoryServer.isDisabled(privilege);
1028 if (debugEnabled())
1029 {
1030 DN authDN = authenticationInfo.getAuthenticationDN();
1031
1032 Message message =
1033 INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGE.get(
1034 getConnectionID(),
1035 operation.getOperationID(),
1036 String.valueOf(authDN),
1037 privilege.getName(), result);
1038 TRACER.debugMessage(DebugLogLevel.INFO, message.toString());
1039 }
1040 }
1041 else
1042 {
1043 Entry authorizationEntry = operation.getAuthorizationEntry();
1044 if (authorizationEntry == null)
1045 {
1046 result = false;
1047 }
1048 else
1049 {
1050 boolean isRoot =
1051 DirectoryServer.isRootDN(authorizationEntry.getDN());
1052 result = getPrivileges(authorizationEntry,
1053 isRoot).contains(privilege) ||
1054 DirectoryServer.isDisabled(privilege);
1055 }
1056 }
1057 }
1058
1059 return result;
1060 }
1061
1062
1063
1064 /**
1065 * Indicates whether the authenticate client has all of the
1066 * specified privileges.
1067 *
1068 * @param privileges The array of privileges for which to make the
1069 * determination.
1070 * @param operation The operation being processed which needs to
1071 * make the privilege determination, or
1072 * {@code null} if there is no associated
1073 * operation.
1074 *
1075 * @return {@code true} if the authenticated client has all of the
1076 * specified privileges, or {@code false} if not.
1077 */
1078 public boolean hasAllPrivileges(Privilege[] privileges,
1079 Operation operation)
1080 {
1081 HashSet<Privilege> privSet = this.privileges;
1082
1083 if (debugEnabled())
1084 {
1085 for (Privilege p : privileges)
1086 {
1087 if (! privSet.contains(p))
1088 {
1089 return false;
1090 }
1091 }
1092
1093 return true;
1094 }
1095 else
1096 {
1097 boolean result = true;
1098 StringBuilder buffer = new StringBuilder();
1099 buffer.append("{");
1100
1101 for (int i=0; i < privileges.length; i++)
1102 {
1103 if (i > 0)
1104 {
1105 buffer.append(",");
1106 }
1107
1108 buffer.append(privileges[i].getName());
1109
1110 if (! privSet.contains(privileges[i]))
1111 {
1112 result = false;
1113 }
1114 }
1115
1116 buffer.append(" }");
1117
1118 if (operation == null)
1119 {
1120 DN authDN = authenticationInfo.getAuthenticationDN();
1121
1122 Message message =
1123 INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGES.get(
1124 getConnectionID(), -1L,
1125 String.valueOf(authDN),
1126 buffer.toString(), result);
1127 TRACER.debugMessage(DebugLogLevel.INFO,
1128 message.toString());
1129 }
1130 else
1131 {
1132 DN authDN = authenticationInfo.getAuthenticationDN();
1133
1134 Message message = INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGES
1135 .get(
1136 getConnectionID(),
1137 operation.getOperationID(),
1138 String.valueOf(authDN),
1139 buffer.toString(), result);
1140 TRACER.debugMessage(DebugLogLevel.INFO, message.toString());
1141 }
1142
1143 return result;
1144 }
1145 }
1146
1147
1148
1149 /**
1150 * Retrieves the set of privileges encoded in the provided entry.
1151 *
1152 * @param entry The entry to use to obtain the privilege
1153 * information.
1154 * @param isRoot Indicates whether the set of root privileges
1155 * should be automatically included in the
1156 * privilege set.
1157 *
1158 * @return A set of the privileges that should be assigned.
1159 */
1160 private HashSet<Privilege> getPrivileges(Entry entry,
1161 boolean isRoot)
1162 {
1163 if (entry == null)
1164 {
1165 return new HashSet<Privilege>(0);
1166 }
1167
1168 HashSet<Privilege> newPrivileges = new HashSet<Privilege>();
1169 HashSet<Privilege> removePrivileges = new HashSet<Privilege>();
1170
1171 if (isRoot)
1172 {
1173 newPrivileges.addAll(DirectoryServer.getRootPrivileges());
1174 }
1175
1176 AttributeType privType =
1177 DirectoryServer.getAttributeType(OP_ATTR_PRIVILEGE_NAME);
1178 List<Attribute> attrList = entry.getAttribute(privType);
1179 if (attrList != null)
1180 {
1181 for (Attribute a : attrList)
1182 {
1183 for (AttributeValue v : a.getValues())
1184 {
1185 String privName = toLowerCase(v.getStringValue());
1186
1187 // If the name of the privilege is prefixed with a minus
1188 // sign, then we will take away that privilege from the
1189 // user. We'll handle that at the end so that we can make
1190 // sure it's not added back later.
1191 if (privName.startsWith("-"))
1192 {
1193 privName = privName.substring(1);
1194 Privilege p = Privilege.privilegeForName(privName);
1195 if (p == null)
1196 {
1197 // FIXME -- Generate an administrative alert.
1198
1199 // We don't know what privilege to remove, so we'll
1200 // remove all of them.
1201 newPrivileges.clear();
1202 return newPrivileges;
1203 }
1204 else
1205 {
1206 removePrivileges.add(p);
1207 }
1208 }
1209 else
1210 {
1211 Privilege p = Privilege.privilegeForName(privName);
1212 if (p == null)
1213 {
1214 // FIXME -- Generate an administrative alert.
1215 }
1216 else
1217 {
1218 newPrivileges.add(p);
1219 }
1220 }
1221 }
1222 }
1223 }
1224
1225 for (Privilege p : removePrivileges)
1226 {
1227 newPrivileges.remove(p);
1228 }
1229
1230 return newPrivileges;
1231 }
1232
1233
1234
1235 /**
1236 * Updates the privileges associated with this client connection
1237 * object based on the provided entry for the authentication
1238 * identity.
1239 *
1240 * @param entry The entry for the authentication identity
1241 * associated with this client connection.
1242 * @param isRoot Indicates whether the associated user is a root
1243 * user and should automatically inherit the root
1244 * privilege set.
1245 */
1246 private void updatePrivileges(Entry entry, boolean isRoot)
1247 {
1248 privileges = getPrivileges(entry, isRoot);
1249 }
1250
1251
1252
1253 /**
1254 * Retrieves an opaque set of information that may be used for
1255 * processing multi-stage SASL binds.
1256 *
1257 * @return An opaque set of information that may be used for
1258 * processing multi-stage SASL binds.
1259 */
1260 public final Object getSASLAuthStateInfo()
1261 {
1262 return saslAuthState;
1263 }
1264
1265
1266
1267 /**
1268 * Specifies an opaque set of information that may be used for
1269 * processing multi-stage SASL binds.
1270 *
1271 * @param saslAuthState An opaque set of information that may be
1272 * used for processing multi-stage SASL
1273 * binds.
1274 */
1275 public final void setSASLAuthStateInfo(Object saslAuthState)
1276 {
1277 this.saslAuthState = saslAuthState;
1278 }
1279
1280
1281
1282 /**
1283 * Retrieves the size limit that will be enforced for searches
1284 * performed using this client connection.
1285 *
1286 * @return The size limit that will be enforced for searches
1287 * performed using this client connection.
1288 */
1289 public final int getSizeLimit()
1290 {
1291 return sizeLimit;
1292 }
1293
1294
1295
1296 /**
1297 * Specifies the size limit that will be enforced for searches
1298 * performed using this client connection.
1299 *
1300 * @param sizeLimit The size limit that will be enforced for
1301 * searches performed using this client
1302 * connection.
1303 */
1304 public void setSizeLimit(int sizeLimit)
1305 {
1306 this.sizeLimit = sizeLimit;
1307 }
1308
1309
1310
1311 /**
1312 * Retrieves the maximum length of time in milliseconds that this
1313 * client connection will be allowed to remain idle before it should
1314 * be disconnected.
1315 *
1316 * @return The maximum length of time in milliseconds that this
1317 * client connection will be allowed to remain idle before
1318 * it should be disconnected.
1319 */
1320 public final long getIdleTimeLimit()
1321 {
1322 return idleTimeLimit;
1323 }
1324
1325
1326
1327 /**
1328 * Specifies the maximum length of time in milliseconds that this
1329 * client connection will be allowed to remain idle before it should
1330 * be disconnected.
1331 *
1332 * @param idleTimeLimit The maximum length of time in milliseconds
1333 * that this client connection will be
1334 * allowed to remain idle before it should be
1335 * disconnected.
1336 */
1337 public void setIdleTimeLimit(long idleTimeLimit)
1338 {
1339 this.idleTimeLimit = idleTimeLimit;
1340 }
1341
1342
1343
1344 /**
1345 * Retrieves the default maximum number of entries that should
1346 * checked for matches during a search.
1347 *
1348 * @return The default maximum number of entries that should
1349 * checked for matches during a search.
1350 */
1351 public final int getLookthroughLimit()
1352 {
1353 return lookthroughLimit;
1354 }
1355
1356
1357
1358 /**
1359 * Specifies the default maximum number of entries that should
1360 * be checked for matches during a search.
1361 *
1362 * @param lookthroughLimit The default maximum number of
1363 * entries that should be check for
1364 * matches during a search.
1365 */
1366 public void setLookthroughLimit(int lookthroughLimit)
1367 {
1368 this.lookthroughLimit = lookthroughLimit;
1369 }
1370
1371
1372
1373 /**
1374 * Retrieves the time limit that will be enforced for searches
1375 * performed using this client connection.
1376 *
1377 * @return The time limit that will be enforced for searches
1378 * performed using this client connection.
1379 */
1380 public final int getTimeLimit()
1381 {
1382 return timeLimit;
1383 }
1384
1385
1386
1387 /**
1388 * Specifies the time limit that will be enforced for searches
1389 * performed using this client connection.
1390 *
1391 * @param timeLimit The time limit that will be enforced for
1392 * searches performed using this client
1393 * connection.
1394 */
1395 public void setTimeLimit(int timeLimit)
1396 {
1397 this.timeLimit = timeLimit;
1398 }
1399
1400
1401
1402 /**
1403 * Retrieves a one-line summary of this client connection in a form
1404 * that is suitable for including in the monitor entry for the
1405 * associated connection handler. It should be in a format that is
1406 * both humand readable and machine parseable (e.g., a
1407 * space-delimited name-value list, with quotes around the values).
1408 *
1409 * @return A one-line summary of this client connection in a form
1410 * that is suitable for including in the monitor entry for
1411 * the associated connection handler.
1412 */
1413 public abstract String getMonitorSummary();
1414
1415
1416
1417 /**
1418 * Indicates whether the user associated with this client connection
1419 * should be considered a member of the specified group, optionally
1420 * evaluated within the context of the provided operation. If an
1421 * operation is given, then the determination should be made based
1422 * on the authorization identity for that operation. If the
1423 * operation is {@code null}, then the determination should be made
1424 * based on the authorization identity for this client connection.
1425 * Note that this is a point-in-time determination and the caller
1426 * must not cache the result.
1427 *
1428 * @param group The group for which to make the determination.
1429 * @param operation The operation to use to obtain the
1430 * authorization identity for which to make the
1431 * determination, or {@code null} if the
1432 * authorization identity should be obtained from
1433 * this client connection.
1434 *
1435 * @return {@code true} if the target user is currently a member of
1436 * the specified group, or {@code false} if not.
1437 *
1438 * @throws DirectoryException If a problem occurs while attempting
1439 * to make the determination.
1440 */
1441 public boolean isMemberOf(Group group, Operation operation)
1442 throws DirectoryException
1443 {
1444 if (operation == null)
1445 {
1446 return group.isMember(authenticationInfo.getAuthorizationDN());
1447 }
1448 else
1449 {
1450 return group.isMember(operation.getAuthorizationDN());
1451 }
1452 }
1453
1454
1455
1456 /**
1457 * Retrieves the set of groups in which the user associated with
1458 * this client connection may be considered to be a member. If an
1459 * operation is provided, then the determination should be made
1460 * based on the authorization identity for that operation. If the
1461 * operation is {@code null}, then it should be made based on the
1462 * authorization identity for this client connection. Note that
1463 * this is a point-in-time determination and the caller must not
1464 * cache the result.
1465 *
1466 * @param operation The operation to use to obtain the
1467 * authorization identity for which to retrieve
1468 * the associated groups, or {@code null} if the
1469 * authorization identity should be obtained from
1470 * this client connection.
1471 *
1472 * @return The set of groups in which the target user is currently
1473 * a member.
1474 *
1475 * @throws DirectoryException If a problem occurs while attempting
1476 * to make the determination.
1477 */
1478 public Set<Group> getGroups(Operation operation)
1479 throws DirectoryException
1480 {
1481 // FIXME -- This probably isn't the most efficient implementation.
1482 DN authzDN;
1483 if (operation == null)
1484 {
1485 if ((authenticationInfo == null) ||
1486 (! authenticationInfo.isAuthenticated()))
1487 {
1488 authzDN = null;
1489 }
1490 else
1491 {
1492 authzDN = authenticationInfo.getAuthorizationDN();
1493 }
1494 }
1495 else
1496 {
1497 authzDN = operation.getAuthorizationDN();
1498 }
1499
1500 if ((authzDN == null) || authzDN.isNullDN())
1501 {
1502 return java.util.Collections.<Group>emptySet();
1503 }
1504
1505 Entry userEntry = DirectoryServer.getEntry(authzDN);
1506 if (userEntry == null)
1507 {
1508 return java.util.Collections.<Group>emptySet();
1509 }
1510
1511 HashSet<Group> groupSet = new HashSet<Group>();
1512 for (Group g :
1513 DirectoryServer.getGroupManager().getGroupInstances())
1514 {
1515 if (g.isMember(userEntry))
1516 {
1517 groupSet.add(g);
1518 }
1519 }
1520
1521 return groupSet;
1522 }
1523
1524
1525
1526 /**
1527 * Retrieves the DN of the key manager provider that should be used
1528 * for operations requiring access to a key manager. The default
1529 * implementation returns {@code null} to indicate that no key
1530 * manager provider is avaialble, but subclasses should override
1531 * this method to return a valid DN if they perform operations which
1532 * may need access to a key manager.
1533 *
1534 * @return The DN of the key manager provider that should be used
1535 * for operations requiring access to a key manager, or
1536 * {@code null} if there is no key manager provider
1537 * configured for this client connection.
1538 */
1539 public DN getKeyManagerProviderDN()
1540 {
1541 // In the default implementation, we'll return null.
1542 return null;
1543 }
1544
1545
1546
1547 /**
1548 * Retrieves the DN of the trust manager provider that should be
1549 * used for operations requiring access to a trust manager. The
1550 * default implementation returns {@code null} to indicate that no
1551 * trust manager provider is avaialble, but subclasses should
1552 * override this method to return a valid DN if they perform
1553 * operations which may need access to a trust manager.
1554 *
1555 * @return The DN of the trust manager provider that should be used
1556 * for operations requiring access to a trust manager, or
1557 * {@code null} if there is no trust manager provider
1558 * configured for this client connection.
1559 */
1560 public DN getTrustManagerProviderDN()
1561 {
1562 // In the default implementation, we'll return null.
1563 return null;
1564 }
1565
1566
1567
1568 /**
1569 * Retrieves the alias of the server certificate that should be used
1570 * for operations requiring a server certificate. The default
1571 * implementation returns {@code null} to indicate that any alias is
1572 * acceptable.
1573 *
1574 * @return The alias of the server certificate that should be used
1575 * for operations requring a server certificate, or
1576 * {@code null} if any alias is acceptable.
1577 */
1578 public String getCertificateAlias()
1579 {
1580 // In the default implementation, we'll return null.
1581 return null;
1582 }
1583
1584
1585
1586 /**
1587 * Retrieves a string representation of this client connection.
1588 *
1589 * @return A string representation of this client connection.
1590 */
1591 public final String toString()
1592 {
1593 StringBuilder buffer = new StringBuilder();
1594 toString(buffer);
1595 return buffer.toString();
1596 }
1597
1598
1599
1600 /**
1601 * Appends a string representation of this client connection to the
1602 * provided buffer.
1603 *
1604 * @param buffer The buffer to which the information should be
1605 * appended.
1606 */
1607 public abstract void toString(StringBuilder buffer);
1608
1609
1610
1611 /**
1612 * Performs any work that may be needed before the JVM invokes
1613 * garbage collection for this object. In this case, it makes sure
1614 * to deregister with the Directory Server as a change notification
1615 * listener. If a subclass wishes to perform custom finalization
1616 * processing, then it should override this method and make sure to
1617 * invoke {@code super.finalize} as its first call.
1618 */
1619 protected void finalize()
1620 {
1621 finalizeConnectionInternal();
1622 }
1623
1624
1625 /**
1626 * Returns the network group to which the connection belongs.
1627 *
1628 * @return the network group attached to the connection
1629 */
1630 public final NetworkGroup getNetworkGroup()
1631 {
1632 return networkGroup;
1633 }
1634
1635 /**
1636 * Sets the network group to which the connection belongs.
1637 *
1638 * @param networkGroup the network group to which the
1639 * connections belongs to
1640 */
1641 public final void setNetworkGroup (NetworkGroup networkGroup)
1642 {
1643 this.networkGroup = networkGroup;
1644 }
1645
1646
1647
1648 /**
1649 * Retrieves the length of time in milliseconds that this client
1650 * connection has been idle.
1651 * <BR><BR>
1652 * Note that the default implementation will always return zero.
1653 * Subclasses associated with connection handlers should override
1654 * this method if they wish to provided idle time limit
1655 * functionality.
1656 *
1657 * @return The length of time in milliseconds that this client
1658 * connection has been idle.
1659 */
1660 public long getIdleTime()
1661 {
1662 return 0L;
1663 }
1664 }
1665