mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-04-20 18:36:31 +02:00
Merge branch 'fix/machinepagestability' into 'main'
API v0.3 See merge request fabinfra/fabaccess/borepin!45
This commit is contained in:
commit
beb295db4e
@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
# MA0003: Add argument name to improve readability
|
# MA0003: Add argument name to improve readability
|
||||||
dotnet_diagnostic.MA0003.severity = none
|
dotnet_diagnostic.MA0003.severity = none
|
||||||
|
csharp_style_prefer_switch_expression=false:suggestion
|
||||||
|
@ -31,6 +31,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
.gitlab-ci.yml = .gitlab-ci.yml
|
.gitlab-ci.yml = .gitlab-ci.yml
|
||||||
|
.gitmodules = .gitmodules
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
|
@ -30,7 +30,7 @@ namespace Borepin.Model
|
|||||||
Manager = new UserVisualize(_Machine.Manager);
|
Manager = new UserVisualize(_Machine.Manager);
|
||||||
Manager.LoadData();
|
Manager.LoadData();
|
||||||
|
|
||||||
MachineInfoExtended machineInfoExtended = (await _Machine.Info.GetMachineInfoExtended().ConfigureAwait(false)).Item1;
|
MachineInfoExtended machineInfoExtended = await _Machine.Manage.GetMachineInfoExtended().ConfigureAwait(false);
|
||||||
if(machineInfoExtended != null)
|
if(machineInfoExtended != null)
|
||||||
{
|
{
|
||||||
if (machineInfoExtended.CurrentUser == null || machineInfoExtended.CurrentUser.Username == null)
|
if (machineInfoExtended.CurrentUser == null || machineInfoExtended.CurrentUser.Username == null)
|
||||||
@ -43,13 +43,13 @@ namespace Borepin.Model
|
|||||||
CurrentUser.LoadData();
|
CurrentUser.LoadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (machineInfoExtended.TransferUser == null || machineInfoExtended.TransferUser.Username == null)
|
if (machineInfoExtended.LastUser == null || machineInfoExtended.LastUser.Username == null)
|
||||||
{
|
{
|
||||||
LastUser = null;
|
LastUser = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LastUser = new UserVisualize(machineInfoExtended.TransferUser);
|
LastUser = new UserVisualize(machineInfoExtended.LastUser);
|
||||||
LastUser.LoadData();
|
LastUser.LoadData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ namespace Borepin.Model
|
|||||||
|
|
||||||
CanUse = !((UseInterface_Proxy)_Machine.Use).IsNull;
|
CanUse = !((UseInterface_Proxy)_Machine.Use).IsNull;
|
||||||
CanInUse = !((InUseInterface_Proxy) _Machine.Inuse).IsNull;
|
CanInUse = !((InUseInterface_Proxy) _Machine.Inuse).IsNull;
|
||||||
CanTransfer = !((TransferInterface_Proxy) _Machine.Transfer).IsNull;
|
CanTakeOver = !((TakeoverInterface_Proxy) _Machine.Takeover).IsNull;
|
||||||
CanCheck = !((CheckInterface_Proxy) _Machine.Check).IsNull;
|
CanCheck = !((CheckInterface_Proxy) _Machine.Check).IsNull;
|
||||||
CanManage = !((ManageInterface_Proxy) _Machine.Manage).IsNull;
|
CanManage = !((ManageInterface_Proxy) _Machine.Manage).IsNull;
|
||||||
CanAdmin = !((AdminInterface_Proxy) _Machine.Admin).IsNull;
|
CanAdmin = !((AdminInterface_Proxy) _Machine.Admin).IsNull;
|
||||||
@ -140,7 +140,7 @@ namespace Borepin.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool _CanTransfer;
|
private bool _CanTransfer;
|
||||||
public bool CanTransfer
|
public bool CanTakeOver
|
||||||
{
|
{
|
||||||
get => _CanTransfer;
|
get => _CanTransfer;
|
||||||
set => SetProperty(ref _CanTransfer, value);
|
set => SetProperty(ref _CanTransfer, value);
|
||||||
|
@ -49,10 +49,10 @@ namespace Borepin.PageModel
|
|||||||
|
|
||||||
IsConnected = true;
|
IsConnected = true;
|
||||||
|
|
||||||
IMachineSystem machineSystem = await _BFFHService.GetMachineSystemInterface().ConfigureAwait(false);
|
IMachineSystem machineSystem = (await _BFFHService.GetSession().ConfigureAwait(false)).MachineSystem;
|
||||||
MachineSystem.IInfoInterface machine_infoInterface = await machineSystem.Info().ConfigureAwait(false);
|
MachineSystem.IInfoInterface machine_infoInterface = await machineSystem.Info().ConfigureAwait(false);
|
||||||
|
|
||||||
IUserSystem userSystem = await _BFFHService.GetUserSystemInterface().ConfigureAwait(false);
|
IUserSystem userSystem = (await _BFFHService.GetSession().ConfigureAwait(false)).UserSystem;
|
||||||
UserSystem.IInfoInterface user_infoInterface = await userSystem.Info().ConfigureAwait(false);
|
UserSystem.IInfoInterface user_infoInterface = await userSystem.Info().ConfigureAwait(false);
|
||||||
User user_self = (await user_infoInterface.GetUserSelf().ConfigureAwait(false)).Item1;
|
User user_self = (await user_infoInterface.GetUserSelf().ConfigureAwait(false)).Item1;
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ namespace Borepin.PageModel
|
|||||||
{
|
{
|
||||||
MachineListItemViewModel new_viewmodel = new MachineListItemViewModel(machine)
|
MachineListItemViewModel new_viewmodel = new MachineListItemViewModel(machine)
|
||||||
{
|
{
|
||||||
IsUserAssigned = true
|
IsUserAssigned = true,
|
||||||
};
|
};
|
||||||
viewmodel_list_user_assigned.Add(new_viewmodel);
|
viewmodel_list_user_assigned.Add(new_viewmodel);
|
||||||
}
|
}
|
||||||
@ -156,10 +156,10 @@ namespace Borepin.PageModel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMachineSystem machineInterface = await _BFFHService.GetMachineSystemInterface().ConfigureAwait(false);
|
IMachineSystem machineInterface = (await _BFFHService.GetSession().ConfigureAwait(false)).MachineSystem;
|
||||||
MachineSystem.IInfoInterface infoInterface = await machineInterface.Info().ConfigureAwait(false);
|
MachineSystem.IInfoInterface infoInterface = await machineInterface.Info().ConfigureAwait(false);
|
||||||
|
|
||||||
Machine machine = (await infoInterface.GetMachineURN(result.Parameters.GetValue<string>("value")).ConfigureAwait(false)).Item1;
|
Machine machine = await infoInterface.GetMachineURN(result.Parameters.GetValue<string>("value")).ConfigureAwait(false);
|
||||||
|
|
||||||
if(machine == null)
|
if(machine == null)
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,7 @@ namespace Borepin.PageModel
|
|||||||
IMachineSystem machineSystem;
|
IMachineSystem machineSystem;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
machineSystem = await _BFFHService.GetMachineSystemInterface().ConfigureAwait(false);
|
machineSystem = (await _BFFHService.GetSession().ConfigureAwait(false)).MachineSystem;
|
||||||
}
|
}
|
||||||
catch(ReconnectingFailedException)
|
catch(ReconnectingFailedException)
|
||||||
{
|
{
|
||||||
@ -54,7 +54,7 @@ namespace Borepin.PageModel
|
|||||||
|
|
||||||
IInfoInterface info = await machineSystem.Info().ConfigureAwait(false);
|
IInfoInterface info = await machineSystem.Info().ConfigureAwait(false);
|
||||||
|
|
||||||
_Machine = (await info.GetMachine(_ID).ConfigureAwait(false)).Item1;
|
_Machine = await info.GetMachine(_ID).ConfigureAwait(false);
|
||||||
MachineItem = new MachineVisualize(_Machine);
|
MachineItem = new MachineVisualize(_Machine);
|
||||||
MachineItem.LoadData();
|
MachineItem.LoadData();
|
||||||
|
|
||||||
|
@ -8,6 +8,11 @@ using Borepin.Service.Storage;
|
|||||||
using Borepin.Model.Storage;
|
using Borepin.Model.Storage;
|
||||||
using Borepin.Service.BFFH.Exceptions;
|
using Borepin.Service.BFFH.Exceptions;
|
||||||
using Borepin.Service.Storage.Exceptions;
|
using Borepin.Service.Storage.Exceptions;
|
||||||
|
using Capnp.Rpc;
|
||||||
|
using FabAccessAPI.Exceptions;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Security.Authentication;
|
||||||
|
|
||||||
namespace Borepin.Service.BFFH
|
namespace Borepin.Service.BFFH
|
||||||
{
|
{
|
||||||
@ -59,7 +64,7 @@ namespace Borepin.Service.BFFH
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Method
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all known Connections from Storage
|
/// Get all known Connections from Storage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -104,17 +109,16 @@ namespace Borepin.Service.BFFH
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Capnp.Rpc.TcpRpcClient rpcClient = new Capnp.Rpc.TcpRpcClient();
|
|
||||||
rpcClient.Connect(connection.Address.Host, connection.Address.Port);
|
TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
||||||
await rpcClient.WhenConnected.ConfigureAwait(false);
|
|
||||||
rpcClient.Dispose();
|
rpcClient.Dispose();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -146,11 +150,11 @@ namespace Borepin.Service.BFFH
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Capnp.Rpc.TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
||||||
|
|
||||||
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
||||||
}
|
}
|
||||||
catch (Capnp.Rpc.RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
catch (RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
throw new ConnectingFailedException("Connecting failed", exception);
|
throw new ConnectingFailedException("Connecting failed", exception);
|
||||||
}
|
}
|
||||||
@ -185,11 +189,11 @@ namespace Borepin.Service.BFFH
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Capnp.Rpc.TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
|
||||||
|
|
||||||
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
||||||
}
|
}
|
||||||
catch (Capnp.Rpc.RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
catch (RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
throw new ConnectingFailedException("Connecting failed", exception);
|
throw new ConnectingFailedException("Connecting failed", exception);
|
||||||
}
|
}
|
||||||
@ -231,11 +235,11 @@ namespace Borepin.Service.BFFH
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Capnp.Rpc.TcpRpcClient rpcClient = await _ConnectAsync(_CurrentConnection.Address.Host, _CurrentConnection.Address.Port).ConfigureAwait(false);
|
TcpRpcClient rpcClient = await _ConnectAsync(_CurrentConnection.Address.Host, _CurrentConnection.Address.Port).ConfigureAwait(false);
|
||||||
|
|
||||||
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
||||||
}
|
}
|
||||||
catch (Capnp.Rpc.RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
catch (RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
throw new ReconnectingFailedException("Connecting failed", new ConnectingFailedException("Connecting failed", exception));
|
throw new ReconnectingFailedException("Connecting failed", new ConnectingFailedException("Connecting failed", exception));
|
||||||
}
|
}
|
||||||
@ -264,51 +268,62 @@ namespace Borepin.Service.BFFH
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region FabAccess API Systems
|
#region FabAccess API Systems
|
||||||
public async Task<IMachineSystem> GetMachineSystemInterface()
|
public async Task<Session> GetSession()
|
||||||
{
|
{
|
||||||
if (!IsConnected)
|
if (!IsConnected)
|
||||||
{
|
{
|
||||||
await Reconnect().ConfigureAwait(false);
|
await Reconnect().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _APIConnection.AccessMachineSystem().ConfigureAwait(false);
|
return _APIConnection.Session;
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IUserSystem> GetUserSystemInterface()
|
|
||||||
{
|
|
||||||
if (!IsConnected)
|
|
||||||
{
|
|
||||||
await Reconnect().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await _APIConnection.AccessUserSystem().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IPermissionSystem> GetPermissionSystemInterface()
|
|
||||||
{
|
|
||||||
if (!IsConnected)
|
|
||||||
{
|
|
||||||
await Reconnect().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await _APIConnection.AccessPermissionSystem().ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
private static async Task<Capnp.Rpc.TcpRpcClient> _ConnectAsync(string host, int port)
|
private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||||
{
|
{
|
||||||
Capnp.Rpc.TcpRpcClient rpcClient = new Capnp.Rpc.TcpRpcClient();
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TcpRpcClient> _ConnectAsync(string host, int port)
|
||||||
|
{
|
||||||
|
TcpRpcClient rpcClient = new TcpRpcClient();
|
||||||
|
rpcClient.InjectMidlayer((tcpstream) =>
|
||||||
|
{
|
||||||
|
var sslStream = new SslStream(tcpstream, false, new RemoteCertificateValidationCallback(RemoteCertificateValidationCallback));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sslStream.AuthenticateAsClient("bffhd");
|
||||||
|
return sslStream;
|
||||||
|
}
|
||||||
|
catch (AuthenticationException)
|
||||||
|
{
|
||||||
|
sslStream.Close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
rpcClient.Connect(host, port);
|
rpcClient.Connect(host, port);
|
||||||
await rpcClient.WhenConnected.ConfigureAwait(false);
|
await rpcClient.WhenConnected.ConfigureAwait(false);
|
||||||
|
|
||||||
return rpcClient;
|
return rpcClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<bool> _AuthenticatePlainAsync(string username, string password)
|
private async Task<bool> _AuthenticatePlainAsync(string username, string password)
|
||||||
{
|
{
|
||||||
return _APIConnection.Auth("PLAIN", new Dictionary<string, object>(StringComparer.Ordinal) { { "Username", username }, { "Password", password } });
|
try
|
||||||
|
{
|
||||||
|
await _APIConnection.Auth("PLAIN", new Dictionary<string, object>(StringComparer.Ordinal) { { "Username", username }, { "Password", password } }).ConfigureAwait(false);
|
||||||
|
return await Task.FromResult(true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch(InvalidCredentialsException)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (AuthenticatingFailedException)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,6 @@ namespace Borepin.Service.BFFH
|
|||||||
Task Disconnect();
|
Task Disconnect();
|
||||||
|
|
||||||
|
|
||||||
Task<IMachineSystem> GetMachineSystemInterface();
|
Task<Session> GetSession();
|
||||||
Task<IPermissionSystem> GetPermissionSystemInterface();
|
|
||||||
Task<IUserSystem> GetUserSystemInterface();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,175 +1,81 @@
|
|||||||
using FabAccessAPI.Schema;
|
using FabAccessAPI.Schema;
|
||||||
using S22.Sasl;
|
using S22.Sasl;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Exception = System.Exception;
|
using FabAccessAPI.Exceptions;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace FabAccessAPI
|
namespace FabAccessAPI
|
||||||
{
|
{
|
||||||
/// Authentication Identity
|
|
||||||
///
|
|
||||||
/// Under the hood a string because the form depends heavily on the method
|
|
||||||
public struct AuthCId
|
|
||||||
{
|
|
||||||
public string Id { get; private set; }
|
|
||||||
|
|
||||||
public AuthCId(string id) : this() { Id = id; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Authorization Identity
|
|
||||||
///
|
|
||||||
/// This identity is internal to FabAccess and completely independent from the authentication
|
|
||||||
/// method or source
|
|
||||||
public struct AuthZId
|
|
||||||
{
|
|
||||||
/// Main User ID. Generally an user name or similar
|
|
||||||
public string Uid;
|
|
||||||
|
|
||||||
/// Sub user ID.
|
|
||||||
///
|
|
||||||
/// Can change scopes for permissions, e.g. having a +admin account with more permissions than
|
|
||||||
/// the default account and +dashboard et.al. accounts that have restricted permissions for
|
|
||||||
/// their applications
|
|
||||||
public string Subuid;
|
|
||||||
|
|
||||||
/// Realm this account originates.
|
|
||||||
///
|
|
||||||
/// The Realm is usually described by a domain name but local policy may dictate an unrelated
|
|
||||||
/// mapping
|
|
||||||
public string Realm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Authentication/Authorization user object.
|
|
||||||
///
|
|
||||||
/// This struct contains the user as is passed to the actual authentication/authorization
|
|
||||||
/// subsystems
|
|
||||||
///
|
|
||||||
public struct AuthUser
|
|
||||||
{
|
|
||||||
/// Contains the Authentication ID used
|
|
||||||
///
|
|
||||||
/// The authentication ID is an identifier for the authentication exchange. This is different
|
|
||||||
/// than the ID of the user to be authenticated; for example when using x509 the authcid is
|
|
||||||
/// the dn of the certificate, when using GSSAPI the authcid is of form `<userid>@<REALM>`
|
|
||||||
public AuthCId Authcid;
|
|
||||||
|
|
||||||
/// Contains the Authorization ID
|
|
||||||
///
|
|
||||||
/// This is the identifier of the user to *authenticate as*. This in several cases is different
|
|
||||||
/// to the `authcid`:
|
|
||||||
/// If somebody wants to authenticate as somebody else, su-style.
|
|
||||||
/// If a person wants to authenticate as a higher-permissions account, e.g. foo may set authzid foo+admin
|
|
||||||
/// to split normal user and "admin" accounts.
|
|
||||||
/// If a method requires a specific authcid that is different from the identifier of the user
|
|
||||||
/// to authenticate as, e.g. GSSAPI, x509 client certificates, API TOKEN authentication.
|
|
||||||
public AuthZId Authzid;
|
|
||||||
|
|
||||||
/// Contains the authentication method used
|
|
||||||
///
|
|
||||||
/// For the most part this is the SASL method
|
|
||||||
public string AuthMethod;
|
|
||||||
|
|
||||||
/// Method-specific key-value pairs
|
|
||||||
///
|
|
||||||
/// Each method can use their own key-value pairs.
|
|
||||||
/// E.g. EXTERNAL encodes the actual method used (x509 client certs, UID/GID for unix sockets,
|
|
||||||
/// ...)
|
|
||||||
public Dictionary<string, string> Kvs;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authentication has two parts: Granting the authentication itself and then performing the
|
|
||||||
// authentication.
|
|
||||||
// Granting the authentication checks if
|
|
||||||
// a) the given authcid fits with the given (authMethod, kvs). In general a failure here indicates
|
|
||||||
// a programming failure — the authcid come from the same source as that tuple
|
|
||||||
// b) the given authcid may authenticate as the given authzid. E.g. if a given client certificate
|
|
||||||
// has been configured for that user, if a GSSAPI user maps to a given user,
|
|
||||||
public enum AuthError
|
|
||||||
{
|
|
||||||
/// Authentication ID is bad/unknown/..
|
|
||||||
BadAuthcid,
|
|
||||||
/// Authorization ID is unknown/..
|
|
||||||
BadAuthzid,
|
|
||||||
/// Authorization ID is not of form user+uid@realm
|
|
||||||
MalformedAuthzid,
|
|
||||||
/// User may not use that authorization id
|
|
||||||
NotAllowedAuthzid,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UnauthorizedException : Exception { }
|
|
||||||
public class UnsupportedMechanismException : Exception { }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// THIS IS VERY INCOMPLETE!
|
/// Authenticate with SASL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Auth
|
public class Auth
|
||||||
{
|
{
|
||||||
#region Log
|
#region Private Fields
|
||||||
//private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
private readonly IAuthentication _AuthCap;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private readonly IAuthenticationSystem _AuthCap;
|
#region Constructors
|
||||||
public Auth(IAuthenticationSystem authCap)
|
public Auth(IAuthentication authCap)
|
||||||
{
|
{
|
||||||
_AuthCap = authCap;
|
_AuthCap = authCap;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public Task<IReadOnlyList<string>> GetMechanisms()
|
#region Methods
|
||||||
|
public async Task<Session> Authenticate(string mech, Dictionary<string, object> properties)
|
||||||
{
|
{
|
||||||
return _AuthCap.Mechanisms();
|
SaslMechanism? saslMechanism = SaslFactory.Create(mech);
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Authenticate(string mech, Dictionary<string, object> properties)
|
|
||||||
{
|
|
||||||
SaslMechanism? m = SaslFactory.Create(mech);
|
|
||||||
foreach (KeyValuePair<string, object> entry in properties)
|
foreach (KeyValuePair<string, object> entry in properties)
|
||||||
{
|
{
|
||||||
m.Properties.Add(entry.Key, entry.Value);
|
saslMechanism.Properties.Add(entry.Key, entry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Request.initialResponse? initialResponse = new Request.initialResponse();
|
byte[] data = new byte[0];
|
||||||
if (m.HasInitial)
|
|
||||||
|
if (saslMechanism.HasInitial)
|
||||||
{
|
{
|
||||||
initialResponse.Initial = m.GetResponse(new byte[0]);
|
data = saslMechanism.GetResponse(new byte[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Request? req = new Request
|
Response? response = await _AuthCap.Step(data);
|
||||||
|
while (!saslMechanism.IsCompleted)
|
||||||
{
|
{
|
||||||
Mechanism = m.Name,
|
if(response.Failed != null)
|
||||||
InitialResponse = initialResponse
|
|
||||||
};
|
|
||||||
|
|
||||||
Response? resp = await _AuthCap.Start(req);
|
|
||||||
while (!m.IsCompleted)
|
|
||||||
{
|
{
|
||||||
if (resp.which == Response.WHICH.Challence)
|
switch (response.Failed.Code)
|
||||||
{
|
{
|
||||||
byte[]? additional = m.GetResponse(resp.Challence.ToArray());
|
case Response.Error.badMechanism:
|
||||||
resp = await _AuthCap.Step(additional);
|
throw new BadMechanismException();
|
||||||
|
case Response.Error.invalidCredentials:
|
||||||
|
throw new InvalidCredentialsException();
|
||||||
|
case Response.Error.aborted:
|
||||||
|
case Response.Error.failed:
|
||||||
|
default:
|
||||||
|
throw new AuthenticationFailedException(response.Failed.AdditionalData.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(response.Challenge != null)
|
||||||
|
{
|
||||||
|
byte[]? additional = saslMechanism.GetResponse(response.Challenge.ToArray());
|
||||||
|
response = await _AuthCap.Step(additional);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
throw new AuthenticationFailedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.which == Response.WHICH.Outcome)
|
if (response.Successful != null)
|
||||||
{
|
{
|
||||||
if (resp.Outcome.Result == Response.Result.successful)
|
return response.Successful.Session;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//TODO: Provide meaningful info about auth failure
|
throw new AuthenticationFailedException();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Capnp.Rpc;
|
using Capnp.Rpc;
|
||||||
|
using FabAccessAPI.Exceptions;
|
||||||
using FabAccessAPI.Schema;
|
using FabAccessAPI.Schema;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -24,12 +25,13 @@ namespace FabAccessAPI
|
|||||||
{
|
{
|
||||||
RpcClient = rpcClient;
|
RpcClient = rpcClient;
|
||||||
_BootstrapCap = RpcClient.GetMain<IBootstrap>();
|
_BootstrapCap = RpcClient.GetMain<IBootstrap>();
|
||||||
//_Log.Debug($"Done bootstraping API connection.");
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Fields
|
#region Fields
|
||||||
public TcpRpcClient? RpcClient { get; } = null;
|
public TcpRpcClient? RpcClient { get; } = null;
|
||||||
|
|
||||||
|
public Session? Session { get; private set; } = null;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
@ -40,48 +42,21 @@ namespace FabAccessAPI
|
|||||||
/// <param name="mech">The desired authentication mechanism</param>
|
/// <param name="mech">The desired authentication mechanism</param>
|
||||||
/// <param name="kvs">Key-Value data specific to the mechanism</param>
|
/// <param name="kvs">Key-Value data specific to the mechanism</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<bool> Auth(string mech, Dictionary<string, object> kvs, CancellationToken cancellationToken_ = default)
|
public async Task Auth(string mech, Dictionary<string, object> kvs, CancellationToken cancellationToken_ = default)
|
||||||
{
|
{
|
||||||
if(_Auth == null)
|
IReadOnlyList<string>? mechs = await _BootstrapCap.Mechanisms();
|
||||||
{
|
|
||||||
IAuthenticationSystem? authCap = await _BootstrapCap.AuthenticationSystem(cancellationToken_).ConfigureAwait(false);
|
|
||||||
_Auth = new Auth(authCap);
|
|
||||||
}
|
|
||||||
|
|
||||||
IReadOnlyList<string>? mechs = await _Auth.GetMechanisms();
|
|
||||||
if (!mechs.Contains(mech))
|
if (!mechs.Contains(mech))
|
||||||
{
|
{
|
||||||
throw new UnsupportedMechanismException();
|
throw new UnsupportedMechanismException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _Auth.Authenticate(mech, kvs);
|
if (_Auth == null)
|
||||||
|
{
|
||||||
|
IAuthentication? authCap = await _BootstrapCap.CreateSession(mech, cancellationToken_).ConfigureAwait(false);
|
||||||
|
_Auth = new Auth(authCap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
Session = await _Auth.Authenticate(mech, kvs);
|
||||||
/// Get a wrapped capability to interact with machines
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A wrapped capability to interact with machines</returns>
|
|
||||||
public async Task<IMachineSystem> AccessMachineSystem()
|
|
||||||
{
|
|
||||||
return await _BootstrapCap.MachineSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a wrapped capability to interact with users
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A wrapped capability to interact with users</returns>
|
|
||||||
public async Task<IUserSystem> AccessUserSystem()
|
|
||||||
{
|
|
||||||
return await _BootstrapCap.UserSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a wrapped capability to interact with permissions
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A wrapped capability to interact with permissions</returns>
|
|
||||||
public async Task<IPermissionSystem> AccessPermissionSystem()
|
|
||||||
{
|
|
||||||
return await _BootstrapCap.PermissionSystem();
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
28
FabAccessAPI/Exceptions/AuthenticationFailedException.cs
Normal file
28
FabAccessAPI/Exceptions/AuthenticationFailedException.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FabAccessAPI.Exceptions
|
||||||
|
{
|
||||||
|
public class AuthenticationFailedException : Exception
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
public AuthenticationFailedException(byte[] additionalData = null)
|
||||||
|
{
|
||||||
|
AdditionalData = additionalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationFailedException(byte[] additionalData, string message) : base(message)
|
||||||
|
{
|
||||||
|
AdditionalData = additionalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationFailedException(byte[] additionalData, string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
AdditionalData = additionalData;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
public byte[]? AdditionalData { get; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
22
FabAccessAPI/Exceptions/BadMechanismException.cs
Normal file
22
FabAccessAPI/Exceptions/BadMechanismException.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FabAccessAPI.Exceptions
|
||||||
|
{
|
||||||
|
public class BadMechanismException : Exception
|
||||||
|
{
|
||||||
|
public BadMechanismException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadMechanismException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadMechanismException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
FabAccessAPI/Exceptions/InvalidCredentialsException.cs
Normal file
22
FabAccessAPI/Exceptions/InvalidCredentialsException.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FabAccessAPI.Exceptions
|
||||||
|
{
|
||||||
|
public class InvalidCredentialsException : Exception
|
||||||
|
{
|
||||||
|
public InvalidCredentialsException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCredentialsException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCredentialsException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
FabAccessAPI/Exceptions/UnsupportedMechanismException.cs
Normal file
22
FabAccessAPI/Exceptions/UnsupportedMechanismException.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FabAccessAPI.Exceptions
|
||||||
|
{
|
||||||
|
public class UnsupportedMechanismException : Exception
|
||||||
|
{
|
||||||
|
public UnsupportedMechanismException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnsupportedMechanismException(string message) : base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnsupportedMechanismException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit c855646a90958ae575d58be074d187acb9f8f4fa
|
Subproject commit c9283ebd696ed6dd428a7c3d24820889f7ab4bf3
|
35
FabAccessAPI_Test/Connection_Test.cs
Normal file
35
FabAccessAPI_Test/Connection_Test.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Capnp.Rpc;
|
||||||
|
using FabAccessAPI;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FabAccessAPI_Test
|
||||||
|
{
|
||||||
|
public class Connection_Test
|
||||||
|
{
|
||||||
|
[TestCase("test.fab-access.org", 59661)]
|
||||||
|
public async Task Connect(string host, int port)
|
||||||
|
{
|
||||||
|
TcpRpcClient tcpRpcClient = new TcpRpcClient();
|
||||||
|
tcpRpcClient.Connect(host, port);
|
||||||
|
await tcpRpcClient.WhenConnected;
|
||||||
|
|
||||||
|
Connection connection = new Connection(tcpRpcClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("test.fab-access.org", 59661, "Testuser", "secret")]
|
||||||
|
public async Task Authenticate_PLAIN(string host, int port, string username, string password)
|
||||||
|
{
|
||||||
|
TcpRpcClient tcpRpcClient = new TcpRpcClient();
|
||||||
|
tcpRpcClient.Connect(host, port);
|
||||||
|
await tcpRpcClient.WhenConnected;
|
||||||
|
|
||||||
|
Connection connection = new Connection(tcpRpcClient);
|
||||||
|
await connection.Auth("PLAIN", new Dictionary<string, object>(StringComparer.Ordinal) { { "Username", username }, { "Password", password } });
|
||||||
|
|
||||||
|
Assert.IsNotNull(connection.Session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
external/capnproto-dotnetcore
vendored
2
external/capnproto-dotnetcore
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 1ba1b6fbe0d9a278445ef7fde7624f218171156b
|
Subproject commit 086bbc2497785d2cc63e9252df6f6d3ee7599579
|
Loading…
x
Reference in New Issue
Block a user