/// <summary> /// Requests message processing from the current sink. /// </summary> /// <param name="sinkStack">A stack of channel sinks that called the current sink.</param> /// <param name="requestMsg">The message that contains the request.</param> /// <param name="requestHeaders">Headers retrieved from the incoming message from the client.</param> /// <param name="requestStream">The stream that needs to be to processed and passed on to the deserialization sink.</param> /// <param name="responseMsg">When this method returns, contains a <see cref="T:System.Runtime.Remoting.Messaging.IMessage" /> that holds the response message. This parameter is passed uninitialized.</param> /// <param name="responseHeaders">When this method returns, contains a <see cref="T:System.Runtime.Remoting.Channels.ITransportHeaders" /> that holds the headers that are to be added to return message heading to the client. This parameter is passed uninitialized.</param> /// <param name="responseStream">When this method returns, contains a <see cref="T:System.IO.Stream" /> that is heading back to the transport sink. This parameter is passed uninitialized.</param> public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Read secure transaction identifier from request headers string strTransactID = (string)requestHeaders[CommonHeaderNames.SECURE_TRANSACTION_ID]; Guid transactID = (strTransactID == null ? Guid.Empty : new Guid(strTransactID)); // Read current transaction step and client IP address from request headers SecureTransactionStage transactionStage = (SecureTransactionStage)Convert.ToInt32((string)requestHeaders[CommonHeaderNames.SECURE_TRANSACTION_STATE]); IPAddress clientAddress = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress; // Put current channel sink to the sink stack so AsyncProcessResponse can be called asynchronously if necessary order sinkStack.Push(this, null); ServerProcessing processingResult; try { switch (transactionStage) { case SecureTransactionStage.SendingPublicKey: // Client sends the public key to the server // Generate shared key and encrypt with the public key of the client processingResult = MakeSharedKey(transactID, requestHeaders, out responseMsg, out responseHeaders, out responseStream); break; case SecureTransactionStage.SendingEncryptedMessage: // Client sends the encrypted request message to the server if (IsExistingSecurityTransaction(transactID)) processingResult = ProcessEncryptedMessage(transactID, sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); else throw new CryptoRemotingException(string.Format(LanguageResource.CryptoRemotingException_InvalidClientRequest, SecureTransactionStage.UnknownTransactionID)); break; case SecureTransactionStage.Uninitialized: // Uninitialized, nothing has happened // Check if encryption is not required for this client address if (!RequireEncryption(clientAddress)) processingResult = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); else throw new CryptoRemotingException(LanguageResource.CryptoRemotingException_ServerRequiresEncryption); break; default: throw new CryptoRemotingException(string.Format(LanguageResource.CryptoRemotingException_InvalidClientRequest, transactionStage)); } } catch (CryptoRemotingException) { processingResult = SendEmptyToClient(sinkStack, requestMsg, requestHeaders, requestStream, transactionStage, out responseMsg, out responseHeaders, out responseStream); requestMsg = null; } // Pop the current sink from the sink stack sinkStack.Pop(this); return processingResult; }
/// <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) { // Gets the asynchronous processing state AsyncProcessingState asyncState = (AsyncProcessingState)state; try { SecureTransactionStage currentStage = (SecureTransactionStage)Convert.ToInt32((string)headers[CommonHeaderNames.SECURE_TRANSACTION_STATE]); switch (currentStage) { case SecureTransactionStage.SendingEncryptedResult: // Get the encrypted response from the server lock (_lockObject) { if (asyncState.SecureTransactionID.Equals(_secureTransactionID)) { stream = DecryptResponse(stream, headers); } else { throw new CryptoRemotingException(LanguageResource.CryptoRemotingException_KeyChanged); } } break; case SecureTransactionStage.UnknownTransactionID: // Bad transaction identifier throw new CryptoRemotingException(LanguageResource.CryptoRemotingException_InvalidTransactionID); default: case SecureTransactionStage.Uninitialized: // Secure transaction is not yet set up break; } } catch (CryptoRemotingException) { lock (_lockObject) { // If remote transaction identifier matches the local secure transaction identifier, reset the shared key if (_provider == null || asyncState.SecureTransactionID.Equals(_secureTransactionID)) { ClearSharedKey(); } ProcessMessage(asyncState.Message, asyncState.Headers, asyncState.Stream, out headers, out stream); } } finally { // Close the input stream asyncState.Stream.Close(); } // Pass on to the next sink to continue processing sinkStack.AsyncProcessResponse(headers, stream); }
/// <summary> /// Erzeugt eine leere Antwortnachricht. /// </summary> /// <param name="transactionStage">Art des aktuellen Transaktionsschritts</param> /// <param name="responseMsg">Antwort-Nachricht</param> /// <param name="responseHeaders">Antwort-Header</param> /// <param name="responseStream">Antwort-Datenstrom</param> /// <returns>Verarbeitungsstatus</returns> private ServerProcessing SendEmptyToClient(SecureTransactionStage transactionStage, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Inizialisieren responseMsg = null; responseStream = new MemoryStream(); responseHeaders = new TransportHeaders(); // Aktuellen Transaktionsschritt als Antwort-Header schreiben responseHeaders[CommonHeaderNames.SECURE_TRANSACTION_STATE] = ((int)transactionStage).ToString(); // Volständige Verarbeitung zurückmelden return(ServerProcessing.Complete); }
/// <summary> /// Creates an empty response message. /// </summary> /// <param name="sinkStack">The sink stack.</param> /// <param name="requestMsg">Request message.</param> /// <param name="requestHeaders">Request transport headers.</param> /// <param name="requestStream">Request stream.</param> /// <param name="transactionStage">Current secure transaction stage.</param> /// <param name="responseMsg">Response message.</param> /// <param name="responseHeaders">Response transport headers.</param> /// <param name="responseStream">Response stream.</param> /// <returns></returns> private ServerProcessing SendEmptyToClient(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, SecureTransactionStage transactionStage, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { responseMsg = null; requestStream = new MemoryStream(); responseStream = new MemoryStream(); responseHeaders = new TransportHeaders(); responseHeaders[CommonHeaderNames.SECURE_TRANSACTION_STATE] = ((int)transactionStage).ToString(); ServerProcessing processingResult = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); return(processingResult); }
/// <summary> /// Erzeugt eine leere Antwortnachricht. /// </summary> /// <param name="transactionStage">Art des aktuellen Transaktionsschritts</param> /// <param name="responseMsg">Antwort-Nachricht</param> /// <param name="responseHeaders">Antwort-Header</param> /// <param name="responseStream">Antwort-Datenstrom</param> /// <returns>Verarbeitungsstatus</returns> private ServerProcessing SendEmptyToClient(SecureTransactionStage transactionStage, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Inizialisieren responseMsg = null; responseStream = new MemoryStream(); responseHeaders = new TransportHeaders(); // Aktuellen Transaktionsschritt als Antwort-Header schreiben responseHeaders[CommonHeaderNames.SECURE_TRANSACTION_STATE] = ((int)transactionStage).ToString(); // Volständige Verarbeitung zurückmelden return ServerProcessing.Complete; }
/// <summary> /// Verarbeitet eine Antwort-Nachricht asynchron. /// </summary> /// <param name="sinkStack">Senkenstapel</param> /// <param name="state">Asynchroner Verarbeitungsstatus</param> /// <param name="headers">Anfrage-Header-Auflistung</param> /// <param name="stream">Anfrage-Datenstrom</param> public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream) { // Asychronen Verarbeitungsstatus abrufen AsyncProcessingState asyncState = (AsyncProcessingState)state; try { // Aktuellen Verarbeitungsschritt der Sicherheitstransaktion ermitteln SecureTransactionStage currentStage = (SecureTransactionStage)Convert.ToInt32((string)headers[CommonHeaderNames.SECURE_TRANSACTION_STATE]); // Verarbeitungsschritt auswerten switch (currentStage) { case SecureTransactionStage.SendingEncryptedResult: // Verschlüsselte Daten vom Server eingtroffen lock (_lockObject) { // Wenn die Antwort auch tatsächlich zur aktuellen Sicherheitstransaktion gehört ... if (asyncState.SecureTransactionID.Equals(_secureTransactionID)) { // Datenstrom entschlüsseln stream = DecryptResponse(stream, headers); } // Andernfalls ... else { // Ausnahme werfen throw new CryptoRemotingException(LanguageResource.CryptoRemotingException_KeyChanged); } } break; case SecureTransactionStage.UnknownTransactionID: // Unbekannte Transaktionskennung // Ausnahme werfen throw new CryptoRemotingException(LanguageResource.CryptoRemotingException_InvalidTransactionID); default: case SecureTransactionStage.Uninitialized: // Keine Sicherheitstransaktion eingerichtet break; } } catch (CryptoRemotingException) { lock (_lockObject) { // Wenn die gesendete Transaktionskennung mit der lokalen übereinstimmt ... if (_provider == null || asyncState.SecureTransactionID.Equals(_secureTransactionID)) { // Gemeinamen Schlüssel löschen ClearSharedKey(); } // Nachricht weiterverarbeiten ProcessMessage(asyncState.Message, asyncState.Headers, asyncState.Stream, out headers, out stream); } } finally { // Datenstrom schließen asyncState.Stream.Close(); } // Verarbeitung in der nächsten Kanalsenke fortsetzen sinkStack.AsyncProcessResponse(headers, stream); }
/// <summary> /// Creates an empty response message. /// </summary> /// <param name="sinkStack">The sink stack.</param> /// <param name="requestMsg">Request message.</param> /// <param name="requestHeaders">Request transport headers.</param> /// <param name="requestStream">Request stream.</param> /// <param name="transactionStage">Current secure transaction stage.</param> /// <param name="responseMsg">Response message.</param> /// <param name="responseHeaders">Response transport headers.</param> /// <param name="responseStream">Response stream.</param> /// <returns></returns> private ServerProcessing SendEmptyToClient(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, SecureTransactionStage transactionStage, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { responseMsg = null; requestStream = new MemoryStream(); responseStream = new MemoryStream(); responseHeaders = new TransportHeaders(); responseHeaders[CommonHeaderNames.SECURE_TRANSACTION_STATE] = ((int)transactionStage).ToString(); ServerProcessing processingResult = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); return processingResult; }
/// <summary> /// Verarbeitet eine einzele Clientanfrage /// </summary> /// <param name="sinkStack">Aufrufstapel der Kanalsenken</param> /// <param name="requestMsg">Anfrage-nachricht</param> /// <param name="requestHeaders">Anfrage-Header</param> /// <param name="requestStream">Anfrage-Datenstrom</param> /// <param name="responseMsg">Antwort-Nachricht</param> /// <param name="responseHeaders">Antwort-Header</param> /// <param name="responseStream">Antwort-Datenstrom</param> /// <returns>Status serverseitigen Verarbeitung der Nachricht insgesamt</returns> public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream) { // Sicherheitstransaktionskennung aus Anfrage-Header lesen string strTransactID = (string)requestHeaders[CommonHeaderNames.SECURE_TRANSACTION_ID]; // In Guid umwandeln Guid transactID = (strTransactID == null ? Guid.Empty : new Guid(strTransactID)); // Aktuellen Transaktionsschritt aus Anfrage-Header lesen SecureTransactionStage transactionStage = (SecureTransactionStage)Convert.ToInt32((string)requestHeaders[CommonHeaderNames.SECURE_TRANSACTION_STATE]); // IP-Adresse des Clients aus Anfrage-Header lesen IPAddress clientAddress = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress; // Aktuelle Kanalsenke auf den Senkenstapel legen, damit AsyncProcessResponse später ggf. asynchron aufgerufen werden kann sinkStack.Push(this, null); // Variable für Verarbeitungsstatus ServerProcessing processingResult; // Aktuellen Transaktionsschritt auswerten switch (transactionStage) { case SecureTransactionStage.SendingPublicKey: // Client sendet den öffentlichen Schlüssel an den Server // Gemeinsamen Schlüssel erzeugen und mit dem öffentlichen Schlüssel des Clients verschlüsseln processingResult = MakeSharedKey(transactID, requestHeaders, out responseMsg, out responseHeaders, out responseStream); break; case SecureTransactionStage.SendingEncryptedMessage: // Client sendet die verschlüsselte Anfragenachricht an den Server // Wenn die Sicherheitstransaktionskennung des Clients bekannt ist ... if (IsExistingSecurityTransaction(transactID)) { // Verschlüsselte Nachricht verarbeiten processingResult = ProcessEncryptedMessage(transactID, sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); } else { // Leere Nachricht an den Client senden und Transaktionsschritt auf "Unbekannte Sicherheitstransaktionskennung". setzen. processingResult = SendEmptyToClient(SecureTransactionStage.UnknownTransactionID, out responseMsg, out responseHeaders, out responseStream); } break; case SecureTransactionStage.Uninitialized: // Uninizialisiert, noch nichts geschehen // Wenn für diesen Client Verschlüsselung nicht zwingend notwendig ist ... if (!RequireEncryption(clientAddress)) { // Nachricht gleich an die nächste Senke zur Weiterverarbeitung übergeben processingResult = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream); } else { // Ausnahme werfen throw new CryptoRemotingException(LanguageResource.CryptoRemotingException_ServerRequiresEncryption); } break; default: // Ausnahme werfen throw new CryptoRemotingException(string.Format(LanguageResource.CryptoRemotingException_InvalidClientRequest, transactionStage)); } // Aktuelle Senke wieder vom Senkenstapel runternehmen sinkStack.Pop(this); // Veratbeitungsstatus zurückgeben return(processingResult); }