using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using DotNetOpenAuth.Messaging.Bindings; using Microsoft.Practices.ServiceLocation; using Taloyhtio.GeneralSSO.Server.CodeFiles.Common; using Taloyhtio.GeneralSSO.Server.CodeFiles.Entities; using Taloyhtio.GeneralSSO.Server.CodeFiles.Repositories; namespace Taloyhtio.GeneralSSO.Server.CodeFiles.Infrastructure.OAuth { public class DataStore : INonceStore, ICryptoKeyStore { private ISymmetricCryptoKeyRepository keyRepository; private INonceRepository nonceRepository; public DataStore() { this.keyRepository = ServiceLocator.Current.GetInstance(); this.nonceRepository = ServiceLocator.Current.GetInstance(); } /// /// Stores a given nonce and timestamp. /// /// The context, or namespace, within which the /// must be unique. /// The context SHOULD be treated as case-sensitive. /// The value will never be null but may be the empty string. /// A series of random characters. /// The UTC timestamp that together with the nonce string make it unique /// within the given . /// The timestamp may also be used by the data store to clear out old nonces. /// /// True if the context+nonce+timestamp (combination) was not previously in the database. /// False if the nonce was stored previously with the same timestamp and context. /// /// /// The nonce must be stored for no less than the maximum time window a message may /// be processed within before being discarded as an expired message. /// This maximum message age can be looked up via the /// /// property, accessible via the /// property. /// public bool StoreNonce(string context, string code, DateTime timestampUtc) { try { if (this.nonceRepository.Exists(context, code, timestampUtc)) { // possibly replay attack, return false return false; } this.nonceRepository.Save(new Nonce { Context = context, Code = code, Timestamp = timestampUtc }); return true; } catch { return false; } } public CryptoKey GetKey(string bucket, string handle) { var key = this.keyRepository.GetBy(bucket, handle); if (key == null) { return null; } return new CryptoKey(key.Secret, key.ExpirationDate); } public IEnumerable> GetKeys(string bucket) { // return from key in ServerContext.DataContext.SymmetricCryptoKeys // where key.Bucket == bucket // orderby key.ExpiresUtc descending // select new KeyValuePair(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())); var keys = this.keyRepository.GetByOrderedByExpirationDesc(bucket); if (keys.IsNullOrEmpty()) { return new List>(); } return keys.Select(k => new KeyValuePair(k.Handle, new CryptoKey(k.Secret, k.ExpirationDate.AsUtc()))); } public void StoreKey(string bucket, string handle, CryptoKey key) { var keyRow = new SymmetricCryptoKey() { Bucket = bucket, Handle = handle, Secret = key.Key, ExpirationDate = key.ExpiresUtc, }; // ServerContext.DataContext.SymmetricCryptoKeys.InsertOnSubmit(keyRow); // ServerContext.DataContext.SubmitChanges(); this.keyRepository.Save(keyRow); } public void RemoveKey(string bucket, string handle) { // var match = ServerContext.DataContext.SymmetricCryptoKeys.FirstOrDefault(k => k.Bucket == bucket && k.Handle == handle); // if (match != null) // { // ServerContext.DataContext.SymmetricCryptoKeys.DeleteOnSubmit(match); // } var key = this.keyRepository.GetBy(bucket, handle); if (key != null) { this.keyRepository.Delete(key); } } } }