diff --git a/Borepin.sln b/Borepin.sln
index 140ff2a..80f8342 100644
--- a/Borepin.sln
+++ b/Borepin.sln
@@ -15,11 +15,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Borepin.GTK", "Borepin\Bore
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Borepin.macOS", "Borepin\Borepin.macOS\Borepin.macOS.csproj", "{3EC23FE7-395E-4BBC-B56B-9455354BDA34}"
EndProject
-Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "NFC_Test", "NFC_Test\NFC_Test.csproj", "{41EC0C17-B456-42AE-89F2-79DDB8ED9858}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NFC_Test", "NFC_Test\NFC_Test.csproj", "{41EC0C17-B456-42AE-89F2-79DDB8ED9858}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NFC", "NFC\NFC.csproj", "{9C2ED2EB-D91C-4D80-9580-6A135C05AF11}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NFC", "NFC\NFC.csproj", "{9C2ED2EB-D91C-4D80-9580-6A135C05AF11}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FabAccessAPI", "FabAccessAPI\FabAccessAPI.csproj", "{3251FCE9-FEA3-4662-8BEB-636BE6732D48}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FabAccessAPI", "FabAccessAPI\FabAccessAPI.csproj", "{3251FCE9-FEA3-4662-8BEB-636BE6732D48}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FabAccessAPI_Test", "FabAccessAPI_Test\FabAccessAPI_Test.csproj", "{6DD3DE28-BB0B-45BA-9072-CF6325E294CB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "S22.Sasl", "external\SASL\S22.Sasl.csproj", "{7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -301,6 +305,54 @@ Global
{3251FCE9-FEA3-4662-8BEB-636BE6732D48}.Release|x64.Build.0 = Release|Any CPU
{3251FCE9-FEA3-4662-8BEB-636BE6732D48}.Release|x86.ActiveCfg = Release|Any CPU
{3251FCE9-FEA3-4662-8BEB-636BE6732D48}.Release|x86.Build.0 = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|ARM.Build.0 = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|x64.Build.0 = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Debug|x86.Build.0 = Debug|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|ARM.ActiveCfg = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|ARM.Build.0 = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|iPhone.Build.0 = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|x64.ActiveCfg = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|x64.Build.0 = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|x86.ActiveCfg = Release|Any CPU
+ {6DD3DE28-BB0B-45BA-9072-CF6325E294CB}.Release|x86.Build.0 = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|ARM.Build.0 = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|x64.Build.0 = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Debug|x86.Build.0 = Debug|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|ARM.ActiveCfg = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|ARM.Build.0 = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|iPhone.Build.0 = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|x64.ActiveCfg = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|x64.Build.0 = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|x86.ActiveCfg = Release|Any CPU
+ {7FEC3D5E-C240-41B6-BBFA-895C4F4D45CA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Borepin/Borepin.iOS/Borepin.iOS.csproj b/Borepin/Borepin.iOS/Borepin.iOS.csproj
index 3c9847e..83951c5 100644
--- a/Borepin/Borepin.iOS/Borepin.iOS.csproj
+++ b/Borepin/Borepin.iOS/Borepin.iOS.csproj
@@ -83,30 +83,78 @@
false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
diff --git a/FabAccessAPI/Auth.cs b/FabAccessAPI/Auth.cs
new file mode 100644
index 0000000..9f68def
--- /dev/null
+++ b/FabAccessAPI/Auth.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Capnp;
+using Capnp.Rpc;
+using FabAccessAPI.Schema;
+using S22.Sasl;
+
+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 User {
+ /// 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 `@`
+ 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 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,
+
+ }
+
+ class Auth {
+ private IAuthentication _authCap;
+ public Auth(IAuthentication authCap) {
+ _authCap = authCap;
+ }
+
+ public Task> GetMechanisms() {
+ return _authCap.Mechanisms();
+ }
+
+ public async Task Handshake() {
+ var host = "localhost";
+ var asm = typeof(Api).Assembly;
+ var program = $"{asm.FullName}-{asm.GetName().Version}";
+ var version = (0u, 1u);
+
+ var message = new Greeting() {
+ Host = host,
+ Major = version.Item1,
+ Minor = version.Item2,
+ Program = program
+ };
+
+ var msg = MessageBuilder.Create();
+ var root = msg.BuildRoot();
+ message.serialize(root);
+
+ var pump = new FramePump(stream);
+ pump.Send(msg.Frame);
+
+ var frame = Framing.ReadSegments(stream);
+
+ var deserializer = DeserializerState.CreateRoot(frame);
+ var reader = new Greeting.READER(deserializer);
+
+
+ var serverInfo = reader;
+ Console.WriteLine($"Server: {serverInfo.Host}");
+ Console.WriteLine($"Version: {serverInfo.Program}");
+ Console.WriteLine($"API-Version: {serverInfo.Major}.{serverInfo.Minor}");
+ }
+
+ public async Task