Taylohtio/GeneralSSO/GeneralSSO.Server/CodeFiles/Infrastructure/OAuth/DataStore.cs

118 lines
4.9 KiB
C#

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<ISymmetricCryptoKeyRepository>();
this.nonceRepository = ServiceLocator.Current.GetInstance<INonceRepository>();
}
/// <summary>
/// Stores a given nonce and timestamp.
/// </summary>
/// <param name="context">The context, or namespace, within which the
/// <paramref name="nonce"/> must be unique.
/// The context SHOULD be treated as case-sensitive.
/// The value will never be <c>null</c> but may be the empty string.</param>
/// <param name="nonce">A series of random characters.</param>
/// <param name="timestampUtc">The UTC timestamp that together with the nonce string make it unique
/// within the given <paramref name="context"/>.
/// The timestamp may also be used by the data store to clear out old nonces.</param>
/// <returns>
/// 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.
/// </returns>
/// <remarks>
/// 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
/// <see cref="DotNetOpenAuth.Configuration.MessagingElement.MaximumMessageLifetime"/>
/// property, accessible via the <see cref="DotNetOpenAuth.Configuration.DotNetOpenAuthSection.Configuration"/>
/// property.
/// </remarks>
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<KeyValuePair<string, CryptoKey>> GetKeys(string bucket)
{
// return from key in ServerContext.DataContext.SymmetricCryptoKeys
// where key.Bucket == bucket
// orderby key.ExpiresUtc descending
// select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()));
var keys = this.keyRepository.GetByOrderedByExpirationDesc(bucket);
if (keys.IsNullOrEmpty())
{
return new List<KeyValuePair<string, CryptoKey>>();
}
return keys.Select(k => new KeyValuePair<string, CryptoKey>(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);
}
}
}
}