diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2011-05-28 17:31:20 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2011-05-28 17:31:20 -0700 |
commit | dbbc823b7580d4e7d5251539a8dcace730df2e3f (patch) | |
tree | 52489fda9952d9aa7ccd59fab795e6862e24753b /projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs | |
parent | bb155ca75f8906bde74d8adbf36fa4f4c4bcded7 (diff) | |
parent | 5ea256fa7309ad23f4278ef9113ccde5a231bff7 (diff) | |
download | DotNetOpenAuth-dbbc823b7580d4e7d5251539a8dcace730df2e3f.zip DotNetOpenAuth-dbbc823b7580d4e7d5251539a8dcace730df2e3f.tar.gz DotNetOpenAuth-dbbc823b7580d4e7d5251539a8dcace730df2e3f.tar.bz2 |
Introduced ICryptoKeyStore, and worked it into OpenID OPs, RPs, and OAuth 2.0 roles.
Diffstat (limited to 'projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs')
-rw-r--r-- | projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs | 130 |
1 files changed, 33 insertions, 97 deletions
diff --git a/projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs b/projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs index e13633a..90a5544 100644 --- a/projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs +++ b/projecttemplates/RelyingPartyLogic/RelyingPartyApplicationDbStore.cs @@ -9,120 +9,73 @@ namespace RelyingPartyLogic { using System.Collections.Generic; using System.Data; using System.Linq; - using System.Text; + using DotNetOpenAuth; + using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.OpenId; - using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// A database-backed state store for OpenID relying parties. /// </summary> - public class RelyingPartyApplicationDbStore : NonceDbStore, IRelyingPartyApplicationStore { + public class RelyingPartyApplicationDbStore : NonceDbStore, IOpenIdApplicationStore { /// <summary> /// Initializes a new instance of the <see cref="RelyingPartyApplicationDbStore"/> class. /// </summary> public RelyingPartyApplicationDbStore() { } - #region IAssociationStore<Uri> Members + #region ICryptoStore Members - /// <summary> - /// Saves an <see cref="Association"/> for later recall. - /// </summary> - /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for providers).</param> - /// <param name="association">The association to store.</param> - /// <remarks> - /// TODO: what should implementations do on association handle conflict? - /// </remarks> - public void StoreAssociation(Uri distinguishingFactor, Association association) { + public CryptoKey GetKey(string bucket, string handle) { using (var dataContext = new TransactedDatabaseEntities(System.Data.IsolationLevel.ReadCommitted)) { - var sharedAssociation = new OpenIdAssociation { - DistinguishingFactor = distinguishingFactor.AbsoluteUri, - AssociationHandle = association.Handle, - ExpirationUtc = association.Expires, - PrivateData = association.SerializePrivateData(), - }; - - dataContext.AddToOpenIdAssociations(sharedAssociation); + var associations = from assoc in dataContext.SymmetricCryptoKeys + where assoc.Bucket == bucket + where assoc.Handle == handle + where assoc.ExpirationUtc > DateTime.UtcNow + select assoc; + return associations.AsEnumerable() + .Select(assoc => new CryptoKey(assoc.Secret, assoc.ExpirationUtc.AsUtc())) + .FirstOrDefault(); } } - /// <summary> - /// Gets the best association (the one with the longest remaining life) for a given key. - /// </summary> - /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param> - /// <param name="securityRequirements">The security requirements that the returned association must meet.</param> - /// <returns> - /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key. - /// </returns> - /// <remarks> - /// In the event that multiple associations exist for the given - /// <paramref name="distinguishingFactor"/>, it is important for the - /// implementation for this method to use the <paramref name="securityRequirements"/> - /// to pick the best (highest grade or longest living as the host's policy may dictate) - /// association that fits the security requirements. - /// Associations that are returned that do not meet the security requirements will be - /// ignored and a new association created. - /// </remarks> - public Association GetAssociation(Uri distinguishingFactor, SecuritySettings securityRequirements) { + public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) { using (var dataContext = new TransactedDatabaseEntities(System.Data.IsolationLevel.ReadCommitted)) { - var relevantAssociations = from assoc in dataContext.OpenIdAssociations - where assoc.DistinguishingFactor == distinguishingFactor.AbsoluteUri + var relevantAssociations = from assoc in dataContext.SymmetricCryptoKeys + where assoc.Bucket == bucket where assoc.ExpirationUtc > DateTime.UtcNow - where assoc.PrivateDataLength * 8 >= securityRequirements.MinimumHashBitLength - where assoc.PrivateDataLength * 8 <= securityRequirements.MaximumHashBitLength orderby assoc.ExpirationUtc descending select assoc; var qualifyingAssociations = relevantAssociations.AsEnumerable() - .Select(assoc => DeserializeAssociation(assoc)); - return qualifyingAssociations.FirstOrDefault(); + .Select(assoc => new KeyValuePair<string, CryptoKey>(assoc.Handle, new CryptoKey(assoc.Secret, assoc.ExpirationUtc.AsUtc()))); + return qualifyingAssociations.ToList(); // the data context is closing, so we must cache the result. } } - /// <summary> - /// Gets the association for a given key and handle. - /// </summary> - /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param> - /// <param name="handle">The handle of the specific association that must be recalled.</param> - /// <returns> - /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key and handle. - /// </returns> - public Association GetAssociation(Uri distinguishingFactor, string handle) { + public void StoreKey(string bucket, string handle, CryptoKey key) { using (var dataContext = new TransactedDatabaseEntities(System.Data.IsolationLevel.ReadCommitted)) { - var associations = from assoc in dataContext.OpenIdAssociations - where assoc.DistinguishingFactor == distinguishingFactor.AbsoluteUri - where assoc.AssociationHandle == handle - where assoc.ExpirationUtc > DateTime.UtcNow - select assoc; - return associations.AsEnumerable() - .Select(assoc => DeserializeAssociation(assoc)) - .FirstOrDefault(); + var sharedAssociation = new SymmetricCryptoKey { + Bucket = bucket, + Handle = handle, + ExpirationUtc = key.ExpiresUtc, + Secret = key.Key, + }; + + dataContext.AddToSymmetricCryptoKeys(sharedAssociation); } } - /// <summary> - /// Removes a specified handle that may exist in the store. - /// </summary> - /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param> - /// <param name="handle">The handle of the specific association that must be deleted.</param> - /// <returns> - /// True if the association existed in this store previous to this call. - /// </returns> - /// <remarks> - /// No exception should be thrown if the association does not exist in the store - /// before this call. - /// </remarks> - public bool RemoveAssociation(Uri distinguishingFactor, string handle) { + public void RemoveKey(string bucket, string handle) { using (var dataContext = new TransactedDatabaseEntities(System.Data.IsolationLevel.ReadCommitted)) { - var association = dataContext.OpenIdAssociations.FirstOrDefault(a => a.DistinguishingFactor == distinguishingFactor.AbsoluteUri && a.AssociationHandle == handle); + var association = dataContext.SymmetricCryptoKeys.FirstOrDefault(a => a.Bucket == bucket && a.Handle == handle); if (association != null) { dataContext.DeleteObject(association); - return true; } else { - return false; } } } + #endregion + /// <summary> /// Clears all expired associations from the store. /// </summary> @@ -132,27 +85,10 @@ namespace RelyingPartyLogic { /// This should be done frequently enough to avoid a memory leak, but sparingly enough /// to not be a performance drain. /// </remarks> - public void ClearExpiredAssociations() { + internal void ClearExpiredCryptoKeys() { using (var dataContext = new TransactedDatabaseEntities(IsolationLevel.ReadCommitted)) { - dataContext.ClearExpiredAssociations(dataContext.Transaction); + dataContext.ClearExpiredCryptoKeys(dataContext.Transaction); } } - - #endregion - - /// <summary> - /// Deserializes an association from the database. - /// </summary> - /// <param name="association">The association from the database.</param> - /// <returns>The deserialized association.</returns> - private static Association DeserializeAssociation(OpenIdAssociation association) { - if (association == null) { - throw new ArgumentNullException("association"); - } - - byte[] privateData = new byte[association.PrivateDataLength]; - Array.Copy(association.PrivateData, privateData, association.PrivateDataLength); - return Association.Deserialize(association.AssociationHandle, association.ExpirationUtc, privateData); - } } } |