diff options
Diffstat (limited to 'src/DotNetOpenAuth.OpenId/OpenId/Provider/ProviderAssociationHandleEncoder.cs')
-rw-r--r-- | src/DotNetOpenAuth.OpenId/OpenId/Provider/ProviderAssociationHandleEncoder.cs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Provider/ProviderAssociationHandleEncoder.cs b/src/DotNetOpenAuth.OpenId/OpenId/Provider/ProviderAssociationHandleEncoder.cs new file mode 100644 index 0000000..5de560c --- /dev/null +++ b/src/DotNetOpenAuth.OpenId/OpenId/Provider/ProviderAssociationHandleEncoder.cs @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------- +// <copyright file="ProviderAssociationHandleEncoder.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Provider { + using System; + using System.Diagnostics.Contracts; + using System.Threading; + using DotNetOpenAuth.Configuration; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.Messaging.Bindings; + + /// <summary> + /// Provides association storage in the association handle itself, but embedding signed and encrypted association + /// details in the handle. + /// </summary> + public class ProviderAssociationHandleEncoder : IProviderAssociationStore { + /// <summary> + /// The name of the bucket in which to store keys that encrypt association data into association handles. + /// </summary> + internal const string AssociationHandleEncodingSecretBucket = "https://localhost/dnoa/association_handles"; + + /// <summary> + /// The crypto key store used to persist encryption keys. + /// </summary> + private readonly ICryptoKeyStore cryptoKeyStore; + + /// <summary> + /// Initializes a new instance of the <see cref="ProviderAssociationHandleEncoder"/> class. + /// </summary> + /// <param name="cryptoKeyStore">The crypto key store.</param> + public ProviderAssociationHandleEncoder(ICryptoKeyStore cryptoKeyStore) { + Contract.Requires<ArgumentNullException>(cryptoKeyStore != null); + this.cryptoKeyStore = cryptoKeyStore; + } + + /// <summary> + /// Encodes the specified association data bag. + /// </summary> + /// <param name="secret">The symmetric secret.</param> + /// <param name="expiresUtc">The UTC time that the association should expire.</param> + /// <param name="privateAssociation">A value indicating whether this is a private association.</param> + /// <returns> + /// The association handle that represents this association. + /// </returns> + public string Serialize(byte[] secret, DateTime expiresUtc, bool privateAssociation) { + var associationDataBag = new AssociationDataBag { + Secret = secret, + IsPrivateAssociation = privateAssociation, + ExpiresUtc = expiresUtc, + }; + + var formatter = AssociationDataBag.CreateFormatter(this.cryptoKeyStore, AssociationHandleEncodingSecretBucket, expiresUtc - DateTime.UtcNow); + return formatter.Serialize(associationDataBag); + } + + /// <summary> + /// Retrieves an association given an association handle. + /// </summary> + /// <param name="containingMessage">The OpenID message that referenced this association handle.</param> + /// <param name="privateAssociation">A value indicating whether a private association is expected.</param> + /// <param name="handle">The association handle.</param> + /// <returns> + /// An association instance, or <c>null</c> if the association has expired or the signature is incorrect (which may be because the OP's symmetric key has changed). + /// </returns> + /// <exception cref="ProtocolException">Thrown if the association is not of the expected type.</exception> + public Association Deserialize(IProtocolMessage containingMessage, bool privateAssociation, string handle) { + var formatter = AssociationDataBag.CreateFormatter(this.cryptoKeyStore, AssociationHandleEncodingSecretBucket); + AssociationDataBag bag; + try { + bag = formatter.Deserialize(containingMessage, handle); + } catch (ProtocolException ex) { + Logger.OpenId.Error("Rejecting an association because deserialization of the encoded handle failed.", ex); + return null; + } + + ErrorUtilities.VerifyProtocol(bag.IsPrivateAssociation == privateAssociation, "Unexpected association type."); + Association assoc = Association.Deserialize(handle, bag.ExpiresUtc, bag.Secret); + return assoc.IsExpired ? null : assoc; + } + } +} |