From 52588d66d57dcbf9972911d6d1787994eb3687c8 Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Fri, 15 Nov 2019 13:49:21 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 41 +++++++++++++++++++ AuthenticationChallenges.cs | 41 +++++++++++++++++++ AuthenticationProve.cs | 23 +++++++++++ AuthenticationRequest.cs | 21 ++++++++++ BaseIdentityProvider.cs | 34 ++++++++++++++++ IIdentityProvider.cs | 18 +++++++++ Identity.cs | 60 ++++++++++++++++++++++++++++ ODBIdentityProvider.cs | 78 +++++++++++++++++++++++++++++++++++++ Properties/AssemblyInfo.cs | 26 +++++++++++++ Role.cs | 13 +++++++ RoleAssignment.cs | 10 +++++ SecureAttribute.cs | 36 +++++++++++++++++ SeededPassword.cs | 61 +++++++++++++++++++++++++++++ ln.identities.csproj | 53 +++++++++++++++++++++++++ 14 files changed, 515 insertions(+) create mode 100644 .gitignore create mode 100644 AuthenticationChallenges.cs create mode 100644 AuthenticationProve.cs create mode 100644 AuthenticationRequest.cs create mode 100644 BaseIdentityProvider.cs create mode 100644 IIdentityProvider.cs create mode 100644 Identity.cs create mode 100644 ODBIdentityProvider.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 Role.cs create mode 100644 RoleAssignment.cs create mode 100644 SecureAttribute.cs create mode 100644 SeededPassword.cs create mode 100644 ln.identities.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf793ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db +.vs/ + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover diff --git a/AuthenticationChallenges.cs b/AuthenticationChallenges.cs new file mode 100644 index 0000000..f5a6c02 --- /dev/null +++ b/AuthenticationChallenges.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +namespace ln.identities +{ + public class AuthenticationChallenges + { + public AuthenticationChallenge[] Challenges => authenticationChallenges.ToArray(); + + List authenticationChallenges = new List(); + + private AuthenticationChallenges() + { + } + + public AuthenticationChallenges(IEnumerable secureAttributes) + { + foreach (SecureAttribute secureAttribute in secureAttributes) + { + authenticationChallenges.Add(new AuthenticationChallenge(secureAttribute)); + } + } + } + + public class AuthenticationChallenge + { + public Guid SecureAttributeID { get; private set; } + public String SecureAttributeTypeName { get; private set; } + public string SecureAttributeLabel { get; private set; } + public String AuthenticationParameters { get; private set; } + public byte[] Challenge { get; private set; } + + public AuthenticationChallenge(SecureAttribute secureAttribute) + { + SecureAttributeID = secureAttribute.UniqueID; + SecureAttributeTypeName = secureAttribute.GetAttributeTypeName(); + SecureAttributeLabel = secureAttribute.Label; + AuthenticationParameters = secureAttribute.GetAuthenticationParameters(); + Challenge = secureAttribute.CreateChallenge(); + } + } +} diff --git a/AuthenticationProve.cs b/AuthenticationProve.cs new file mode 100644 index 0000000..8a25b3f --- /dev/null +++ b/AuthenticationProve.cs @@ -0,0 +1,23 @@ +using System; +namespace ln.identities +{ + public class AuthenticationProve + { + private AuthenticationProve() + { + } + public AuthenticationProve(string identityName,Guid secureAttributeUniqueID,byte[] challenge,byte[] prove) + { + IdentityName = identityName; + SecureAttributeUniqueID = secureAttributeUniqueID; + Challenge = challenge; + Prove = prove; + } + + public string IdentityName { get; private set; } + public Guid SecureAttributeUniqueID { get; private set; } + + public byte[] Challenge { get; private set; } + public byte[] Prove { get; private set; } + } +} diff --git a/AuthenticationRequest.cs b/AuthenticationRequest.cs new file mode 100644 index 0000000..2be65f6 --- /dev/null +++ b/AuthenticationRequest.cs @@ -0,0 +1,21 @@ +using System; +namespace ln.identities +{ + public class AuthenticationRequest + { + public String IdentityName { get; private set; } + public String SecureAttributeTypeName { get; private set; } + + private AuthenticationRequest() + { + } + + public AuthenticationRequest(String identityName,String secureAttributeTypeName) + { + IdentityName = identityName; + SecureAttributeTypeName = secureAttributeTypeName; + } + + public AuthenticationRequest(String identityName) : this(identityName, null){} + } +} diff --git a/BaseIdentityProvider.cs b/BaseIdentityProvider.cs new file mode 100644 index 0000000..ab87e9f --- /dev/null +++ b/BaseIdentityProvider.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ln.identities +{ + public abstract class BaseIdentityProvider : IIdentityProvider + { + public BaseIdentityProvider() + { + } + + public virtual Identity Authenticate(AuthenticationProve authenticationProve) + { + Identity identity = GetIdentity(authenticationProve.IdentityName); + if (identity == null) + throw new KeyNotFoundException(); + + SecureAttribute secureAttribute = identity.GetSecureAttribute(authenticationProve.SecureAttributeUniqueID); + if (secureAttribute.Authenticate(authenticationProve.Challenge, authenticationProve.Prove)) + { + return identity; + } + throw new ArgumentOutOfRangeException(); + } + + public abstract Identity CreateIdentity(string identityName); + public abstract IEnumerable> GetIdentities(); + public abstract Identity GetIdentity(Guid uniqueID); + public abstract bool Save(Identity identity); + + public virtual Identity GetIdentity(string identityName) => GetIdentity(GetIdentities().FirstOrDefault((kvp) => identityName.Equals(kvp.Value)).Key); + } +} diff --git a/IIdentityProvider.cs b/IIdentityProvider.cs new file mode 100644 index 0000000..17da2ba --- /dev/null +++ b/IIdentityProvider.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +namespace ln.identities +{ + public interface IIdentityProvider + { + IEnumerable> GetIdentities(); + + Identity GetIdentity(Guid uniqueID); + Identity GetIdentity(string identityName); + + Identity CreateIdentity(string identityName); + + bool Save(Identity identity); + + Identity Authenticate(AuthenticationProve authenticationProve); + } +} diff --git a/Identity.cs b/Identity.cs new file mode 100644 index 0000000..5bb659f --- /dev/null +++ b/Identity.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ln.identities +{ + public class Identity + { + public Guid UniqueID { get; private set; } + + public String IdentityName { get; set; } + + List secureAttributes = new List(); + List roleAssignments = new List(); + + private Identity() + { + } + + private Identity(Guid uniqueID,string identityName) + { + UniqueID = uniqueID; + IdentityName = identityName; + } + + public Identity(string identityName) : this(Guid.NewGuid(),identityName){} + + public SecureAttribute GetSecureAttribute(Guid uniqueID) + { + foreach (SecureAttribute secureAttribute in secureAttributes) + { + if (secureAttribute.UniqueID.Equals(uniqueID)) + return secureAttribute; + } + throw new KeyNotFoundException(); + } + + public SecureAttribute[] GetSecureAttributes() => secureAttributes.ToArray(); + public SecureAttribute[] GetSecureAttributes(String secureAttributeTypeName) => secureAttributeTypeName == null ? GetSecureAttributes() : secureAttributes.Where((secureAttribute)=>secureAttribute.GetAttributeTypeName().Equals(secureAttributeTypeName)).ToArray(); + public KeyValuePair[] GetChallenges() => GetChallenges(null); + public KeyValuePair[] GetChallenges(String secureAttributeTypeName) + { + SecureAttribute[] sas = GetSecureAttributes(secureAttributeTypeName); + KeyValuePair[] challenges = new KeyValuePair[sas.Length]; + + for (int n = 0; n < sas.Length; n++) + { + challenges[n] = new KeyValuePair(sas[n].UniqueID, sas[n].CreateChallenge()); + } + + return challenges; + } + + public void AddSecureAttribute(SecureAttribute secureAttribute) => secureAttributes.Add(secureAttribute); + public void RemoveSecureAttribute(SecureAttribute secureAttribute) => secureAttributes.Remove(secureAttribute); + + + + } +} diff --git a/ODBIdentityProvider.cs b/ODBIdentityProvider.cs new file mode 100644 index 0000000..9fc81e1 --- /dev/null +++ b/ODBIdentityProvider.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using ln.types.odb.ng.storage; +using ln.types.odb.ng; +using System.Linq; +using ln.types.btree; +using ln.types.collections; +using System.Security.Principal; +namespace ln.identities +{ + public class ODBIdentityProvider : BaseIdentityProvider + { + public IStorageContainer StorageContainer { get; } + + Mapper mapper; + WeakValueDictionary identityCache = new WeakValueDictionary(); + + public ODBIdentityProvider(IStorageContainer storageContainer) + { + StorageContainer = storageContainer; + mapper = new Mapper(storageContainer); + + mapper.EnsureIndex("UniqueID"); + mapper.EnsureIndex("IdentityName"); + } + + public override IEnumerable> GetIdentities() => mapper.Load().Select((identity) => new KeyValuePair(identity.UniqueID, identity.IdentityName)); + public override Identity GetIdentity(Guid uniqueID) + { + if (identityCache.ContainsKey(uniqueID)) + return identityCache[uniqueID]; + + Identity identity = mapper.Load(Query.Equals("UniqueID", uniqueID)).FirstOrDefault(); + if (identity != null) + { + identityCache.Add(identity.UniqueID,identity); + return identity; + } + + throw new KeyNotFoundException(); + } + public override Identity GetIdentity(string identityName) + { + Identity identity = mapper.Load(Query.Equals("IdentityName", identityName)).FirstOrDefault(); + if (identity != null) + { + if (!identityCache.ContainsKey(identity.UniqueID)) + identityCache.Add(identity.UniqueID, identity); + + return identity; + } + throw new KeyNotFoundException(); + } + + public override Identity CreateIdentity(string identityName) + { + Identity identity = new Identity(identityName); + identityCache.Add(identity.UniqueID, identity); + return identity; + } + + public override bool Save(Identity identity) + { + if (!identityCache.ContainsKey(identity.UniqueID)) + throw new KeyNotFoundException(); + + Identity cachedIdentity = identityCache[identity.UniqueID]; + + if (!Object.ReferenceEquals(identity, cachedIdentity)) + throw new ArgumentOutOfRangeException(); + + mapper.Save(cachedIdentity); + + return true; + } + + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e421788 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("ln.identities")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/Role.cs b/Role.cs new file mode 100644 index 0000000..f237e04 --- /dev/null +++ b/Role.cs @@ -0,0 +1,13 @@ +using System; +namespace ln.identities +{ + public class Role + { + public String Name { get; } + + + public Role() + { + } + } +} diff --git a/RoleAssignment.cs b/RoleAssignment.cs new file mode 100644 index 0000000..4e8ee1c --- /dev/null +++ b/RoleAssignment.cs @@ -0,0 +1,10 @@ +using System; +namespace ln.identities +{ + public class RoleAssignment + { + public RoleAssignment() + { + } + } +} diff --git a/SecureAttribute.cs b/SecureAttribute.cs new file mode 100644 index 0000000..3e00109 --- /dev/null +++ b/SecureAttribute.cs @@ -0,0 +1,36 @@ +using System; +namespace ln.identities +{ + public abstract class SecureAttribute + { + static public Random Random { get; } = new Random(); + + public Guid UniqueID { get; private set; } + public String Label { get; set; } + + public byte[] Challenge { get; private set; } + + protected SecureAttribute() + { + UniqueID = Guid.NewGuid(); + } + protected SecureAttribute(String label) + :this() + { + Label = label; + } + + public abstract String GetAuthenticationParameters(); + public abstract bool Authenticate(byte[] challenge, byte[] prove); + + public virtual byte[] CreateChallenge() + { + Challenge = new byte[32]; + Random.NextBytes(Challenge); + return Challenge; + } + + public string GetAttributeTypeName() => this.GetType().Name; + + } +} diff --git a/SeededPassword.cs b/SeededPassword.cs new file mode 100644 index 0000000..f044fcb --- /dev/null +++ b/SeededPassword.cs @@ -0,0 +1,61 @@ +using System; +using System.Security.Cryptography; +using System.Text; +using System.Linq; +using ln.types; +namespace ln.identities +{ + public class SeededPassword : SecureAttribute + { + public byte[] Seed { get; } + + byte[] secretBytes; + + private SeededPassword() { } + + public SeededPassword(byte[] seed,byte[] secretBytes) + :base("Passwort") + { + this.Seed = seed; + this.secretBytes = secretBytes; + } + public SeededPassword(string password) + :base("Passwort") + { + Seed = new byte[32]; + Random.NextBytes(Seed); + + using (SHA256 sha256 = SHA256.Create()) + { + byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + Console.WriteLine("PasswordBytes={0}", passwordBytes.ToHexString()); + Console.WriteLine("Seed={0}", Seed.ToHexString()); + + sha256.TransformBlock(Seed, 0, Seed.Length, null, 0); + sha256.TransformBlock(passwordBytes, 0, passwordBytes.Length, null, 0); + sha256.TransformFinalBlock(Seed, 0, Seed.Length); + + secretBytes = sha256.Hash; + Console.WriteLine("SecretBytes={0}", secretBytes.ToHexString()); + } + } + + public override bool Authenticate(byte[] challenge,byte[] prove) + { + if (!Challenge.AreEqual(challenge)) + return false; + + using (SHA256 sha256 = SHA256.Create()) + { + sha256.TransformBlock(Challenge, 0, Challenge.Length, null, 0); + sha256.TransformBlock(secretBytes, 0, secretBytes.Length, null, 0); + sha256.TransformFinalBlock(Challenge, 0, Challenge.Length); + + byte[] myProve = sha256.Hash; + return myProve.AreEqual(prove); + } + } + + public override string GetAuthenticationParameters() => Seed.ToHexString(); + } +} diff --git a/ln.identities.csproj b/ln.identities.csproj new file mode 100644 index 0000000..5ec3d49 --- /dev/null +++ b/ln.identities.csproj @@ -0,0 +1,53 @@ + + + + Debug + AnyCPU + {AA1F75AF-0AEC-4CC0-AC3B-209AE90781AC} + Library + ln.identities + ln.identities + v4.7 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + {8D9AB9A5-E513-4BA7-A450-534F6456BF28} + ln.types + + + + \ No newline at end of file