/// <summary>
        /// Creates the association at the provider side after the association request has been received.
        /// </summary>
        /// <param name="request">The association request.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>The newly created association.</returns>
        /// <remarks>
        /// The response message is updated to include the details of the created association by this method,
        /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.
        /// </remarks>
        protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(request, "request");
            var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;
            ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, "request");
            ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");

            this.SessionType = this.SessionType ?? request.SessionType;

            // Go ahead and create the association first, complete with its secret that we're about to share.
            Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings);

            // We now need to securely communicate the secret to the relying party using Diffie-Hellman.
            // We do this by performing a DH algorithm on the secret and setting a couple of properties
            // that will be transmitted to the Relying Party.  The RP will perform an inverse operation
            // using its part of a DH secret in order to decrypt the shared secret we just invented
            // above when we created the association.
            DiffieHellman dh = new DiffieHellmanManaged(
                diffieHellmanRequest.DiffieHellmanModulus ?? AssociateDiffieHellmanRequest.DefaultMod,
                diffieHellmanRequest.DiffieHellmanGen ?? AssociateDiffieHellmanRequest.DefaultGen,
                AssociateDiffieHellmanRequest.DefaultX);
            HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(this.Protocol, this.SessionType);
            this.DiffieHellmanServerPublic = DiffieHellmanUtilities.EnsurePositive(dh.CreateKeyExchange());
            this.EncodedMacKey = DiffieHellmanUtilities.SHAHashXorSecret(hasher, dh, diffieHellmanRequest.DiffieHellmanConsumerPublic, association.SecretKey);

            return association;
        }
		/// <summary>
		/// Creates the association at relying party side after the association response has been received.
		/// </summary>
		/// <param name="request">The original association request that was already sent and responded to.</param>
		/// <returns>The newly created association.</returns>
		/// <remarks>
		/// The resulting association is <i>not</i> added to the association store and must be done by the caller.
		/// </remarks>
		protected override Association CreateAssociationAtRelyingParty(AssociateRequest request) {
			var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;
			ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, "request");

			HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(Protocol, this.SessionType);
			byte[] associationSecret = DiffieHellmanUtilities.SHAHashXorSecret(hasher, diffieHellmanRequest.Algorithm, this.DiffieHellmanServerPublic, this.EncodedMacKey);

			Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, this.AssociationHandle, associationSecret, TimeSpan.FromSeconds(this.ExpiresIn));
			return association;
		}
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <param name="response">The response.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings for the Provider.  Should be <c>null</c> for Relying Parties.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		/// <remarks>
		/// The response message is updated to include the details of the created association by this method.
		/// This method is called by both the Provider and the Relying Party, but actually performs
		/// quite different operations in either scenario.
		/// </remarks>
		internal static Association CreateAssociation(AssociateRequest request, IAssociateSuccessfulResponseProvider response, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(request, "request");
			Requires.NotNull(response, "response");
			Requires.NotNull(securitySettings, "securitySettings");

			// We need to initialize some common properties based on the created association.
			var association = response.CreateAssociationAtProvider(request, associationStore, securitySettings);
			response.ExpiresIn = association.SecondsTillExpiration;
			response.AssociationHandle = association.Handle;

			return association;
		}
		public void ValidMessageTest() {
			this.request = new AssociateUnencryptedRequest(Protocol.V20.Version, this.secureRecipient);
			this.request.AssociationType = this.protocol.Args.SignatureAlgorithm.HMAC_SHA1;
			this.request.EnsureValidMessage();
		}
		public void Setup() {
			this.request = new AssociateUnencryptedRequest(this.protocol.Version, this.secureRecipient);
		}
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings of the Provider.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		/// <remarks>
		///   <para>The caller will update this message's
		///   <see cref="AssociateSuccessfulResponse.ExpiresIn"/> and
		///   <see cref="AssociateSuccessfulResponse.AssociationHandle"/>
		/// properties based on the <see cref="Association"/> returned by this method, but any other
		/// association type specific properties must be set by this method.</para>
		///   <para>The response message is updated to include the details of the created association by this method,
		/// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
		/// </remarks>
		public Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Association association = HmacShaAssociationProvider.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings);
			this.MacKey = association.SecretKey;
			return association;
		}
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		Association IAssociateSuccessfulResponseRelyingParty.CreateAssociationAtRelyingParty(AssociateRequest request) {
			Requires.NotNull(request, "request");
			throw new NotImplementedException();
		}
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <returns>The created association.</returns>
		public Association CreateAssociationAtRelyingParty(AssociateRequest request) {
			Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, this.AssociationHandle, this.MacKey, TimeSpan.FromSeconds(this.ExpiresIn));
			return association;
		}
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <returns>The created association.</returns>
 protected abstract Association CreateAssociationAtRelyingParty(AssociateRequest request);
        /// <summary>
        /// Creates a new association with a given Provider.
        /// </summary>
        /// <param name="provider">The provider to create an association with.</param>
        /// <param name="associateRequest">The associate request.  May be <c>null</c>, which will always result in a <c>null</c> return value..</param>
        /// <param name="retriesRemaining">The number of times to try the associate request again if the Provider suggests it.</param>
        /// <returns>
        /// The newly created association, or null if no association can be created with
        /// the given Provider given the current security settings.
        /// </returns>
        private Association CreateNewAssociation(ProviderEndpointDescription provider, AssociateRequest associateRequest, int retriesRemaining)
        {
            ErrorUtilities.VerifyArgumentNotNull(provider, "provider");

            if (associateRequest == null || retriesRemaining < 0) {
                // this can happen if security requirements and protocol conflict
                // to where there are no association types to choose from.
                return null;
            }

            try {
                var associateResponse = this.channel.Request(associateRequest);
                var associateSuccessfulResponse = associateResponse as AssociateSuccessfulResponse;
                var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse;
                if (associateSuccessfulResponse != null) {
                    Association association = associateSuccessfulResponse.CreateAssociation(associateRequest, null);
                    this.associationStore.StoreAssociation(provider.Endpoint, association);
                    return association;
                } else if (associateUnsuccessfulResponse != null) {
                    if (string.IsNullOrEmpty(associateUnsuccessfulResponse.AssociationType)) {
                        Logger.OpenId.Debug("Provider rejected an association request and gave no suggestion as to an alternative association type.  Giving up.");
                        return null;
                    }

                    if (!this.securitySettings.IsAssociationInPermittedRange(Protocol.Lookup(provider.ProtocolVersion), associateUnsuccessfulResponse.AssociationType)) {
                        Logger.OpenId.DebugFormat("Provider rejected an association request and suggested '{0}' as an association to try, which this Relying Party does not support.  Giving up.", associateUnsuccessfulResponse.AssociationType);
                        return null;
                    }

                    if (retriesRemaining <= 0) {
                        Logger.OpenId.Debug("Unable to agree on an association type with the Provider in the allowed number of retries.  Giving up.");
                        return null;
                    }

                    // Make sure the Provider isn't suggesting an incompatible pair of association/session types.
                    Protocol protocol = Protocol.Lookup(provider.ProtocolVersion);
                    ErrorUtilities.VerifyProtocol(
                        HmacShaAssociation.IsDHSessionCompatible(protocol, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType),
                        OpenIdStrings.IncompatibleAssociationAndSessionTypes,
                        associateUnsuccessfulResponse.AssociationType,
                        associateUnsuccessfulResponse.SessionType);

                    associateRequest = AssociateRequest.Create(this.securitySettings, provider, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType);
                    return this.CreateNewAssociation(provider, associateRequest, retriesRemaining - 1);
                } else {
                    throw new ProtocolException(MessagingStrings.UnexpectedMessageReceivedOfMany);
                }
            } catch (ProtocolException ex) {
                // If the association failed because the remote server can't handle Expect: 100 Continue headers,
                // then our web request handler should have already accomodated for future calls.  Go ahead and
                // immediately make one of those future calls now to try to get the association to succeed.
                if (StandardWebRequestHandler.IsExceptionFrom417ExpectationFailed(ex)) {
                    return this.CreateNewAssociation(provider, associateRequest, retriesRemaining - 1);
                }

                // Since having associations with OPs is not totally critical, we'll log and eat
                // the exception so that auth may continue in dumb mode.
                Logger.OpenId.ErrorFormat("An error occurred while trying to create an association with {0}.  {1}", provider.Endpoint, ex);
                return null;
            }
        }
		protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings) {
			Contract.Requires<ArgumentNullException>(request != null);
			Contract.Requires<ArgumentNullException>(securitySettings != null);
			throw new NotImplementedException();
		}
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <returns>The created association.</returns>
 protected abstract Association CreateAssociationAtRelyingParty(AssociateRequest request);
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <param name="securitySettings">The security settings of the Provider.</param>
 /// <returns>The created association.</returns>
 /// <remarks>
 /// 	<para>The caller will update this message's <see cref="ExpiresIn"/> and <see cref="AssociationHandle"/>
 /// properties based on the <see cref="Association"/> returned by this method, but any other
 /// association type specific properties must be set by this method.</para>
 /// 	<para>The response message is updated to include the details of the created association by this method,
 /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
 /// </remarks>
 protected abstract Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings);
        /// <summary>
        /// Called to create the Association based on a request previously given by the Relying Party.
        /// </summary>
        /// <param name="request">The prior request for an association.</param>
        /// <param name="securitySettings">The security settings for the Provider.  Should be <c>null</c> for Relying Parties.</param>
        /// <returns>The created association.</returns>
        /// <remarks>
        /// 	<para>The response message is updated to include the details of the created association by this method,
        /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
        /// 	<para>This method is called by both the Provider and the Relying Party, but actually performs
        /// quite different operations in either scenario.</para>
        /// </remarks>
        internal Association CreateAssociation(AssociateRequest request, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(request, "request");
            ErrorUtilities.VerifyInternal(!this.associationCreated, "The association has already been created.");

            Association association;

            // If this message is outgoing, then we need to initialize some common
            // properties based on the created association.
            if (this.Incoming) {
                association = this.CreateAssociationAtRelyingParty(request);
            } else {
                ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");
                association = this.CreateAssociationAtProvider(request, securitySettings);
                this.ExpiresIn = association.SecondsTillExpiration;
                this.AssociationHandle = association.Handle;
            }

            this.associationCreated = true;

            return association;
        }
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <param name="securitySettings">The security settings of the Provider.</param>
 /// <returns>The created association.</returns>
 /// <remarks>
 /// 	<para>The caller will update this message's
 /// <see cref="AssociateSuccessfulResponse.ExpiresIn"/> and
 /// <see cref="AssociateSuccessfulResponse.AssociationHandle"/>
 /// properties based on the <see cref="Association"/> returned by this method, but any other
 /// association type specific properties must be set by this method.</para>
 /// 	<para>The response message is updated to include the details of the created association by this method,
 /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
 /// </remarks>
 protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings)
 {
     Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings);
     this.MacKey = association.SecretKey;
     return association;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="AssociateSuccessfulResponse"/> class.
 /// </summary>
 /// <param name="responseVersion">The OpenID version of the response message.</param>
 /// <param name="originatingRequest">The originating request.</param>
 internal AssociateSuccessfulResponse(Version responseVersion, AssociateRequest originatingRequest)
     : base(responseVersion, originatingRequest)
 {
 }
		public void InvalidMessageTest() {
			this.request = new AssociateUnencryptedRequest(Protocol.V20.Version, this.insecureRecipient);
			this.request.AssociationType = this.protocol.Args.SignatureAlgorithm.HMAC_SHA1;
			this.request.EnsureValidMessage(); // no-encryption only allowed for secure channels.
		}
