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 Authenticate(string mech, Dictionary properties) { + var m = SaslFactory.Create(mech); + foreach (KeyValuePair entry in properties) { + m.Properties.Add(entry.Key, entry.Value); + } + + var initialResponse = new Request.initialResponse(); + if (m.HasInitial) { + initialResponse.Initial = m.GetResponse(new byte[0]); + } + + var req = new Request { + Mechanism = m.Name, + InitialResponse = initialResponse + }; + + var resp = await _authCap.Start(req); + while (!m.IsCompleted) { + if (resp.which == Response.WHICH.Challence) { + var additional = m.GetResponse(resp.Challence.ToArray()); + resp = await _authCap.Step(additional); + } + else { + break; + } + } + + + return null; + } + + + + } + +} diff --git a/FabAccessAPI/Connection.cs b/FabAccessAPI/Connection.cs index 8541833..7688e51 100644 --- a/FabAccessAPI/Connection.cs +++ b/FabAccessAPI/Connection.cs @@ -2,82 +2,31 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading.Tasks; using Capnp; +using Capnp.Rpc; using FabAccessAPI.Schema; -using S22.Sasl; namespace FabAccessAPI { - class Connection - { - public bool Connect(Greeting clientInfo, Stream stream) - { - var message = new Message() + class Connection { + private TcpRpcClient _rpcClient; + private IBootstrap _bootstrapCap; + private User _user; + private Auth _auth; - { - Greet = clientInfo, - which = Message.WHICH.Greet, - }; - - 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 Message.READER(deserializer); - - switch (reader.which) - { - case Message.WHICH.Greet: - var serverInfo = reader.Greet; - Console.WriteLine($"Server: {serverInfo.Host}"); - Console.WriteLine($"Version: {serverInfo.Program}"); - Console.WriteLine($"API-Version: {serverInfo.Major}.{serverInfo.Minor}"); - break; - case Message.WHICH.Leave: - var leave_inner = reader.Leave; - switch (leave_inner.TheReason) - { - case Leave.Reason.incompatible: - Console.WriteLine($"Connection aborted due to incompatible API: {leave_inner.Message}"); - break; - case Leave.Reason.other: - Console.WriteLine($"Connection aborted: {leave_inner.Message}"); - break; - default: - Console.WriteLine($"Got invalid This should never happen: {leave_inner.Message}"); - break; - } - return false; - default: - Console.WriteLine($"Got unexpected message: {reader.which}"); - break; - - } - - //FIXME: Replace the hardcoded credentials - SaslMechanism m = SaslFactory.Create("PLAIN"); - m.Properties.Add("Username", "test"); - m.Properties.Add("Password", "secret"); - - var authRequest = new Request() - { - Mechanism = m.Name, - - }; - - var auth = new AuthMessage() - { - - }; - - return true; + /// + /// + /// + /// Should be an already configured and connected TcpRpcClient + public Connection(TcpRpcClient rpcClient) { + _rpcClient = rpcClient; + _bootstrapCap = _rpcClient.GetMain(); } + async Task Auth(string mech, Dictionary kvs) { + _auth = new Auth(await _bootstrapCap.Auth()); + var mechs = await _auth.GetMechanisms().ConfigureAwait(false); + } } } diff --git a/FabAccessAPI/FabAccessAPI.cs b/FabAccessAPI/FabAccessAPI.cs index acf265d..36ee66a 100644 --- a/FabAccessAPI/FabAccessAPI.cs +++ b/FabAccessAPI/FabAccessAPI.cs @@ -1,8 +1,11 @@ using System; +using S22.Sasl; namespace FabAccessAPI { - public class Class1 + public class Api { + + } } diff --git a/FabAccessAPI/InjectableTcpRpcClient.cs b/FabAccessAPI/InjectableTcpRpcClient.cs new file mode 100644 index 0000000..3676431 --- /dev/null +++ b/FabAccessAPI/InjectableTcpRpcClient.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Capnp.Rpc; + +namespace FabAccessAPI { + class InjectableTcpRpcClient : TcpRpcClient { + + } +} diff --git a/FabAccessAPI_Test/FabAccessAPI_Test.csproj b/FabAccessAPI_Test/FabAccessAPI_Test.csproj new file mode 100644 index 0000000..d109b70 --- /dev/null +++ b/FabAccessAPI_Test/FabAccessAPI_Test.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + diff --git a/FabAccessAPI_Test/UnitTest1.cs b/FabAccessAPI_Test/UnitTest1.cs new file mode 100644 index 0000000..fabf812 --- /dev/null +++ b/FabAccessAPI_Test/UnitTest1.cs @@ -0,0 +1,18 @@ +using NUnit.Framework; + +namespace FabAccessAPI_Test +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + } +} \ No newline at end of file