Added more API Service Methods

This commit is contained in:
TheJoKlLa 2022-05-11 15:02:17 +02:00
parent a9a3f9c545
commit bb4a74f8c4
11 changed files with 202 additions and 150 deletions

View File

@ -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);
}

View File

@ -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)
{
}
}
}

View File

@ -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)
{
}
}
}

View File

@ -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)
{
}
}
}

View File

@ -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)
{
}
}
}

View File

@ -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
}

View File

@ -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();

View File

@ -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();

View File

@ -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.

View File

@ -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.");
}
}
}
}

View File

@ -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();
}
}
}