| | |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2012 ForgeRock AS |
| | | * Portions copyright 2011-2013 ForgeRock AS |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | |
| | | */ |
| | | protected AtomicBoolean bindOrStartTLSInProgress; |
| | | |
| | | // Indicates whether any necessary finalization work has been done |
| | | // for this client connection. |
| | | /** |
| | | * Indicates whether any necessary finalization work has been done for this |
| | | * client connection. |
| | | */ |
| | | private boolean finalized; |
| | | |
| | | // The set of privileges assigned to this client connection. |
| | | /** The set of privileges assigned to this client connection. */ |
| | | private HashSet<Privilege> privileges; |
| | | |
| | | // The size limit for use with this client connection. |
| | | /** The size limit for use with this client connection. */ |
| | | private int sizeLimit; |
| | | |
| | | // The time limit for use with this client connection. |
| | | /** The time limit for use with this client connection. */ |
| | | private int timeLimit; |
| | | |
| | | // The lookthrough limit for use with this client connection. |
| | | /** The lookthrough limit for use with this client connection. */ |
| | | private int lookthroughLimit; |
| | | |
| | | // The time that this client connection was established. |
| | | /** The time that this client connection was established. */ |
| | | private final long connectTime; |
| | | |
| | | // The idle time limit for this client connection. |
| | | /** The idle time limit for this client connection. */ |
| | | private long idleTimeLimit; |
| | | |
| | | // The opaque information used for storing intermediate state |
| | | // information needed across multi-stage SASL binds. |
| | | /** |
| | | * The opaque information used for storing intermediate state information |
| | | * needed across multi-stage SASL binds. |
| | | */ |
| | | private Object saslAuthState; |
| | | |
| | | // A string representation of the time that this client connection |
| | | // was established. |
| | | /** |
| | | * A string representation of the time that this client connection was |
| | | * established. |
| | | */ |
| | | private final String connectTimeString; |
| | | |
| | | // A set of persistent searches registered for this client. |
| | | /** A set of persistent searches registered for this client. */ |
| | | private final CopyOnWriteArrayList<PersistentSearch> |
| | | persistentSearches; |
| | | |
| | | // The network group to which the connection belongs to. |
| | | /** The network group to which the connection belongs to. */ |
| | | private NetworkGroup networkGroup; |
| | | |
| | | /** Need to evaluate the network group for the first operation. */ |
| | |
| | | { |
| | | saslBindInProgress.set(false); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns whether this connection is used for inner work not directly |
| | | * requested by an external client. |
| | | * |
| | | * @return {@code true} if this is an inner connection, {@code false} |
| | | * otherwise |
| | | */ |
| | | public boolean isInnerConnection() |
| | | { |
| | | return getConnectionID() < 0; |
| | | } |
| | | |
| | | } |
| | |
| | | import org.opends.messages.Message; |
| | | import org.opends.messages.MessageBuilder; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.controls.ControlDecoder; |
| | | import org.opends.server.types.*; |
| | | |
| | | |
| | | /** |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isInnerOperation() |
| | | { |
| | | return operation.isInnerOperation(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isInternalOperation() |
| | | { |
| | | return operation.isInternalOperation(); |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void setInnerOperation(boolean isInnerOperation) |
| | | { |
| | | operation.setInnerOperation(isInnerOperation); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void setInternalOperation(boolean isInternalOperation) |
| | | { |
| | | operation.setInternalOperation(isInternalOperation); |
| | |
| | | @Override |
| | | public boolean isConnectLoggable(final ClientConnection connection) |
| | | { |
| | | final long connectionID = connection.getConnectionID(); |
| | | if (connectionID >= 0 || !suppressInternalOperations) |
| | | if (!connection.isInnerConnection() || !suppressInternalOperations) |
| | | { |
| | | switch (policy) |
| | | { |
| | |
| | | @Override |
| | | public boolean isDisconnectLoggable(final ClientConnection connection) |
| | | { |
| | | final long connectionID = connection.getConnectionID(); |
| | | if (connectionID >= 0 || !suppressInternalOperations) |
| | | if (!connection.isInnerConnection() || !suppressInternalOperations) |
| | | { |
| | | switch (policy) |
| | | { |
| | |
| | | */ |
| | | boolean isLoggable(final Operation operation) |
| | | { |
| | | final long connectionID = operation.getConnectionID(); |
| | | if (connectionID < 0) |
| | | { |
| | | // This is an internal operation. |
| | | if (operation.isSynchronizationOperation()) |
| | | { |
| | | return !suppressSynchronizationOperations; |
| | | } |
| | | else |
| | | { |
| | | return !suppressInternalOperations; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | return !((suppressInternalOperations && operation.isInnerOperation()) |
| | | || (suppressSynchronizationOperations |
| | | && operation.isSynchronizationOperation())); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | import static org.forgerock.opendj.adapter.server2x.Converters.*; |
| | | import static org.opends.messages.ProtocolMessages.*; |
| | | import static org.opends.server.loggers.AccessLogger.*; |
| | | import static org.opends.server.loggers.ErrorLogger.*; |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | |
| | | import java.net.UnknownHostException; |
| | | import java.text.ParseException; |
| | | import java.util.Collection; |
| | | import java.util.Map; |
| | | |
| | | import javax.servlet.FilterChain; |
| | | import javax.servlet.FilterConfig; |
| | |
| | | import org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory; |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.admin.std.server.ConnectionHandlerCfg; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.schema.SchemaConstants; |
| | | import org.opends.server.types.AddressMask; |
| | |
| | | public void doFilter(ServletRequest request, ServletResponse response, |
| | | FilterChain chain) |
| | | { |
| | | final Map<ClientConnection, ClientConnection> clientConnections = |
| | | this.connectionHandler.getClientConnectionsMap(); |
| | | final HTTPClientConnection clientConnection = |
| | | new HTTPClientConnection(this.connectionHandler, request); |
| | | clientConnections.put(clientConnection, clientConnection); |
| | | this.connectionHandler.addClientConnection(clientConnection); |
| | | try |
| | | { |
| | | if (!canProcessRequest(request, clientConnection)) |
| | | { |
| | | return; |
| | | } |
| | | // logs the connect after all the possible disconnect reasons have been |
| | | // checked. |
| | | logConnect(clientConnection); |
| | | |
| | | Connection connection = new SdkConnectionAdapter(clientConnection); |
| | | |
| | |
| | | // The user could not be authenticated. Send an HTTP Basic authentication |
| | | // challenge if HTTP Basic authentication is enabled. |
| | | sendUnauthorizedResponseWithHTTPBasicAuthChallenge(response); |
| | | clientConnection.disconnect(DisconnectReason.INVALID_CREDENTIALS, false, |
| | | null); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | clientConnection |
| | | .disconnect(DisconnectReason.SERVER_ERROR, false, message); |
| | | } |
| | | finally |
| | | { |
| | | clientConnections.remove(clientConnection); |
| | | } |
| | | } |
| | | |
| | | private boolean canProcessRequest(ServletRequest request, |
| | |
| | | // established). |
| | | if (clientConnection.getConnectionID() < 0) |
| | | { |
| | | // The connection will have already been closed. |
| | | clientConnection.disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, |
| | | ERR_CONNHANDLER_REJECTED_BY_SERVER.get()); |
| | | return false; |
| | | } |
| | | |
| | |
| | | |
| | | import static org.forgerock.opendj.adapter.server2x.Converters.*; |
| | | import static org.opends.messages.ProtocolMessages.*; |
| | | import static org.opends.server.loggers.AccessLogger.*; |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | |
| | | import java.net.InetAddress; |
| | |
| | | import org.opends.messages.Message; |
| | | import org.opends.messages.MessageBuilder; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.api.ConnectionHandler; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | |
| | | this.request = request; |
| | | |
| | | this.connectionID = DirectoryServer.newConnectionAccepted(this); |
| | | if (this.connectionID < 0) |
| | | { |
| | | disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, |
| | | ERR_CONNHANDLER_REJECTED_BY_SERVER.get()); |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConnectionHandler<?> getConnectionHandler() |
| | | public HTTPConnectionHandler getConnectionHandler() |
| | | { |
| | | return connectionHandler; |
| | | } |
| | |
| | | protected boolean sendIntermediateResponseMessage( |
| | | IntermediateResponse intermediateResponse) |
| | | { |
| | | // TODO Auto-generated method stub |
| | | return false; |
| | | throw new RuntimeException("Not implemented"); |
| | | } |
| | | |
| | | /** |
| | |
| | | .getClosureMessage())); |
| | | } |
| | | finalizeConnectionInternal(); |
| | | |
| | | |
| | | this.connectionHandler.removeClientConnection(this); |
| | | logDisconnect(this, disconnectReason, message); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | |
| | | op.operation.abort(cancelRequest); |
| | | } |
| | | catch (Exception e) |
| | | { // make sure all operations are cancelled, no mattter what |
| | | { // make sure all operations are cancelled, no matter what |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | |
| | | { |
| | | return connectionValid; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isInnerConnection() |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | |
| | | && !this.currentConfig.isAuthenticationRequired(); |
| | | } |
| | | |
| | | /** |
| | | * Registers a client connection to track it. |
| | | * |
| | | * @param clientConnection |
| | | * the client connection to register |
| | | */ |
| | | void addClientConnection(ClientConnection clientConnection) |
| | | { |
| | | clientConnections.put(clientConnection, clientConnection); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConfigChangeResult applyConfigurationChange( |
| | |
| | | return clientConnections.keySet(); |
| | | } |
| | | |
| | | /** |
| | | * Gives access to the clientConnections to classes in this package. |
| | | * |
| | | * @return the Map containing the current client connections |
| | | */ |
| | | Map<ClientConnection, ClientConnection> getClientConnectionsMap() |
| | | { |
| | | return clientConnections; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN getComponentEntryDN() |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Unregisters a client connection to stop tracking it. |
| | | * |
| | | * @param clientConnection |
| | | * the client connection to unregister |
| | | */ |
| | | void removeClientConnection(ClientConnection clientConnection) |
| | | { |
| | | clientConnections.remove(clientConnection); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void run() |
| | |
| | | import org.opends.server.core.UnbindOperationBasis; |
| | | import org.opends.server.core.WorkQueueStrategy; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.types.AuthenticationInfo; |
| | | import org.opends.server.types.ByteString; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.DisconnectReason; |
| | | import org.opends.server.types.Operation; |
| | | |
| | | import com.forgerock.opendj.util.AsynchronousFutureResult; |
| | |
| | | |
| | | try |
| | | { |
| | | operation.setInnerOperation(this.clientConnection.isInnerConnection()); |
| | | |
| | | // need this raw cast here to fool the compiler's generic type safety |
| | | // Problem here is due to the generic type R on enqueueOperation() |
| | | clientConnection.addOperationInProgress(operation, |
| | |
| | | @Override |
| | | public void close(UnbindRequest request, String reason) |
| | | { |
| | | final int messageID = nextMessageID.get(); |
| | | UnbindOperationBasis operation = |
| | | new UnbindOperationBasis(clientConnection, messageID, messageID, |
| | | to(request.getControls())); |
| | | AuthenticationInfo authInfo = this.clientConnection.getAuthenticationInfo(); |
| | | if (authInfo != null && authInfo.isAuthenticated()) |
| | | { |
| | | final int messageID = nextMessageID.get(); |
| | | UnbindOperationBasis operation = |
| | | new UnbindOperationBasis(clientConnection, messageID, messageID, |
| | | to(request.getControls())); |
| | | |
| | | // run synchronous |
| | | operation.run(); |
| | | |
| | | // run synchronous |
| | | operation.run(); |
| | | } |
| | | else |
| | | { |
| | | this.clientConnection.disconnect(DisconnectReason.UNBIND, false, null); |
| | | } |
| | | isClosed = true; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | connectionID = DirectoryServer.newConnectionAccepted(this); |
| | | if (connectionID < 0) |
| | | { |
| | | disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, |
| | | ERR_CONNHANDLER_REJECTED_BY_SERVER.get()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | clientChannel, getProtocol()); |
| | | if (clientConnection.getConnectionID() < 0) |
| | | { |
| | | // The connection will have already been closed. |
| | | clientConnection.disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, |
| | | ERR_CONNHANDLER_REJECTED_BY_SERVER.get()); |
| | | return; |
| | | } |
| | | |
| | |
| | | * itself rather than requested by an external client. |
| | | */ |
| | | private boolean isInternalOperation; |
| | | private Boolean isInnerOperation; |
| | | |
| | | /** |
| | | * Indicates whether this operation is involved in data synchronization |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this is an internal operation rather than one |
| | | * that was requested by an external client. |
| | | * |
| | | * @return {@code true} if this is an internal operation, or |
| | | * {@code false} if it is not. |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final boolean isInternalOperation() |
| | | { |
| | | return isInternalOperation; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether this is an internal operation rather than one |
| | | * that was requested by an external client. This may not be called |
| | | * from within a plugin. |
| | | * |
| | | * @param isInternalOperation Specifies whether this is an |
| | | * internal operation rather than one |
| | | * that was requested by an external |
| | | * client. |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final void setInternalOperation(boolean isInternalOperation) |
| | | { |
| | | this.isInternalOperation = isInternalOperation; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isInnerOperation() |
| | | { |
| | | if (this.isInnerOperation != null) |
| | | { |
| | | return this.isInnerOperation; |
| | | } |
| | | return isInternalOperation(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void setInnerOperation(boolean isInnerOperation) |
| | | { |
| | | this.isInnerOperation = isInnerOperation; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this is a synchronization operation rather than |
| | | * one that was requested by an external client. |
| | | * |
| | | * @return {@code true} if this is a data synchronization |
| | | * operation, or {@code false} if it is not. |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final boolean isSynchronizationOperation() |
| | | { |
| | | return isSynchronizationOperation; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether this is a synchronization operation rather than |
| | | * one that was requested by an external client. This method may |
| | | * not be called from within a plugin. |
| | | * |
| | | * @param isSynchronizationOperation Specifies whether this is a |
| | | * synchronization operation |
| | | * rather than one that was |
| | | * requested by an external |
| | | * client. |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final void setSynchronizationOperation( |
| | | boolean isSynchronizationOperation) |
| | |
| | | isInternalOperation); |
| | | |
| | | /** |
| | | * Indicates whether this is an inner operation rather than one that was |
| | | * directly requested by an external client. Said otherwise, inner operations |
| | | * include internal operations, but also operations in the server indirectly |
| | | * mandated by external requests like Rest2LDAP for example. This may not be |
| | | * called from within a plugin. |
| | | * |
| | | * @return {@code true} if this is an inner operation, or {@code false} if it |
| | | * is not. |
| | | */ |
| | | boolean isInnerOperation(); |
| | | |
| | | /** |
| | | * Specifies whether this is an inner operation rather than one that was |
| | | * directly requested by an external client. Said otherwise, inner operations |
| | | * include internal operations, but also operations in the server indirectly |
| | | * mandated by external requests like Rest2LDAP for example. This may not be |
| | | * called from within a plugin. |
| | | * |
| | | * @param isInnerOperation |
| | | * Specifies whether this is an inner operation rather than one that |
| | | * was requested by an external client. |
| | | */ |
| | | void setInnerOperation(boolean isInnerOperation); |
| | | |
| | | /** |
| | | * Indicates whether this is a synchronization operation rather than |
| | | * one that was requested by an external client. |
| | | * |
| | |
| | | @DataProvider(name = "isLoggableData") |
| | | public Object[][] getIsLoggableData() |
| | | { |
| | | // when suppress is set to true and the corresponding operation is set to |
| | | // true too, then the operation is not loggable. |
| | | // You can read the array like this: read two by two from line start, if |
| | | // both are true in a pair, then the expected result is false (not loggable) |
| | | return new Object[][] { |
| | | { 1L, false, false, false, false, true }, |
| | | { -1L, true, true, true, true, false }, |
| | | { -1L, true, true, true, false, false }, |
| | | { -1L, true, true, false, true, false }, |
| | | { -1L, true, true, false, false, false }, |
| | | { -1L, true, false, true, true, false }, |
| | | { -1L, true, false, true, false, false },// this will change |
| | | { -1L, true, false, false, true, true }, |
| | | { -1L, true, false, false, false, true }, |
| | | { -1L, false, true, true, true, true },// this will change |
| | | { -1L, false, true, true, false, true }, |
| | | { -1L, false, true, false, true, true }, |
| | | { -1L, false, true, false, false, true }, |
| | | { -1L, false, false, true, true, false }, |
| | | { -1L, false, false, true, false, false },// this will change |
| | | { -1L, false, false, false, true, true }, |
| | | { -1L, false, false, false, false, true }, }; |
| | | { true, true, true, true, false }, |
| | | { true, true, true, false, false }, |
| | | { true, true, false, true, false }, |
| | | { true, true, false, false, false }, |
| | | { true, false, true, true, false }, |
| | | { true, false, true, false, true }, |
| | | { true, false, false, true, true }, |
| | | { true, false, false, false, true }, |
| | | { false, true, true, true, false }, |
| | | { false, true, true, false, true }, |
| | | { false, true, false, true, true }, |
| | | { false, true, false, false, true }, |
| | | { false, false, true, true, false }, |
| | | { false, false, true, false, true }, |
| | | { false, false, false, true, true }, |
| | | { false, false, false, false, true }, }; |
| | | } |
| | | |
| | | @Test(dataProvider = "isLoggableData") |
| | | public void rootFilterIsLoggable(long connectionID, |
| | | boolean suppressSynchronization, boolean isSynchronizationOp, |
| | | boolean suppressInternal, boolean isInternalOp, boolean testResult) |
| | | public void rootFilterIsLoggable(boolean suppressSynchronization, |
| | | boolean isSynchronizationOp, boolean suppressInternal, |
| | | boolean isInternalOp, boolean expectedTestResult) |
| | | { |
| | | final Operation operation = mock(Operation.class); |
| | | when(operation.getConnectionID()).thenReturn(connectionID); |
| | | when(operation.isSynchronizationOperation()) |
| | | .thenReturn(isSynchronizationOp); |
| | | when(operation.isInternalOperation()).thenReturn(isInternalOp); |
| | | when(operation.isInnerOperation()).thenReturn(isInternalOp); |
| | | |
| | | final RootFilter filter = |
| | | new RootFilter(suppressInternal, suppressSynchronization, null, null); |
| | | assertEquals(filter.isLoggable(operation), testResult); |
| | | assertEquals(filter.isLoggable(operation), expectedTestResult); |
| | | } |
| | | |
| | | } |