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);
 }
Esempio n. 2
0
        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;
        }
Esempio n. 6
0
        /// <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);
        }