mirror of
https://gitlab.com/fabinfra/fabaccess/borepin.git
synced 2025-03-12 14:51:44 +01:00
Added more API Service Methods
This commit is contained in:
parent
a9a3f9c545
commit
bb4a74f8c4
@ -130,11 +130,6 @@ namespace Borepin.Service.BFFH
|
||||
/// <exception cref="AuthenticatingFailedException"></exception>
|
||||
public async Task Connect(Connection connection)
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
throw new AllreadyConnectedException();
|
||||
}
|
||||
|
||||
string password;
|
||||
try
|
||||
{
|
||||
@ -162,7 +157,6 @@ namespace Borepin.Service.BFFH
|
||||
if (! await _AuthenticatePlainAsync(connection.Username, password).ConfigureAwait(false))
|
||||
{
|
||||
await Disconnect().ConfigureAwait(false);
|
||||
throw new AuthenticatingFailedException();
|
||||
}
|
||||
|
||||
_CurrentConnection = new Connection_Plain(connection)
|
||||
@ -182,10 +176,6 @@ namespace Borepin.Service.BFFH
|
||||
/// <exception cref="AuthenticatingFailedException"></exception>
|
||||
public async Task Connect(Connection connection, string password)
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
throw new AllreadyConnectedException();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@ -201,7 +191,7 @@ namespace Borepin.Service.BFFH
|
||||
if (!await _AuthenticatePlainAsync(connection.Username, password).ConfigureAwait(false))
|
||||
{
|
||||
await Disconnect().ConfigureAwait(false);
|
||||
throw new AuthenticatingFailedException();
|
||||
|
||||
}
|
||||
|
||||
_CurrentConnection = new Connection_Plain(connection)
|
||||
@ -239,15 +229,6 @@ namespace Borepin.Service.BFFH
|
||||
|
||||
_APIConnection = new FabAccessAPI.Connection(rpcClient);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
if (! await _AuthenticatePlainAsync(_CurrentConnection.Username, _CurrentConnection.Password).ConfigureAwait(false))
|
||||
{
|
||||
throw new ReconnectingFailedException("Authentication failed", new AuthenticatingFailedException());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -316,11 +297,7 @@ namespace Borepin.Service.BFFH
|
||||
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)
|
||||
catch(UnsupportedMechanismException)
|
||||
{
|
||||
return await Task.FromResult(true).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Borepin.Service.BFFH.Exceptions
|
||||
{
|
||||
public class APIIncompatibleException : Exception
|
||||
{
|
||||
public APIIncompatibleException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public APIIncompatibleException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public APIIncompatibleException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Borepin.Service.BFFH.Exceptions
|
||||
{
|
||||
public class AllreadyConnectedException : Exception
|
||||
{
|
||||
public AllreadyConnectedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AllreadyConnectedException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AllreadyConnectedException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Borepin.Service.BFFH.Exceptions
|
||||
{
|
||||
public class AuthenticatingFailedException : Exception
|
||||
{
|
||||
public AuthenticatingFailedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AuthenticatingFailedException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AuthenticatingFailedException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Borepin.Service.BFFH.Exceptions
|
||||
{
|
||||
public class ConnectingFailedException : Exception
|
||||
{
|
||||
public ConnectingFailedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ConnectingFailedException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ConnectingFailedException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,19 @@
|
||||
using FabAccessAPI.Schema;
|
||||
using Capnp.Rpc;
|
||||
using FabAccessAPI.Exceptions;
|
||||
using FabAccessAPI.Schema;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Security;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FabAccessAPI
|
||||
{
|
||||
public class API : IAPI
|
||||
{
|
||||
#region Private Members
|
||||
private Connection _APIConnection;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@ -28,7 +36,7 @@ namespace FabAccessAPI
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return _APIConnection != null && _APIConnection.RpcClient.State == ConnectionState.Active;
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,24 +50,138 @@ namespace FabAccessAPI
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
public void Connect(ConnectionData connectionData)
|
||||
/// <summary>
|
||||
/// Connect to server with ConnectionData
|
||||
/// </summary>
|
||||
/// <exception cref="AuthenticationException"></exception>
|
||||
/// <exception cref="ConnectingFailedException"></exception>
|
||||
public async Task Connect(ConnectionData connectionData)
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
await Disconnect();
|
||||
}
|
||||
|
||||
TcpRpcClient rpcClient = await _ConnectAsync(connectionData).ConfigureAwait(false);
|
||||
|
||||
_APIConnection = new Connection(rpcClient);
|
||||
|
||||
try
|
||||
{
|
||||
await _Authenticate(connectionData).ConfigureAwait(false);
|
||||
}
|
||||
catch(System.Exception)
|
||||
{
|
||||
await Disconnect().ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public Task Disconnect()
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
_APIConnection.RpcClient?.Dispose();
|
||||
}
|
||||
|
||||
_APIConnection = null;
|
||||
ConnectionData = null;
|
||||
ConnectionInfo = null;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Reconnect()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
public async Task<ConnectionInfo> TestConnection(ConnectionData connectionData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
try
|
||||
{
|
||||
TcpRpcClient rpcClient = await _ConnectAsync(connectionData).ConfigureAwait(false);
|
||||
Connection testConnection = new Connection(rpcClient);
|
||||
|
||||
rpcClient.Dispose();
|
||||
|
||||
ConnectionInfo connectionInfo = new ConnectionInfo()
|
||||
{
|
||||
APIVersion = testConnection.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
// TODO Cert Check
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reconnect()
|
||||
/// <summary>
|
||||
/// Connect to server async with ConnectionData
|
||||
/// </summary>
|
||||
/// <exception cref="AuthenticationException">TLS Error</exception>
|
||||
/// <exception cref="ConnectingFailedException">Based on RPC Exception</exception>
|
||||
///
|
||||
private async Task<TcpRpcClient> _ConnectAsync(ConnectionData connectionData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
rpcClient.Connect(connectionData.Host.Host, connectionData.Host.Port);
|
||||
await rpcClient.WhenConnected.ConfigureAwait(false);
|
||||
|
||||
return rpcClient;
|
||||
}
|
||||
catch (RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
|
||||
{
|
||||
throw new ConnectingFailedException("Connecting failed", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionInfo TestConnection(ConnectionData connectionData)
|
||||
/// <summary>
|
||||
/// Authenticate connection with ConnectionData
|
||||
/// </summary>
|
||||
/// <exception cref="UnsupportedMechanismException"></exception>
|
||||
/// <exception cref="InvalidCredentialsException"></exception>
|
||||
/// <exception cref="AuthenticationFailedException"></exception>
|
||||
private async Task _Authenticate(ConnectionData connectionData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Dictionary<string, object> joinedProperties = new Dictionary<string, object>();
|
||||
foreach(KeyValuePair<string, object> keyValuePair in connectionData.Properties)
|
||||
{
|
||||
joinedProperties.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
foreach (KeyValuePair<string, object> keyValuePair in connectionData.SecretProperties)
|
||||
{
|
||||
joinedProperties.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
|
||||
await _APIConnection.Auth(MechanismString.ToString(connectionData.Mechanism), joinedProperties).ConfigureAwait(false);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -24,6 +24,12 @@ namespace FabAccessAPI
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>
|
||||
/// Authenticate Connection to get Session
|
||||
/// </summary>
|
||||
/// <exception cref="BadMechanismException"></exception>
|
||||
/// <exception cref="InvalidCredentialsException"></exception>
|
||||
/// <exception cref="AuthenticationFailedException"></exception>
|
||||
public async Task<Session> Authenticate(string mech, Dictionary<string, object> properties)
|
||||
{
|
||||
SaslMechanism? saslMechanism = SaslFactory.Create(mech);
|
||||
@ -44,17 +50,7 @@ namespace FabAccessAPI
|
||||
{
|
||||
if(response.Failed != null)
|
||||
{
|
||||
switch (response.Failed.Code)
|
||||
{
|
||||
case Response.Error.badMechanism:
|
||||
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());
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(response.Challenge != null)
|
||||
{
|
||||
@ -71,6 +67,20 @@ namespace FabAccessAPI
|
||||
{
|
||||
return response.Successful.Session;
|
||||
}
|
||||
else if (response.Failed != null)
|
||||
{
|
||||
switch (response.Failed.Code)
|
||||
{
|
||||
case Response.Error.badMechanism:
|
||||
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());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuthenticationFailedException();
|
||||
|
@ -41,7 +41,9 @@ namespace FabAccessAPI
|
||||
/// </summary>
|
||||
/// <param name="mech">The desired authentication mechanism</param>
|
||||
/// <param name="kvs">Key-Value data specific to the mechanism</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="UnsupportedMechanismException"></exception>
|
||||
/// <exception cref="InvalidCredentialsException"></exception>
|
||||
/// <exception cref="AuthenticationFailedException"></exception>
|
||||
public async Task Auth(string mech, Dictionary<string, object> kvs, CancellationToken cancellationToken_ = default)
|
||||
{
|
||||
IReadOnlyList<string>? mechs = await _BootstrapCap.Mechanisms();
|
||||
|
@ -1,5 +1,6 @@
|
||||
using FabAccessAPI.Schema;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FabAccessAPI
|
||||
{
|
||||
@ -35,17 +36,17 @@ namespace FabAccessAPI
|
||||
/// Connect to BFFH Server
|
||||
/// </summary>
|
||||
/// <param name="connectionData"></param>
|
||||
void Connect(ConnectionData connectionData);
|
||||
Task Connect(ConnectionData connectionData);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from BFFH Server
|
||||
/// </summary>
|
||||
void Disconnect();
|
||||
Task Disconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Reconnect after connection loss with the last ConnectionData
|
||||
/// </summary>
|
||||
void Reconnect();
|
||||
Task Reconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Connect to Server and get ConnectionInfo.
|
||||
|
@ -1,7 +1,24 @@
|
||||
namespace FabAccessAPI
|
||||
using System;
|
||||
|
||||
namespace FabAccessAPI
|
||||
{
|
||||
public enum Mechanism
|
||||
{
|
||||
PLAIN
|
||||
PLAIN,
|
||||
}
|
||||
|
||||
public static class MechanismString
|
||||
{
|
||||
public static string ToString(Mechanism mechanism)
|
||||
{
|
||||
switch(mechanism)
|
||||
{
|
||||
case Mechanism.PLAIN:
|
||||
return "PLAIN";
|
||||
default:
|
||||
throw new ArgumentException("Mechanism not known.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,13 +4,14 @@ using FabAccessAPI.Exceptions;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FabAccessAPI_Test
|
||||
{
|
||||
public class API_Test
|
||||
{
|
||||
[TestCase("Admin1")]
|
||||
public void ConnectDisconnect(string username)
|
||||
public async Task ConnectDisconnect(string username)
|
||||
{
|
||||
API api = new API();
|
||||
|
||||
@ -29,12 +30,12 @@ namespace FabAccessAPI_Test
|
||||
}
|
||||
};
|
||||
|
||||
api.Connect(connectionData);
|
||||
api.Disconnect();
|
||||
await api.Connect(connectionData);
|
||||
await api.Disconnect();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Connect_HostUnreachable()
|
||||
public async Task Connect_HostUnreachable()
|
||||
{
|
||||
API api = new API();
|
||||
|
||||
@ -53,14 +54,19 @@ namespace FabAccessAPI_Test
|
||||
}
|
||||
};
|
||||
|
||||
Assert.Throws<ConnectingFailedException>(() =>
|
||||
try
|
||||
{
|
||||
api.Connect(connectionData);
|
||||
});
|
||||
await api.Connect(connectionData);
|
||||
}
|
||||
catch (ConnectingFailedException)
|
||||
{
|
||||
Assert.Pass();
|
||||
}
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Connect_InvalidCredentials()
|
||||
public async Task Connect_InvalidCredentials()
|
||||
{
|
||||
API api = new API();
|
||||
|
||||
@ -79,10 +85,15 @@ namespace FabAccessAPI_Test
|
||||
}
|
||||
};
|
||||
|
||||
Assert.Throws<InvalidCredentialsException>(() =>
|
||||
try
|
||||
{
|
||||
api.Connect(connectionData);
|
||||
});
|
||||
await api.Connect(connectionData);
|
||||
}
|
||||
catch(InvalidCredentialsException)
|
||||
{
|
||||
Assert.Pass();
|
||||
}
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user