private ServerProcessing SendEmptyToClient(SecureTransaction transactType, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { responseMsg = null; responseStream = new MemoryStream(); responseHeaders = new TransportHeaders(); responseHeaders[CommonHeaders.Transaction] = ((int)transactType).ToString(); return(ServerProcessing.Complete); }
public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream) { AsyncProcessingState asyncState = (AsyncProcessingState)state; try { SecureTransaction transactType = (SecureTransaction)Convert.ToInt32((string)headers[CommonHeaders.Transaction]); switch (transactType) { case SecureTransaction.SendingEncryptedResult: { lock (_transactionLock) { if (asyncState.ID.Equals(_transactID)) { stream = DecryptResponse(stream, headers); } else { throw new SecureRemotingException("The key has changed since the message was decrypted."); } } break; } case SecureTransaction.UnknownIdentifier: { throw new SecureRemotingException("The server sink was unable to identify the client, most likely due to the connection information timing out."); } default: case SecureTransaction.Uninitialized: { break; } } } catch (SecureRemotingException) { lock (_transactionLock) { if (_provider == null || asyncState.ID.Equals(_transactID)) { ClearSharedKey(); } ProcessMessage(asyncState.Message, asyncState.Headers, asyncState.Stream, out headers, out stream); } } finally { asyncState.Stream.Close(); } sinkStack.AsyncProcessResponse(headers, stream); }
/// <summary>Requests message processing from the current sink.</summary> /// <param name="sinkStack">A stack of channel sinks</param> /// <param name="requestMsg">Request message.</param> /// <param name="requestHeaders">Headers sent by client.</param> /// <param name="requestStream">Stream to be processed..</param> /// <param name="responseMsg">Response message.</param> /// <param name="responseHeaders">Response headers.</param> /// <param name="responseStream">Response stream.</param> /// <returns>Status of the server message processing.</returns> public ServerProcessing ProcessMessage( IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Get header information about transaction string strTransactID = (string)requestHeaders[CommonHeaders.ID]; Guid transactID = (strTransactID == null ? Guid.Empty : new Guid(strTransactID)); SecureTransaction transactType = (SecureTransaction)Convert.ToInt32((string)requestHeaders[CommonHeaders.Transaction]); // For reference, find out who is connecting to us. We can use this to filter // and to enforce security based on client identity. IPAddress clientAddress = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress; // Set the IP address and port of our client CallContext.SetData("ClientIP", clientAddress); // Push this onto the sink stack sinkStack.Push(this, null); // Process the transaction based on its type (as stored in the CommonHeaders.Transaction header field) ServerProcessing processingResult; switch (transactType) { case SecureTransaction.SendingPublicKey: // We've received a request from a new client asking for a shared key (by sending us // his RSA public key). Create a shared key, encrypt it, and send it back to him. processingResult = MakeSharedKey(transactID, requestHeaders, out responseMsg, out responseHeaders, out responseStream); System.Diagnostics.Debug.WriteLine("Connection added: " + transactID); break; case SecureTransaction.SendingEncryptedMessage: // We've received an encrypted message. Decrypt it and send it along to the next sink. // But first make sure we have a record of the transaction. if (PreviousTransactionWithClient(transactID)) { processingResult = ProcessEncryptedMessage( transactID, sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); } // Otherwise, let the client know that we don't recognize him. else { processingResult = SendEmptyToClient( SecureTransaction.UnknownIdentifier, out responseMsg, out responseHeaders, out responseStream); System.Diagnostics.Debug.WriteLine("Unknown connection: " + transactID); } break; case SecureTransaction.Uninitialized: // The transaction type did not match any known type, or wasn't specified. // So just pass on the message to the next sink. This shouldn't happen // unless the client isn't using the SecureClientSink provider, in which // case this is the correct behavior. if (!RequireSecurity(clientAddress)) { processingResult = _next.ProcessMessage( sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); } // If the server has elected not to allow plaintext traffic, let the // client know that we're not happy. else { throw new SecureRemotingException("Server requires a secure connection for this client"); } break; default: // Houston, we have a problem! throw new SecureRemotingException("Invalid request from client: " + transactType + "."); } // Take us off the stack and return the result. sinkStack.Pop(this); return(processingResult); }
public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { responseHeaders = null; string strTransactID = (string)requestHeaders[CommonHeaders.ID]; Guid transactID = (strTransactID == null ? Guid.Empty : new Guid(strTransactID)); SecureTransaction transactType = (SecureTransaction)Convert.ToInt32((string)requestHeaders[CommonHeaders.Transaction]); IPAddress clientAddress = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress; sinkStack.Push(this, null); ServerProcessing processingResult; switch (transactType) { case SecureTransaction.SendingPublicKey: { processingResult = MakeSharedKey(transactID, requestHeaders, out responseMsg, out responseHeaders, out responseStream); System.Diagnostics.Debug.WriteLine("Connection added: " + transactID); break; } case SecureTransaction.SendingEncryptedMessage: { ClientConnectionInfo cci = (ClientConnectionInfo)_connections[transactID.ToString()]; string customerID = requestHeaders[CommonHeaders.CustomerID].ToString(); string password = requestHeaders[CommonHeaders.Password].ToString(); string extensionNumber = requestHeaders[CommonHeaders.ExtensionNumber].ToString(); if (PreviousTransactionWithClient(transactID)) { if (RequireSecurity == true) { Authenticate(cci, customerID, extensionNumber, password); } processingResult = ProcessEncryptedMessage(transactID, sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); if (clientAddress != null && cci != null) { CheckForManagementAllowed(cci, clientAddress.ToString(), extensionNumber); } } else { processingResult = SendEmptyToClient(SecureTransaction.UnknownIdentifier, out responseMsg, out responseHeaders, out responseStream); } break; } case SecureTransaction.Uninitialized: { if (!RequireSecurity) { processingResult = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); } else { throw new SecureRemotingException("Server requires a secure connection for this client"); } break; } default: { // Houston, we have a problem! throw new SecureRemotingException("Invalid request from client: " + transactType + "."); } } sinkStack.Pop(this); return(processingResult); }
/// <summary> /// Creates all necessary objects to send an empty message back to the client. /// Can be used to send back to the client an "Unknown Identifier" transaction type message. /// Note that this is a recoverable error and as such does not throw an exception. /// </summary> /// <param name="transactType">The transaction type to send to the client.</param> /// <param name="responseMsg">The output response message.</param> /// <param name="responseHeaders">The output response headers.</param> /// <param name="responseStream">The output response stream.</param> /// <returns>Status of the server message processing (Complete).</returns> private ServerProcessing SendEmptyToClient( SecureTransaction transactType, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Initialize all output objects and set the transaction type. responseMsg = null; responseStream = new MemoryStream(); responseHeaders = new TransportHeaders(); responseHeaders[CommonHeaders.Transaction] = ((int)transactType).ToString(); return ServerProcessing.Complete; }
/// <summary>Requests asynchronous processing of a response to a method call on the current sink.</summary> /// <param name="sinkStack">A stack of sinks that called this sink.</param> /// <param name="state">Information generated on the request side that is associated with this sink.</param> /// <param name="headers">The headers retrieved from the server response stream.</param> /// <param name="stream">The stream coming back from the transport sink.</param> public void AsyncProcessResponse( IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream) { // Get the async state we put on the stack AsyncProcessingState asyncState = (AsyncProcessingState)state; try { // Decrypt the response if possible SecureTransaction transactType = (SecureTransaction)Convert.ToInt32((string)headers[CommonHeaders.Transaction]); switch (transactType) { // The only valid value; the server is sending results encrypted, // so we need to decrypt them case SecureTransaction.SendingEncryptedResult: lock (_transactionLock) { if (asyncState.ID.Equals(_transactID)) { stream = DecryptResponse(stream, headers); } else { throw new SecureRemotingException("The key has changed since the message was decrypted."); } } break; // The server has no record of the client, so error out. // If this were synchronous, we could try again, first renewing // the connection information. The best we can do here is null // out our current connection information so that the next time // through we'll create a new provider and identifier. case SecureTransaction.UnknownIdentifier: throw new SecureRemotingException( "The server sink was unable to identify the client, " + "most likely due to the connection information timing out."); // Something happened and the response is not encrypted, i.e. there // are no transport headers, or at least no transaction header, or it has // been explicitly set by the server to Uninitialized. // Regardless, do nothing. default: case SecureTransaction.Uninitialized: break; } } catch (SecureRemotingException) { // We got back a secure remoting exceptionIt would be difficult to retry this as an // asynchronous call as we need to have the output ready to go before // we return. Thus, we'll make a synchronous one by calling ProcessMessage() // just as if we were the previous sink. Luckily, we kept all of the // necessary information sitting around. lock (_transactionLock) // This is a big, big lock, as are many locks in this app! Oh well. { if (_provider == null || asyncState.ID.Equals(_transactID)) { ClearSharedKey(); } ProcessMessage( asyncState.Message, asyncState.Headers, asyncState.Stream, out headers, out stream); } } finally { // Close the old stream just in case it hasn't been closed yet. asyncState.Stream.Close(); } // Process through the rest of the sinks. sinkStack.AsyncProcessResponse(headers, stream); }