#pragma warning restore 0414

		/// <summary>
		/// Initializes a new instance of the <see cref="AssociateUnsuccessfulResponse"/> class.
		/// </summary>
		/// <param name="responseVersion">The OpenID version of the response message.</param>
		/// <param name="originatingRequest">The originating request.</param>
		internal AssociateUnsuccessfulResponse(Version responseVersion, AssociateRequest originatingRequest)
			: base(responseVersion, originatingRequest) {
			this.ErrorMessage = string.Format(CultureInfo.CurrentCulture, OpenIdStrings.AssociationOrSessionTypeUnrecognizedOrNotSupported, originatingRequest.AssociationType, originatingRequest.SessionType);
		}
#pragma warning restore 0414

        /// <summary>
        /// Initializes a new instance of the <see cref="AssociateUnsuccessfulResponse"/> class.
        /// </summary>
        /// <param name="responseVersion">The OpenID version of the response message.</param>
        /// <param name="originatingRequest">The originating request.</param>
        internal AssociateUnsuccessfulResponse(Version responseVersion, AssociateRequest originatingRequest)
            : base(responseVersion, originatingRequest)
        {
            this.ErrorMessage = string.Format(CultureInfo.CurrentCulture, OpenIdStrings.AssociationOrSessionTypeUnrecognizedOrNotSupported, originatingRequest.AssociationType, originatingRequest.SessionType);
        }
		protected override Association CreateAssociationAtRelyingParty(AssociateRequest request) {
			Contract.Requires<ArgumentNullException>(request != null);
			throw new NotImplementedException();
		}
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <param name="securitySettings">The security settings of the Provider.</param>
 /// <returns>The created association.</returns>
 /// <remarks>
 ///     <para>The caller will update this message's <see cref="ExpiresIn"/> and <see cref="AssociationHandle"/>
 /// properties based on the <see cref="Association"/> returned by this method, but any other
 /// association type specific properties must be set by this method.</para>
 ///     <para>The response message is updated to include the details of the created association by this method,
 /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
 /// </remarks>
 protected abstract Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings);
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings of the Provider.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		Association IAssociateSuccessfulResponseProvider.CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(request, "request");
			Requires.NotNull(associationStore, "associationStore");
			Requires.NotNull(securitySettings, "securitySettings");
			throw new NotImplementedException();
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="AssociateSuccessfulResponse"/> class.
		/// </summary>
		/// <param name="responseVersion">The OpenID version of the response message.</param>
		/// <param name="originatingRequest">The originating request.</param>
		internal AssociateSuccessfulResponse(Version responseVersion, AssociateRequest originatingRequest)
			: base(responseVersion, originatingRequest) {
		}