mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-07-30 17:30:40 +00:00
SessionHeaders
This commit is contained in:
@@ -193,7 +193,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_remoteDomain = value;
|
_remoteDomain = value;
|
||||||
_session.RemoteHeaders[EpAuthPacketHeader.Domain] = value;
|
_session.RemoteHeaders.Domain = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_localDomain = value;
|
_localDomain = value;
|
||||||
_session.LocalHeaders[EpAuthPacketHeader.Domain] = value;
|
_session.LocalHeaders.Domain = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -262,8 +262,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
{
|
{
|
||||||
base.Assign(socket);
|
base.Assign(socket);
|
||||||
|
|
||||||
_session.LocalHeaders[EpAuthPacketHeader.IPAddress]
|
_session.LocalHeaders.IPAddress = socket.RemoteEndPoint.Address.GetAddressBytes();
|
||||||
= socket.RemoteEndPoint.Address.GetAddressBytes();
|
|
||||||
|
|
||||||
if (socket.State == SocketState.Established &&
|
if (socket.State == SocketState.Established &&
|
||||||
_authDirection == AuthenticationDirection.Initiator)
|
_authDirection == AuthenticationDirection.Initiator)
|
||||||
@@ -277,8 +276,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
if (_authDirection != AuthenticationDirection.Initiator)
|
if (_authDirection != AuthenticationDirection.Initiator)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// change to Map<byte, object> for compatibility
|
var headers = _session.LocalHeaders.Copy();
|
||||||
var headers = _session.LocalHeaders.Select(x => new KeyValuePair<byte, object>((byte)x.Key, x.Value));
|
|
||||||
|
|
||||||
if (_session.AuthenticationMode != AuthenticationMode.None)
|
if (_session.AuthenticationMode != AuthenticationMode.None)
|
||||||
{
|
{
|
||||||
@@ -287,9 +285,9 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
|
|
||||||
var initAuthResult = _session.AuthenticationHandler.Process(null);
|
var initAuthResult = _session.AuthenticationHandler.Process(null);
|
||||||
|
|
||||||
headers.Add((byte)EpAuthPacketHeader.AuthenticationProtocol, _session.AuthenticationHandler.Protocol);
|
headers.AuthenticationProtocol = _session.AuthenticationHandler.Protocol;
|
||||||
headers.Add((byte)EpAuthPacketHeader.AuthenticationData, initAuthResult.AuthenticationData);
|
headers.AuthenticationData = initAuthResult.AuthenticationData;
|
||||||
headers.Add((byte)EpAuthPacketHeader.Domain, _remoteDomain);
|
headers.Domain = _remoteDomain;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,10 +306,9 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
/// Create a new distributed connection.
|
/// Create a new distributed connection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="socket">Socket to transfer data through.</param>
|
/// <param name="socket">Socket to transfer data through.</param>
|
||||||
/// <param name="domain">Working domain.</param>
|
/// <param name="authenticationHandler">Authentication handler for the session.</param>
|
||||||
/// <param name="username">Username.</param>
|
/// <param name="headers">Initial local session headers.</param>
|
||||||
/// <param name="password">Password.</param>
|
public EpConnection(ISocket socket, IAuthenticationHandler authenticationHandler, SessionHeaders headers)
|
||||||
public EpConnection(ISocket socket, IAuthenticationHandler authenticationHandler, Map<EpAuthPacketHeader, object> headers)
|
|
||||||
{
|
{
|
||||||
_session = new Session();
|
_session = new Session();
|
||||||
|
|
||||||
@@ -728,30 +725,18 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
if (_authPacket.Command == EpAuthPacketCommand.Initialize)
|
if (_authPacket.Command == EpAuthPacketCommand.Initialize)
|
||||||
{
|
{
|
||||||
|
|
||||||
var remoteHeaders = new Map<byte, object>();
|
var remoteHeaders = new SessionHeaders();
|
||||||
object remoteAuthData = null;
|
object remoteAuthData = null;
|
||||||
|
|
||||||
if (_authPacket.Tdu != null)
|
if (_authPacket.Tdu != null)
|
||||||
{
|
{
|
||||||
var parsed = Codec.ParseSync(_authPacket.Tdu.Value, null);
|
remoteHeaders = Codec.ParseIndexedType<SessionHeaders>(_authPacket.Tdu.Value, null);
|
||||||
|
remoteAuthData = remoteHeaders.AuthenticationData;
|
||||||
if (parsed is Map<byte, object> headers)
|
remoteHeaders.AuthenticationData = null;
|
||||||
{
|
|
||||||
remoteHeaders = headers;
|
|
||||||
|
|
||||||
foreach (var header in headers)
|
|
||||||
{
|
|
||||||
if (header.Key == (byte)EpAuthPacketHeader.AuthenticationData)
|
|
||||||
remoteAuthData = header.Value;
|
|
||||||
else
|
|
||||||
_session.RemoteHeaders.Add((EpAuthPacketHeader)header.Key, header.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var localHeaders = new Map<byte, object>();
|
_session.RemoteHeaders = remoteHeaders;
|
||||||
foreach (var header in _session.LocalHeaders)
|
var localHeaders = _session.LocalHeaders.Copy();
|
||||||
localHeaders.Add((byte)header.Key, header.Value);
|
|
||||||
|
|
||||||
if (_authPacket.AuthMode == AuthenticationMode.None)
|
if (_authPacket.AuthMode == AuthenticationMode.None)
|
||||||
{
|
{
|
||||||
@@ -773,7 +758,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_session.RemoteHeaders.ContainsKey(EpAuthPacketHeader.AuthenticationProtocol))
|
if (_session.RemoteHeaders.AuthenticationProtocol == null)
|
||||||
{
|
{
|
||||||
SendAuthHeaders(EpAuthPacketMethod.NotSupported, localHeaders);
|
SendAuthHeaders(EpAuthPacketMethod.NotSupported, localHeaders);
|
||||||
_invalidCredentials = true;
|
_invalidCredentials = true;
|
||||||
@@ -781,13 +766,13 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
var provider = _serverWarehouse.GetAuthenticationProvider(_session.RemoteHeaders[EpAuthPacketHeader.AuthenticationProtocol].ToString());
|
var provider = _serverWarehouse.GetAuthenticationProvider(_session.RemoteHeaders.AuthenticationProtocol);
|
||||||
|
|
||||||
var handler = provider.CreateAuthenticationHandler(new AuthenticationContext()
|
var handler = provider.CreateAuthenticationHandler(new AuthenticationContext()
|
||||||
{
|
{
|
||||||
Direction = AuthenticationDirection.Responder,
|
Direction = AuthenticationDirection.Responder,
|
||||||
Mode = _authPacket.AuthMode,
|
Mode = _authPacket.AuthMode,
|
||||||
Domain = _session.RemoteHeaders.ContainsKey(EpAuthPacketHeader.Domain) ? _session.RemoteHeaders[EpAuthPacketHeader.Domain].ToString() : null,
|
Domain = _session.RemoteHeaders.Domain,
|
||||||
Materials = new AuthenticationMaterial[] { new AuthenticationMaterial() { Type = AuthenticationMaterialType.Data, Value = remoteAuthData } }
|
Materials = new AuthenticationMaterial[] { new AuthenticationMaterial() { Type = AuthenticationMaterialType.Data, Value = remoteAuthData } }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -807,8 +792,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
|
|
||||||
// send acknowledgements
|
// send acknowledgements
|
||||||
|
|
||||||
localHeaders.Add((byte)EpAuthPacketHeader.AuthenticationData,
|
localHeaders.AuthenticationData = authResult.AuthenticationData;
|
||||||
authResult.AuthenticationData);
|
|
||||||
|
|
||||||
if (authResult.Ruling == AuthenticationRuling.Failed)
|
if (authResult.Ruling == AuthenticationRuling.Failed)
|
||||||
{
|
{
|
||||||
@@ -853,32 +837,20 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
if (_authPacket.Method == EpAuthPacketMethod.ProceedToHandshake
|
if (_authPacket.Method == EpAuthPacketMethod.ProceedToHandshake
|
||||||
|| _authPacket.Method == EpAuthPacketMethod.ProceedToFinalHandshake)
|
|| _authPacket.Method == EpAuthPacketMethod.ProceedToFinalHandshake)
|
||||||
{
|
{
|
||||||
var remoteHeaders
|
var remoteHeaders = new SessionHeaders();
|
||||||
= new Map<EpAuthPacketHeader, object>();
|
|
||||||
object remoteAuthData = null;
|
object remoteAuthData = null;
|
||||||
|
|
||||||
if (_authPacket.Tdu != null)
|
if (_authPacket.Tdu != null)
|
||||||
{
|
{
|
||||||
var parsed = Codec.ParseSync(_authPacket.Tdu.Value, Instance.Warehouse);
|
remoteHeaders = Codec.ParseIndexedType<SessionHeaders>(
|
||||||
|
_authPacket.Tdu.Value,
|
||||||
if (parsed is Map<byte, object> headers)
|
Instance.Warehouse);
|
||||||
{
|
remoteAuthData = remoteHeaders.AuthenticationData;
|
||||||
foreach (var header in headers)
|
remoteHeaders.AuthenticationData = null;
|
||||||
{
|
|
||||||
if (header.Key == (byte)EpAuthPacketHeader.AuthenticationData)
|
|
||||||
{
|
|
||||||
remoteAuthData = header.Value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
remoteHeaders.Add((EpAuthPacketHeader)header.Key, header.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_session.RemoteHeaders = remoteHeaders;// headers.Select(x => new KeyValuePair<EpAuthPacketHeader, object>((EpAuthPacketHeader)x.Key, x.Value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_session.RemoteHeaders = remoteHeaders;
|
||||||
|
|
||||||
if (_session.AuthenticationMode == AuthenticationMode.None)
|
if (_session.AuthenticationMode == AuthenticationMode.None)
|
||||||
{
|
{
|
||||||
if (_authPacket.Method == EpAuthPacketMethod.SessionEstablished)
|
if (_authPacket.Method == EpAuthPacketMethod.SessionEstablished)
|
||||||
@@ -1972,7 +1944,7 @@ public partial class EpConnection : NetworkConnection, IStore
|
|||||||
_authDirection = AuthenticationDirection.Initiator;
|
_authDirection = AuthenticationDirection.Initiator;
|
||||||
_invalidCredentials = false;
|
_invalidCredentials = false;
|
||||||
|
|
||||||
_session.LocalHeaders[EpAuthPacketHeader.Domain] = domain;
|
_session.LocalHeaders.Domain = domain;
|
||||||
_hostname = hostname;
|
_hostname = hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ partial class EpConnection
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SendAuthHeaders(EpAuthPacketMethod method,
|
void SendAuthHeaders(EpAuthPacketMethod method,
|
||||||
Map<byte, object> authHeaders)
|
SessionHeaders authHeaders)
|
||||||
{
|
{
|
||||||
if (authHeaders != null)
|
if (authHeaders != null)
|
||||||
{
|
{
|
||||||
@@ -388,9 +388,10 @@ partial class EpConnection
|
|||||||
|
|
||||||
var bl = new BinaryList();
|
var bl = new BinaryList();
|
||||||
bl.AddUInt8((byte)((byte)method | 0x20));
|
bl.AddUInt8((byte)((byte)method | 0x20));
|
||||||
bl.AddUInt8Array(Codec.Compose(authHeaders,
|
bl.AddUInt8Array(Codec.ComposeIndexedType(
|
||||||
this.Instance?.Warehouse ?? _serverWarehouse,
|
authHeaders,
|
||||||
this));
|
this.Instance?.Warehouse ?? _serverWarehouse,
|
||||||
|
this));
|
||||||
Send(bl.ToArray());
|
Send(bl.ToArray());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -34,6 +34,68 @@ using Esiur.Security.Cryptography;
|
|||||||
using Esiur.Net.Packets;
|
using Esiur.Net.Packets;
|
||||||
|
|
||||||
namespace Esiur.Security.Authority;
|
namespace Esiur.Security.Authority;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Authentication metadata exchanged while establishing a session.
|
||||||
|
/// Members retain the indexes defined by <see cref="EpAuthPacketHeader"/>, so this
|
||||||
|
/// structure has the same wire representation as the former header map.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SessionHeaders : IndexedStructure
|
||||||
|
{
|
||||||
|
[Index((int)EpAuthPacketHeader.Version)]
|
||||||
|
public object? Version { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.Domain)]
|
||||||
|
public string? Domain { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.SupportedAuthentications)]
|
||||||
|
public object? SupportedAuthentications { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.SupportedHashAlgorithms)]
|
||||||
|
public object? SupportedHashAlgorithms { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.SupportedCiphers)]
|
||||||
|
public object? SupportedCiphers { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.SupportedCompression)]
|
||||||
|
public object? SupportedCompression { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.SupportedMultiFactorAuthentications)]
|
||||||
|
public object? SupportedMultiFactorAuthentications { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.CipherType)]
|
||||||
|
public object? CipherType { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.CipherKey)]
|
||||||
|
public byte[]? CipherKey { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.SoftwareIdentity)]
|
||||||
|
public string? SoftwareIdentity { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.Referrer)]
|
||||||
|
public string? Referrer { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.Time)]
|
||||||
|
public DateTime? Time { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.IPAddress)]
|
||||||
|
public byte[]? IPAddress { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.Identity)]
|
||||||
|
public string? Identity { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.AuthenticationProtocol)]
|
||||||
|
public string? AuthenticationProtocol { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.AuthenticationData)]
|
||||||
|
public object? AuthenticationData { get; set; }
|
||||||
|
|
||||||
|
[Index((int)EpAuthPacketHeader.ErrorMessage)]
|
||||||
|
public string? ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
internal SessionHeaders Copy() => (SessionHeaders)MemberwiseClone();
|
||||||
|
}
|
||||||
|
|
||||||
public class Session
|
public class Session
|
||||||
{
|
{
|
||||||
public byte[] Id { get; set; }
|
public byte[] Id { get; set; }
|
||||||
@@ -47,8 +109,8 @@ public class Session
|
|||||||
public ISymetricCipher SymetricCipher { get; set; } = null;
|
public ISymetricCipher SymetricCipher { get; set; } = null;
|
||||||
|
|
||||||
|
|
||||||
public Map<EpAuthPacketHeader, object> LocalHeaders { get; set; } = new Map<EpAuthPacketHeader, object>();
|
public SessionHeaders LocalHeaders { get; set; } = new SessionHeaders();
|
||||||
public Map<EpAuthPacketHeader, object> RemoteHeaders { get; set; } = new Map<EpAuthPacketHeader, object>();
|
public SessionHeaders RemoteHeaders { get; set; } = new SessionHeaders();
|
||||||
|
|
||||||
//public AuthenticationMethod AuthenticationMethod { get; set; }
|
//public AuthenticationMethod AuthenticationMethod { get; set; }
|
||||||
//public AuthenticationMethod RemoteMethod { get; set; }
|
//public AuthenticationMethod RemoteMethod { get; set; }
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Esiur.Data;
|
using Esiur.Data;
|
||||||
|
using Esiur.Net.Packets;
|
||||||
using Esiur.Resource;
|
using Esiur.Resource;
|
||||||
|
using Esiur.Security.Authority;
|
||||||
|
|
||||||
namespace Esiur.Tests.Unit;
|
namespace Esiur.Tests.Unit;
|
||||||
|
|
||||||
@@ -81,6 +83,41 @@ public class IndexedStructureTests
|
|||||||
Assert.Contains("index 1", error.Message, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("index 1", error.Message, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SessionHeaders_RoundTripUsingAuthenticationHeaderIndexes()
|
||||||
|
{
|
||||||
|
var source = new SessionHeaders
|
||||||
|
{
|
||||||
|
Version = (byte)3,
|
||||||
|
Domain = "example.test",
|
||||||
|
IPAddress = new byte[] { 127, 0, 0, 1 },
|
||||||
|
AuthenticationProtocol = "hash",
|
||||||
|
AuthenticationData = new byte[] { 1, 2, 3 },
|
||||||
|
};
|
||||||
|
|
||||||
|
var bytes = Codec.ComposeIndexedType(source, Warehouse.Default, null);
|
||||||
|
var legacyBytes = Codec.Compose(new Map<byte, object>
|
||||||
|
{
|
||||||
|
[(byte)EpAuthPacketHeader.Version] = source.Version,
|
||||||
|
[(byte)EpAuthPacketHeader.Domain] = source.Domain,
|
||||||
|
[(byte)EpAuthPacketHeader.IPAddress] = source.IPAddress,
|
||||||
|
[(byte)EpAuthPacketHeader.AuthenticationProtocol] = source.AuthenticationProtocol,
|
||||||
|
[(byte)EpAuthPacketHeader.AuthenticationData] = source.AuthenticationData,
|
||||||
|
}, Warehouse.Default, null);
|
||||||
|
var (_, raw) = Codec.ParseSync(bytes, 0, Warehouse.Default);
|
||||||
|
var map = Assert.IsType<Map<byte, object>>(raw);
|
||||||
|
var (_, parsed) = Codec.ParseIndexedType<SessionHeaders>(bytes, 0, Warehouse.Default);
|
||||||
|
|
||||||
|
Assert.Equal(legacyBytes, bytes);
|
||||||
|
Assert.Equal("example.test", map[(byte)EpAuthPacketHeader.Domain]);
|
||||||
|
Assert.Equal("hash", map[(byte)EpAuthPacketHeader.AuthenticationProtocol]);
|
||||||
|
Assert.False(map.ContainsKey((byte)EpAuthPacketHeader.ErrorMessage));
|
||||||
|
Assert.Equal(source.Domain, parsed.Domain);
|
||||||
|
Assert.Equal(source.IPAddress, parsed.IPAddress);
|
||||||
|
Assert.Equal(source.AuthenticationProtocol, parsed.AuthenticationProtocol);
|
||||||
|
Assert.Equal(source.AuthenticationData, parsed.AuthenticationData);
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class InvalidStructure : IndexedStructure
|
private sealed class InvalidStructure : IndexedStructure
|
||||||
{
|
{
|
||||||
[Index(1)] public int First { get; set; }
|
[Index(1)] public int First { get; set; }
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
namespace Esiur.Tests.Unit.Integration;
|
||||||
|
|
||||||
|
[Collection("Integration")]
|
||||||
|
public class SessionHeadersIntegrationTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task AuthenticatedHandshake_StoresTypedHeadersWithoutAuthenticationData()
|
||||||
|
{
|
||||||
|
await using var cluster = await IntegrationCluster
|
||||||
|
.StartAsync(_ => Task.CompletedTask)
|
||||||
|
.WaitAsync(TimeSpan.FromSeconds(10));
|
||||||
|
|
||||||
|
var serverConnection = Assert.Single(cluster.Server.Connections);
|
||||||
|
|
||||||
|
Assert.NotNull(cluster.Connection.Session.LocalHeaders.IPAddress);
|
||||||
|
Assert.Null(cluster.Connection.Session.RemoteHeaders.AuthenticationData);
|
||||||
|
|
||||||
|
Assert.Equal("test", serverConnection.Session.RemoteHeaders.Domain);
|
||||||
|
Assert.Equal("hash", serverConnection.Session.RemoteHeaders.AuthenticationProtocol);
|
||||||
|
Assert.Null(serverConnection.Session.RemoteHeaders.AuthenticationData);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user