From 12cbd0de9dc2af4aa11484a59dd4fbdf71dd932a Mon Sep 17 00:00:00 2001 From: yallie Date: Sun, 8 Dec 2024 15:59:54 +0300 Subject: [PATCH 1/3] Broken authentication provider shouldn't crash remoting server. --- CoreRemoting.Tests/RpcTests.cs | 54 +++++++++++++-- CoreRemoting/Channels/Tcp/TcpClientChannel.cs | 15 ++-- CoreRemoting/Channels/Tcp/TcpServerChannel.cs | 16 ++--- .../Websocket/WebsocketClientChannel.cs | 11 +-- CoreRemoting/RemotingClient.cs | 2 +- CoreRemoting/RemotingServer.cs | 68 +++++++++++-------- 6 files changed, 111 insertions(+), 55 deletions(-) diff --git a/CoreRemoting.Tests/RpcTests.cs b/CoreRemoting.Tests/RpcTests.cs index f59f136..ea6551a 100644 --- a/CoreRemoting.Tests/RpcTests.cs +++ b/CoreRemoting.Tests/RpcTests.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Diagnostics; +using System.Security; using System.Threading; using System.Threading.Tasks; using CoreRemoting.Authentication; @@ -326,6 +327,7 @@ public void Generic_methods_should_be_called_correctly() var result = proxy.Echo("Yay"); Assert.Equal("Yay", result); + Assert.Equal(0, _serverFixture.ServerErrorCount); } [Fact] @@ -345,6 +347,7 @@ public void Inherited_methods_should_be_called_correctly() var result = proxy.BaseMethod(); Assert.True(result); + Assert.Equal(0, _serverFixture.ServerErrorCount); } [Fact] @@ -366,6 +369,7 @@ public void Enum_arguments_should_be_passed_correctly() Assert.Equal(TestEnum.First, resultFirst); Assert.Equal(TestEnum.Second, resultSecond); + Assert.Equal(0, _serverFixture.ServerErrorCount); } [Fact] @@ -402,6 +406,7 @@ public void Missing_method_throws_RemoteInvocationException() // a localized message similar to "Method 'Missing method' not found" Assert.NotNull(ex); Assert.Contains("Missing Method", ex.Message); + Assert.Equal(0, _serverFixture.ServerErrorCount); } [Fact] @@ -425,6 +430,7 @@ public void Missing_service_throws_RemoteInvocationException() // a localized message similar to "Service 'System.IDisposable' is not registered" Assert.NotNull(ex); Assert.Contains("IDisposable", ex.Message); + Assert.Equal(0, _serverFixture.ServerErrorCount); } [Fact] @@ -596,6 +602,9 @@ async Task Roundtrip(bool encryption) finally { _serverFixture.Server.Config.MessageEncryption = oldEncryption; + + // reset the error counter for other tests + _serverFixture.ServerErrorCount = 0; } } @@ -852,7 +861,7 @@ void RejectCall(object sender, ServerRpcContext e) => client.Connect(); var proxy = client.CreateProxy(); - var ex = Assert.Throws(() => proxy.Hello()); + var ex = Assert.Throws(proxy.Hello); // Session is not authenticated Assert.Contains("authenticated", ex.Message); @@ -888,7 +897,7 @@ public void Authentication_handler_has_access_to_the_current_session() Channel = ClientChannel, MessageEncryption = false, ServerPort = _serverFixture.Server.Config.NetworkPort, - Credentials = [new Credential()], + Credentials = [new()], }); client.Connect(); @@ -903,6 +912,43 @@ public void Authentication_handler_has_access_to_the_current_session() } } + [Fact] + public void Broken_auhentication_handler_doesnt_break_the_server() + { + var server = _serverFixture.Server; + var authProvider = server.Config.AuthenticationProvider; + server.Config.AuthenticationRequired = true; + server.Config.AuthenticationProvider = new FakeAuthProvider + { + AuthenticateFake = c => throw new Exception("Broken") + }; + + try + { + using var client = new RemotingClient(new ClientConfig() + { + ConnectionTimeout = 3, + InvocationTimeout = 3, + SendTimeout = 3, + Channel = ClientChannel, + MessageEncryption = false, + ServerPort = _serverFixture.Server.Config.NetworkPort, + Credentials = [new()], + }); + + var ex = Assert.Throws(client.Connect); + + Assert.Contains("auth", ex.Message.ToLower()); + Assert.Contains("failed", ex.Message); + } + finally + { + server.Config.AuthenticationProvider = authProvider; + server.Config.AuthenticationRequired = false; + _serverFixture.ServerErrorCount = 0; + } + } + [Fact] public void Authentication_handler_can_check_client_address() { @@ -913,8 +959,8 @@ public void Authentication_handler_can_check_client_address() { AuthenticateFake = c => { - var address = RemotingSession.Current.ClientAddress ?? - throw new ArgumentNullException(); + var address = RemotingSession.Current?.ClientAddress ?? + throw new ArgumentNullException("ClientAddress"); // allow only localhost connections return address.Contains("127.0.0.1") || // ipv4 diff --git a/CoreRemoting/Channels/Tcp/TcpClientChannel.cs b/CoreRemoting/Channels/Tcp/TcpClientChannel.cs index a544890..04e6bfe 100644 --- a/CoreRemoting/Channels/Tcp/TcpClientChannel.cs +++ b/CoreRemoting/Channels/Tcp/TcpClientChannel.cs @@ -16,7 +16,7 @@ public class TcpClientChannel : IClientChannel, IRawMessageTransport /// Event: Fires when a message is received from server. /// public event Action ReceiveMessage; - + /// /// Event: Fires when an error is occurred. /// @@ -34,7 +34,7 @@ public void Init(IRemotingClient client) _tcpClient = new WatsonTcpClient(client.Config.ServerHostName, client.Config.ServerPort); _tcpClient.Settings.NoDelay = true; - _handshakeMetadata = + _handshakeMetadata = new Dictionary { { "MessageEncryption", client.MessageEncryption } @@ -51,7 +51,7 @@ public void Connect() { if (_tcpClient == null) throw new InvalidOperationException("Channel is not initialized."); - + if (_tcpClient.Connected) return; @@ -60,6 +60,7 @@ public void Connect() _tcpClient.Events.ServerDisconnected += OnDisconnected; _tcpClient.Connect(); } + private void OnDisconnected(object o, DisconnectionEventArgs disconnectionEventArgs) { Disconnected?.Invoke(); @@ -73,7 +74,7 @@ private void OnDisconnected(object o, DisconnectionEventArgs disconnectionEventA private void OnError(object sender, ExceptionEventArgs e) { LastException = new NetworkException(e.Exception.Message, e.Exception); - + ErrorOccured?.Invoke(e.Exception.Message, e.Exception); } @@ -131,7 +132,7 @@ public void Disconnect() /// Gets the raw message transport component for this connection. /// public IRawMessageTransport RawMessageTransport => this; - + /// /// Sends a message to the server. /// @@ -149,12 +150,12 @@ public bool SendMessage(byte[] rawMessage) else throw new NetworkException("Channel disconnected"); } - + /// /// Gets or sets the last exception. /// public NetworkException LastException { get; set; } - + /// /// Disconnect and free manages resources. /// diff --git a/CoreRemoting/Channels/Tcp/TcpServerChannel.cs b/CoreRemoting/Channels/Tcp/TcpServerChannel.cs index 3c37560..16be41e 100644 --- a/CoreRemoting/Channels/Tcp/TcpServerChannel.cs +++ b/CoreRemoting/Channels/Tcp/TcpServerChannel.cs @@ -21,7 +21,7 @@ public TcpServerChannel() { _connections = new ConcurrentDictionary(); } - + /// /// Initializes the channel. /// @@ -45,11 +45,11 @@ private void OnClientConnected(object sender, ConnectionEventArgs e) { { "ServerAcceptConnection", true } }; - + _tcpServer.SendAsync(e.Client.Guid, new byte[]{ 0x02 }, metadata); } } - + private void OnClientDisconnected(object sender, DisconnectionEventArgs e) { _connections.TryRemove(e.Client.Guid, out _); @@ -59,7 +59,7 @@ private void OnTcpMessageReceived(object sender, MessageReceivedEventArgs e) { if (_connections.TryGetValue(e.Client.Guid, out TcpConnection connection)) { - connection.FireReceiveMessage(e.Data, e.Metadata); + connection.FireReceiveMessage(e.Data, e.Metadata); } } @@ -70,7 +70,7 @@ public void StartListening() { if (_tcpServer == null) throw new InvalidOperationException("Channel is not initialized."); - + _tcpServer.Start(); } @@ -81,16 +81,16 @@ public void StopListening() { if (_tcpServer == null) return; - + _tcpServer.Stop(); } /// /// Gets whether the channel is listening or not. /// - public bool IsListening => + public bool IsListening => _tcpServer?.IsListening ?? false; - + /// /// Stops listening and frees managed resources. /// diff --git a/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs b/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs index b182053..01de49f 100644 --- a/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs +++ b/CoreRemoting/Channels/Websocket/WebsocketClientChannel.cs @@ -102,20 +102,21 @@ private async Task StartListening() { var buffer = new byte[BufferSize]; var segment = new ArraySegment(buffer); + var webSocket = WebSocket; try { - while (WebSocket.State == WebSocketState.Open) + while (webSocket.State == WebSocketState.Open) { var ms = new SmallBlockMemoryStream(); while (true) { - var result = await WebSocket.ReceiveAsync(segment, + var result = await webSocket.ReceiveAsync(segment, CancellationToken.None).ConfigureAwait(false); if (result.MessageType == WebSocketMessageType.Close) { - await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false); Disconnected?.Invoke(); @@ -135,7 +136,7 @@ await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, var message = new byte[(int)ms.Length]; ms.Position = 0; ms.Read(message, 0, message.Length); - ReceiveMessage(message); + ReceiveMessage?.Invoke(message); } } } @@ -149,7 +150,7 @@ await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, } finally { - WebSocket?.Dispose(); + webSocket?.Dispose(); } } diff --git a/CoreRemoting/RemotingClient.cs b/CoreRemoting/RemotingClient.cs index 808462f..0b786f8 100644 --- a/CoreRemoting/RemotingClient.cs +++ b/CoreRemoting/RemotingClient.cs @@ -90,7 +90,7 @@ public RemotingClient(ClientConfig config) : this() _keyPair = new RsaKeyPair(config.KeySize); _channel = config.Channel ?? new TcpClientChannel(); - + _channel.Init(this); _channel.Disconnected += OnDisconnected; _rawMessageTransport = _channel.RawMessageTransport; diff --git a/CoreRemoting/RemotingServer.cs b/CoreRemoting/RemotingServer.cs index cf45688..8c103e0 100644 --- a/CoreRemoting/RemotingServer.cs +++ b/CoreRemoting/RemotingServer.cs @@ -23,13 +23,13 @@ public sealed class RemotingServer : IRemotingServer private readonly IDependencyInjectionContainer _container; private readonly ServerConfig _config; private readonly string _uniqueServerInstanceName; - + // ReSharper disable once InconsistentNaming - private static readonly ConcurrentDictionary _serverInstances = + private static readonly ConcurrentDictionary _serverInstances = new ConcurrentDictionary(); private static WeakReference _defaultRemotingServerRef; - + /// /// Creates a new instance of the RemotingServer class. /// @@ -38,11 +38,11 @@ public RemotingServer(ServerConfig config = null) { _config = config ?? new ServerConfig(); - _uniqueServerInstanceName = - string.IsNullOrWhiteSpace(_config.UniqueServerInstanceName) - ? Guid.NewGuid().ToString() + _uniqueServerInstanceName = + string.IsNullOrWhiteSpace(_config.UniqueServerInstanceName) + ? Guid.NewGuid().ToString() : _config.UniqueServerInstanceName; - + _serverInstances.AddOrUpdate( key: _config.UniqueServerInstanceName, addValueFactory: _ => this, @@ -51,38 +51,38 @@ public RemotingServer(ServerConfig config = null) oldServer?.Dispose(); return this; }); - - SessionRepository = - _config.SessionRepository ?? - new SessionRepository( + + SessionRepository = + _config.SessionRepository ?? + new SessionRepository( keySize: _config.KeySize, inactiveSessionSweepInterval: _config.InactiveSessionSweepInterval, maximumSessionInactivityTime: _config.MaximumSessionInactivityTime); - + _container = _config.DependencyInjectionContainer ?? new CastleWindsorDependencyInjectionContainer(); Serializer = _config.Serializer ?? new BsonSerializerAdapter(); MethodCallMessageBuilder = new MethodCallMessageBuilder(); MessageEncryptionManager = new MessageEncryptionManager(); - + _container.RegisterService( lifetime: ServiceLifetime.Singleton, asHiddenSystemService: true); - + _config.RegisterServicesAction?.Invoke(_container); Channel = _config.Channel ?? new TcpServerChannel(); - + Channel.Init(this); - + if (_config.IsDefault) RemotingServer.DefaultRemotingServer ??= this; } - + /// /// Event: Fires before an RPC call is invoked. /// public event EventHandler BeforeCall; - + /// /// Event: Fires after an RPC call is invoked. /// @@ -117,7 +117,7 @@ public RemotingServer(ServerConfig config = null) /// Gets the configuration settings. /// public ServerConfig Config => _config; - + /// /// Gets the configured serializer. /// @@ -132,7 +132,7 @@ public RemotingServer(ServerConfig config = null) /// Gets the component for encryption and decryption of messages. /// public IMessageEncryptionManager MessageEncryptionManager { get; } - + /// /// Gets the session repository to perform session management tasks. /// @@ -224,13 +224,21 @@ public void Stop() /// True when authentication was successful, otherwise false public bool Authenticate(Credential[] credentials, out RemotingIdentity authenticatedIdentity) { + authenticatedIdentity = null; + if (_config.AuthenticationProvider == null) - { - authenticatedIdentity = null; return false; + + try + { + return _config.AuthenticationProvider.Authenticate(credentials, out authenticatedIdentity); } + catch (Exception ex) + { + OnError(ex); - return _config.AuthenticationProvider.Authenticate(credentials, out authenticatedIdentity); + return false; + } } /// @@ -240,16 +248,16 @@ public void Dispose() { if (RemotingServer.DefaultRemotingServer == this) RemotingServer.DefaultRemotingServer = null; - + _serverInstances.TryRemove(_config.UniqueServerInstanceName, out _); - + if (Channel != null) { Channel.Dispose(); Channel = null; } } - + #region Managing server instances /// @@ -285,13 +293,13 @@ public static IRemotingServer DefaultRemotingServer } internal set { - _defaultRemotingServerRef = - value == null - ? null + _defaultRemotingServerRef = + value == null + ? null : new WeakReference(value); } } - + #endregion } } \ No newline at end of file From c3a9f8698e584b959c91bb6f2999db7d89358298 Mon Sep 17 00:00:00 2001 From: yallie Date: Sun, 8 Dec 2024 17:55:30 +0300 Subject: [PATCH 2/3] Added RemotingServer Logon and Logoff events. --- CoreRemoting.Tests/RpcTests.cs | 67 ++++++++++++++++++++ CoreRemoting.Tests/Tools/FakeAuthProvider.cs | 4 +- CoreRemoting/IRemotingServer.cs | 10 +++ CoreRemoting/RemotingServer.cs | 42 +++++++++--- CoreRemoting/RemotingSession.cs | 5 +- 5 files changed, 117 insertions(+), 11 deletions(-) diff --git a/CoreRemoting.Tests/RpcTests.cs b/CoreRemoting.Tests/RpcTests.cs index ea6551a..9912675 100644 --- a/CoreRemoting.Tests/RpcTests.cs +++ b/CoreRemoting.Tests/RpcTests.cs @@ -1013,5 +1013,72 @@ public void ServerComponent_can_track_client_network_address() // what's my address as seen by remote server? Assert.NotNull(proxy.ClientAddress); } + + [Fact] + public void Logon_and_logoff_events_are_triggered() + { + void CheckSession(string operation) + { + var rs = RemotingSession.Current; + Assert.NotNull(rs); + Assert.True(rs?.IsAuthenticated); + Assert.NotNull(rs?.ClientAddress); + Assert.NotNull(rs?.Identity); + Console.WriteLine($"Client {rs.Identity.Name} from {rs.ClientAddress} is {operation}"); + } + + var logon = false; + void Logon(object sender, EventArgs _) + { + logon = true; + CheckSession("logged on"); + } + + var logoff = false; + void Logoff(object sender, EventArgs _) + { + logoff = true; + CheckSession("logged off"); + } + + var server = _serverFixture.Server; + var authProvider = server.Config.AuthenticationProvider; + server.Config.AuthenticationProvider = new FakeAuthProvider(); + + server.Logon += Logon; + server.Logoff += Logoff; + server.Config.AuthenticationRequired = true; + + try + { + using var client = new RemotingClient(new ClientConfig() + { + ConnectionTimeout = 0, + InvocationTimeout = 0, + SendTimeout = 0, + Channel = ClientChannel, + MessageEncryption = false, + Credentials = [new()], + ServerPort = _serverFixture.Server.Config.NetworkPort, + }); + + client.Connect(); + + var proxy = client.CreateProxy(); + Assert.Equal("Hello", proxy.Echo("Hello")); + + client.Disconnect(); + + Assert.True(logon); + Assert.True(logoff); + } + finally + { + server.Config.AuthenticationProvider = authProvider; + server.Config.AuthenticationRequired = false; + server.Logoff -= Logoff; + server.Logon -= Logon; + } + } } } \ No newline at end of file diff --git a/CoreRemoting.Tests/Tools/FakeAuthProvider.cs b/CoreRemoting.Tests/Tools/FakeAuthProvider.cs index 29912ea..2495bee 100644 --- a/CoreRemoting.Tests/Tools/FakeAuthProvider.cs +++ b/CoreRemoting.Tests/Tools/FakeAuthProvider.cs @@ -9,7 +9,7 @@ public class FakeAuthProvider : IAuthenticationProvider public bool Authenticate(Credential[] credentials, out RemotingIdentity authenticatedIdentity) { - var success = AuthenticateFake(credentials); + var success = AuthenticateFake?.Invoke(credentials) ?? true; authenticatedIdentity = new RemotingIdentity() @@ -18,7 +18,7 @@ public bool Authenticate(Credential[] credentials, out RemotingIdentity authenti Domain = "domain", IsAuthenticated = success, Name = credentials[0].Value, - Roles = new[] {"Test"} + Roles = ["Test"], }; return success; diff --git a/CoreRemoting/IRemotingServer.cs b/CoreRemoting/IRemotingServer.cs index 074ea9d..9c2d5ff 100644 --- a/CoreRemoting/IRemotingServer.cs +++ b/CoreRemoting/IRemotingServer.cs @@ -36,6 +36,16 @@ public interface IRemotingServer : IDisposable /// event EventHandler Error; + /// + /// Event: Fires when a client logs on. + /// + event EventHandler Logon; + + /// + /// Event: Fires when a client logs off. + /// + event EventHandler Logoff; + /// /// Gets the unique name of this server instance. /// diff --git a/CoreRemoting/RemotingServer.cs b/CoreRemoting/RemotingServer.cs index 8c103e0..2dab19f 100644 --- a/CoreRemoting/RemotingServer.cs +++ b/CoreRemoting/RemotingServer.cs @@ -79,19 +79,19 @@ public RemotingServer(ServerConfig config = null) } /// - /// Event: Fires before an RPC call is invoked. + /// Event: Fires when a client logs on. /// - public event EventHandler BeforeCall; + public event EventHandler Logon; /// - /// Event: Fires after an RPC call is invoked. + /// Event: Fires when a client logs off. /// - public event EventHandler AfterCall; + public event EventHandler Logoff; /// - /// Event: Fires if an error occurs. + /// Event: Fires when an RPC call is prepared and can be canceled. /// - public event EventHandler Error; + public event EventHandler BeginCall; /// /// Event: Fires when an RPC call is rejected before BeforeCall event. @@ -99,9 +99,19 @@ public RemotingServer(ServerConfig config = null) public event EventHandler RejectCall; /// - /// Event: Fires when an RPC call is prepared and can be canceled. + /// Event: Fires before an RPC call is invoked. /// - public event EventHandler BeginCall; + public event EventHandler BeforeCall; + + /// + /// Event: Fires after an RPC call is invoked. + /// + public event EventHandler AfterCall; + + /// + /// Event: Fires if an error occurs. + /// + public event EventHandler Error; /// /// Gets the dependency injection container that is used a service registry. @@ -200,6 +210,22 @@ internal void OnBeginCall(ServerRpcContext serverRpcContext) } } + /// + /// Fires the event. + /// + internal void OnLogon() + { + Logon?.Invoke(this, EventArgs.Empty); + } + + /// + /// Fires the event. + /// + internal void OnLogoff() + { + Logoff?.Invoke(this, EventArgs.Empty); + } + /// /// Starts listening for client requests. /// diff --git a/CoreRemoting/RemotingSession.cs b/CoreRemoting/RemotingSession.cs index cc5eff8..28099eb 100644 --- a/CoreRemoting/RemotingSession.cs +++ b/CoreRemoting/RemotingSession.cs @@ -13,7 +13,6 @@ using CoreRemoting.Encryption; using CoreRemoting.Serialization; using Serialize.Linq.Nodes; -using CoreRemoting.Toolbox; namespace CoreRemoting { @@ -337,6 +336,8 @@ private void ProcessGoodbyeMessage(WireMessage request) _rawMessageTransport.SendMessage(_server.Serializer.Serialize(resultMessage)); + ((RemotingServer)_server).OnLogoff(); + Task.Run(() => _server.SessionRepository.RemoveSession(_sessionId)); } @@ -390,6 +391,8 @@ private void ProcessAuthenticationRequestMessage(WireMessage request) _rawMessageTransport.SendMessage( _server.Serializer.Serialize(wireMessage)); + + ((RemotingServer)_server).OnLogon(); } /// From 3fffb86a5ee2e1d56eeb875c8a16681d0c516769 Mon Sep 17 00:00:00 2001 From: yallie Date: Sun, 8 Dec 2024 18:43:13 +0300 Subject: [PATCH 3/3] BeginCall event can bypass authentication for chosen methods. --- CoreRemoting.Tests/RpcTests.cs | 38 ++++++++++++++++++++++++++++++++ CoreRemoting/RemotingSession.cs | 7 +++--- CoreRemoting/ServerRpcContext.cs | 5 +++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/CoreRemoting.Tests/RpcTests.cs b/CoreRemoting.Tests/RpcTests.cs index 9912675..8893746 100644 --- a/CoreRemoting.Tests/RpcTests.cs +++ b/CoreRemoting.Tests/RpcTests.cs @@ -1080,5 +1080,43 @@ void Logoff(object sender, EventArgs _) server.Logon -= Logon; } } + + [Fact] + public void BeginCall_event_handler_can_bypass_authentication_for_chosen_method() + { + void BypassAuthorizationForEcho(object sender, ServerRpcContext e) => + e.AuthenticationRequired = + e.MethodCallMessage.MethodName != "Echo"; + + _serverFixture.Server.Config.AuthenticationRequired = true; + _serverFixture.Server.BeginCall += BypassAuthorizationForEcho; + try + { + using var client = new RemotingClient(new ClientConfig() + { + ConnectionTimeout = 0, + InvocationTimeout = 0, + SendTimeout = 0, + Channel = ClientChannel, + MessageEncryption = false, + ServerPort = _serverFixture.Server.Config.NetworkPort, + }); + + client.Connect(); + + // try allowed method "Echo" + var proxy = client.CreateProxy(); + Assert.Equal("This method is allowed", proxy.Echo("This method is allowed")); + + // try disallowed method "Reverse" + var ex = Assert.Throws(() => proxy.Reverse("This method is not allowed")); + Assert.Contains("auth", ex.Message); + } + finally + { + _serverFixture.Server.BeginCall -= BypassAuthorizationForEcho; + _serverFixture.Server.Config.AuthenticationRequired = false; + } + } } } \ No newline at end of file diff --git a/CoreRemoting/RemotingSession.cs b/CoreRemoting/RemotingSession.cs index 28099eb..58b90fe 100644 --- a/CoreRemoting/RemotingSession.cs +++ b/CoreRemoting/RemotingSession.cs @@ -427,6 +427,7 @@ private void ProcessRpcMessage(WireMessage request) request.UniqueCallKey == null ? Guid.Empty : new Guid(request.UniqueCallKey), + AuthenticationRequired = _server.Config.AuthenticationRequired, ServiceInstance = null, MethodCallMessage = callMessage, MethodCallParameterValues = [], @@ -440,9 +441,6 @@ private void ProcessRpcMessage(WireMessage request) try { - if (_server.Config.AuthenticationRequired && !_isAuthenticated) - throw new NetworkException("Session is not authenticated."); - CallContext.RestoreFromSnapshot(callMessage.CallContextSnapshot); callMessage.UnwrapParametersFromDeserializedMethodCallMessage( @@ -455,6 +453,9 @@ private void ProcessRpcMessage(WireMessage request) ((RemotingServer)_server).OnBeginCall(serverRpcContext); + if (serverRpcContext.AuthenticationRequired && !_isAuthenticated) + throw new NetworkException("Session is not authenticated."); + var service = _server.ServiceRegistry.GetService(callMessage.ServiceName); var serviceInterfaceType = _server.ServiceRegistry.GetServiceInterfaceType(callMessage.ServiceName); diff --git a/CoreRemoting/ServerRpcContext.cs b/CoreRemoting/ServerRpcContext.cs index 04b1d4e..28aad66 100644 --- a/CoreRemoting/ServerRpcContext.cs +++ b/CoreRemoting/ServerRpcContext.cs @@ -19,6 +19,11 @@ public class ServerRpcContext /// public Exception Exception { get; set; } + /// + /// Gets or sets a value whether the authentication is required. + /// + public bool AuthenticationRequired { get; set; } + /// /// Gets or sets a value whether the call is canceled by event handler. ///