commit 52588d66d57dcbf9972911d6d1787994eb3687c8 Author: Harald Wolff Date: Fri Nov 15 13:49:21 2019 +0100 Initial Commit 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