diff --git a/Libraries/Esiur/Core/AsyncException.cs b/Libraries/Esiur/Core/AsyncException.cs index c165bb7..e051a92 100644 --- a/Libraries/Esiur/Core/AsyncException.cs +++ b/Libraries/Esiur/Core/AsyncException.cs @@ -32,6 +32,7 @@ public class AsyncException : Exception { public readonly ErrorType Type; public readonly ExceptionCode Code; + //public readonly string Message; public AsyncException(Exception exception) : base(exception.Message, exception) { @@ -42,7 +43,8 @@ public class AsyncException : Exception public override string StackTrace => InnerException != null && Type == ErrorType.Exception ? InnerException.StackTrace : base.StackTrace; public AsyncException(ErrorType type, ushort code, string message) - : base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message) + //: base(type == ErrorType.Management ? ((ExceptionCode)code).ToString() : message) + : base(message) { this.Type = type; this.Code = (ExceptionCode)code; diff --git a/Libraries/Esiur/Net/Packets/EpAuthPacket.cs b/Libraries/Esiur/Net/Packets/EpAuthPacket.cs index c96df23..78c0f36 100644 --- a/Libraries/Esiur/Net/Packets/EpAuthPacket.cs +++ b/Libraries/Esiur/Net/Packets/EpAuthPacket.cs @@ -99,11 +99,11 @@ public class EpAuthPacket : Packet set; } - public string Message - { - get; - set; - } + //public string Message + //{ + // get; + // set; + //} public byte[] SessionId { diff --git a/Libraries/Esiur/Protocol/EpConnection.cs b/Libraries/Esiur/Protocol/EpConnection.cs index 7790156..62d1616 100644 --- a/Libraries/Esiur/Protocol/EpConnection.cs +++ b/Libraries/Esiur/Protocol/EpConnection.cs @@ -714,6 +714,14 @@ public partial class EpConnection : NetworkConnection, IStore if (_authPacket.AuthMode == AuthenticationMode.None) { + if (!(Server?.AllowUnauthorizedAccess ?? false)) + { + SendAuth(EpAuthPacketMethod.ErrorTerminate); + _invalidCredentials = true; + //Close(); + return offset; + } + //@TODO: check if allowed, pass for testing SendAuthHeaders(EpAuthPacketMethod.SessionEstablished, localHeaders); AuthenticatonCompleted(null, "guest"); @@ -772,7 +780,6 @@ public partial class EpConnection : NetworkConnection, IStore SendAuthHeaders(EpAuthPacketMethod.SessionEstablished, localHeaders); AuthenticatonCompleted(authResult.LocalIdentity, authResult.RemoteIdentity); } - } else if (_authPacket.Command == EpAuthPacketCommand.Acknowledge) { @@ -897,7 +904,9 @@ public partial class EpConnection : NetworkConnection, IStore || _authPacket.Method == EpAuthPacketMethod.ErrorRetry) { _invalidCredentials = true; - OnError?.Invoke(this, _authPacket.ErrorCode, _authPacket.Message ?? "Authentication error."); + OnError?.Invoke(this, _authPacket.ErrorCode, "Authentication error."); + _openReply?.TriggerError(new AsyncException(ErrorType.Management, _authPacket.ErrorCode, "Authentication error.")); + Close(); } else if (_authPacket.Method == EpAuthPacketMethod.IndicationEstablished) diff --git a/Libraries/Esiur/Protocol/EpServer.cs b/Libraries/Esiur/Protocol/EpServer.cs index 9fe12de..11c82c0 100644 --- a/Libraries/Esiur/Protocol/EpServer.cs +++ b/Libraries/Esiur/Protocol/EpServer.cs @@ -53,6 +53,12 @@ public class EpServer : NetworkServer, IResource set; } + [Attribute] + public string[] AllowedAuthenticationProviders { get; set; } + + [Attribute] + public bool AllowUnauthorizedAccess { get; set; } + //IMembership membership; //[Attribute] diff --git a/Libraries/Esiur/Security/Authority/Providers/PasswordAuthenticationProvider.cs b/Libraries/Esiur/Security/Authority/Providers/PasswordAuthenticationProvider.cs index c510514..f0a76ea 100644 --- a/Libraries/Esiur/Security/Authority/Providers/PasswordAuthenticationProvider.cs +++ b/Libraries/Esiur/Security/Authority/Providers/PasswordAuthenticationProvider.cs @@ -5,7 +5,7 @@ using System.Text; namespace Esiur.Security.Authority.Providers { - internal class PasswordAuthenticationProvider : IAuthenticationProvider + public class PasswordAuthenticationProvider : IAuthenticationProvider { public string DefaultName => "hash"; @@ -37,14 +37,14 @@ namespace Esiur.Security.Authority.Providers return null; } - public AsyncReply Login(Session session) + public virtual AsyncReply Login(Session session) { - throw new NotImplementedException(); + return new AsyncReply(false); } - public AsyncReply Logout(Session session) + public virtual AsyncReply Logout(Session session) { - throw new NotImplementedException(); + return new AsyncReply(false); } } } diff --git a/Tests/Features/Functional/ClientAuthenticationProvider.cs b/Tests/Features/Functional/ClientAuthenticationProvider.cs new file mode 100644 index 0000000..4ed9638 --- /dev/null +++ b/Tests/Features/Functional/ClientAuthenticationProvider.cs @@ -0,0 +1,44 @@ +using Esiur.Core; +using Esiur.Security.Authority; +using Esiur.Security.Authority.Providers; +using System; +using System.Collections.Generic; +using System.Security.Principal; +using System.Text; + +namespace Esiur.Tests.Functional +{ + internal class ClientAuthenticationProvider : PasswordAuthenticationProvider + { + public override (byte[], byte[]) GetHostedAccountCredential(string identity, string domain) + { + throw new NotImplementedException(); + } + + public override byte[] GetSelfCredential(string identity, string domain, string hostname) + { + if (identity == "tester" && domain == "test" && hostname == "localhost") + return new byte[] { 1, 2, 3, 4, 5 }; + else + return null; + } + + public override (string, byte[]) GetSelfIdentityAndCredential(string domain, string hostname) + { + if (domain == "test" && hostname == "localhost") + return ("tester", new byte[] { 1, 2, 3, 4, 5 }); + else + return (null, null); + } + + public override AsyncReply Login(Session session) + { + return base.Login(session); + } + + public override AsyncReply Logout(Session session) + { + return base.Logout(session); + } + } +} diff --git a/Tests/Features/Functional/Program.cs b/Tests/Features/Functional/Program.cs index b3ec87d..6ed32d0 100644 --- a/Tests/Features/Functional/Program.cs +++ b/Tests/Features/Functional/Program.cs @@ -49,6 +49,7 @@ using Esiur.Security.Membership; using Esiur.Net.Packets; using System.Numerics; using Esiur.Protocol; +using Esiur.Security.Authority.Providers; namespace Esiur.Tests.Functional; @@ -142,12 +143,12 @@ class Program //}); var wh = new Warehouse(); - + wh.RegisterAuthenticationProvider(new ServerAuthenticationProvider()); + // Create stores to keep objects. var system = await wh.Put("sys", new MemoryStore()); - var server = await wh.Put("sys/server", new EpServer() { - - // Membership = membership + var server = await wh.Put("sys/server", new EpServer() { + AllowedAuthenticationProviders = new string[] { "hash" }, }); @@ -213,13 +214,14 @@ class Program private static async void TestClient(IResource local) { + var wh = new Warehouse(); + var auth = new ClientAuthenticationProvider(); + wh.RegisterAuthenticationProvider(auth); var con = await new Warehouse().Get("EP://localhost", new EpConnectionContext { AutoReconnect = true, - //Username = "admin", - //Password = "admin", - Identity = "demo", + Identity = "tester", AuthenticationProtocol = "hash" }); diff --git a/Tests/Features/Functional/ServerAuthenticationProvider.cs b/Tests/Features/Functional/ServerAuthenticationProvider.cs new file mode 100644 index 0000000..1852feb --- /dev/null +++ b/Tests/Features/Functional/ServerAuthenticationProvider.cs @@ -0,0 +1,40 @@ +using Esiur.Core; +using Esiur.Security.Authority; +using Esiur.Security.Authority.Providers; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Tests.Functional +{ + internal class ServerAuthenticationProvider: PasswordAuthenticationProvider + { + public override (byte[], byte[]) GetHostedAccountCredential(string identity, string domain) + { + if (identity == "tester" && domain == "test") + return (new byte[] { 1, 2, 3, 4, 5 }, new byte[] { 6, 7, 8, 9, 10 }); + else + return (null, null); + } + + public override byte[] GetSelfCredential(string identity, string domain, string hostname) + { + return base.GetSelfCredential(identity, domain, hostname); + } + + public override (string, byte[]) GetSelfIdentityAndCredential(string domain, string hostname) + { + return base.GetSelfIdentityAndCredential(domain, hostname); + } + + public override AsyncReply Login(Session session) + { + return base.Login(session); + } + + public override AsyncReply Logout(Session session) + { + return base.Logout(session); + } + } +}