/// <summary>
        /// Creates a response that notifies the Relying Party that the requested
        /// association type is not supported by this Provider, and offers
        /// an alternative association type, if possible.
        /// </summary>
        /// <param name="requestMessage">The request message.</param>
        /// <param name="securitySettings">The security settings that apply to this Provider.</param>
        /// <returns>
        /// The response to send to the Relying Party.
        /// </returns>
        private static AssociateUnsuccessfulResponse CreateUnsuccessfulResponse(IAssociateRequestProvider requestMessage, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(requestMessage, "requestMessage");
            Requires.NotNull(securitySettings, "securitySettings");

            var unsuccessfulResponse = new AssociateUnsuccessfulResponse(requestMessage.Version, (AssociateRequest)requestMessage);

            // The strategy here is to suggest that the RP try again with the lowest
            // permissible security settings, giving the RP the best chance of being
            // able to match with a compatible request.
            bool   unencryptedAllowed = requestMessage.Recipient.IsTransportSecure();
            bool   useDiffieHellman = !unencryptedAllowed;
            var    request = (AssociateRequest)requestMessage;
            var    protocol = requestMessage.GetProtocol();
            string associationType, sessionType;

            if (HmacShaAssociation.TryFindBestAssociation(protocol, false, securitySettings, useDiffieHellman, out associationType, out sessionType))
            {
                ErrorUtilities.VerifyInternal(request.AssociationType != associationType, "The RP asked for an association that should have been allowed, but the OP is trying to suggest the same one as an alternative!");
                unsuccessfulResponse.AssociationType = associationType;
                unsuccessfulResponse.SessionType     = sessionType;
                Logger.OpenId.InfoFormat(
                    "Association requested of type '{0}' and session '{1}', which the Provider does not support.  Sending back suggested alternative of '{0}' with session '{1}'.",
                    request.AssociationType,
                    request.SessionType,
                    unsuccessfulResponse.AssociationType,
                    unsuccessfulResponse.SessionType);
            }
            else
            {
                Logger.OpenId.InfoFormat("Association requested of type '{0}' and session '{1}', which the Provider does not support.  No alternative association type qualified for suggesting back to the Relying Party.", request.AssociationType, request.SessionType);
            }

            return(unsuccessfulResponse);
        }
		/// <summary>
		/// Creates a response that notifies the Relying Party that the requested
		/// association type is not supported by this Provider, and offers
		/// an alternative association type, if possible.
		/// </summary>
		/// <param name="requestMessage">The request message.</param>
		/// <param name="securitySettings">The security settings that apply to this Provider.</param>
		/// <returns>
		/// The response to send to the Relying Party.
		/// </returns>
		private static AssociateUnsuccessfulResponse CreateUnsuccessfulResponse(IAssociateRequestProvider requestMessage, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(requestMessage, "requestMessage");
			Requires.NotNull(securitySettings, "securitySettings");

			var unsuccessfulResponse = new AssociateUnsuccessfulResponse(requestMessage.Version, (AssociateRequest)requestMessage);

			// The strategy here is to suggest that the RP try again with the lowest
			// permissible security settings, giving the RP the best chance of being
			// able to match with a compatible request.
			bool unencryptedAllowed = requestMessage.Recipient.IsTransportSecure();
			bool useDiffieHellman = !unencryptedAllowed;
			var request = (AssociateRequest)requestMessage;
			var protocol = requestMessage.GetProtocol();
			string associationType, sessionType;
			if (HmacShaAssociation.TryFindBestAssociation(protocol, false, securitySettings, useDiffieHellman, out associationType, out sessionType)) {
				ErrorUtilities.VerifyInternal(request.AssociationType != associationType, "The RP asked for an association that should have been allowed, but the OP is trying to suggest the same one as an alternative!");
				unsuccessfulResponse.AssociationType = associationType;
				unsuccessfulResponse.SessionType = sessionType;
				Logger.OpenId.InfoFormat(
					"Association requested of type '{0}' and session '{1}', which the Provider does not support.  Sending back suggested alternative of '{0}' with session '{1}'.",
					request.AssociationType,
					request.SessionType,
					unsuccessfulResponse.AssociationType,
					unsuccessfulResponse.SessionType);
			} else {
				Logger.OpenId.InfoFormat("Association requested of type '{0}' and session '{1}', which the Provider does not support.  No alternative association type qualified for suggesting back to the Relying Party.", request.AssociationType, request.SessionType);
			}

			return unsuccessfulResponse;
		}
		public void RPOnlyRenegotiatesOnce() {
			Protocol protocol = Protocol.V20;
			OpenIdCoordinator coordinator = new OpenIdCoordinator(
				rp => {
					var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version));
					Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves.");
				},
				op => {
					// Receive initial request.
					var request = op.Channel.ReadFromRequest<AssociateRequest>();

					// Send a renegotiate response
					AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
					renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
					renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA1;
					op.Channel.Respond(renegotiateResponse);

					// Receive second-try
					request = op.Channel.ReadFromRequest<AssociateRequest>();

					// Send ANOTHER renegotiate response, at which point the DNOI RP should give up.
					renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
					renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256;
					renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256;
					op.Channel.Respond(renegotiateResponse);
				});
			coordinator.Run();
		}
		public void RPRejectsMismatchingAssociationAndSessionBitLengths() {
			Protocol protocol = Protocol.V20;
			OpenIdCoordinator coordinator = new OpenIdCoordinator(
				rp => {
					var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version));
					Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves.");
				},
				op => {
					// Receive initial request.
					var request = op.Channel.ReadFromRequest<AssociateRequest>();

					// Send a mismatched response
					AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
					renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
					renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256;
					op.Channel.Respond(renegotiateResponse);
				});
			coordinator.Run();
		}
		public void RPRejectsUnrecognizedAssociationType() {
			Protocol protocol = Protocol.V20;
			OpenIdCoordinator coordinator = new OpenIdCoordinator(
				rp => {
					var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version));
					Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves.");
				},
				op => {
					// Receive initial request.
					var request = op.Channel.ReadFromRequest<AssociateRequest>();

					// Send a response that suggests a foreign association type.
					AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
					renegotiateResponse.AssociationType = "HMAC-UNKNOWN";
					renegotiateResponse.SessionType = "DH-UNKNOWN";
					op.Channel.Respond(renegotiateResponse);
				});
			coordinator.Run();
		}
		public async Task RPOnlyRenegotiatesOnce() {
			Protocol protocol = Protocol.V20;
			int opStep = 0;
			HandleProvider(
				async (op, req) => {
					switch (++opStep) {
						case 1:
							// Receive initial request.
							var request = await op.Channel.ReadFromRequestAsync<AssociateRequest>(req, CancellationToken.None);

							// Send a renegotiate response
							var renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
							renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
							renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA1;
							return await op.Channel.PrepareResponseAsync(renegotiateResponse, CancellationToken.None);

						case 2:
							// Receive second-try
							request = await op.Channel.ReadFromRequestAsync<AssociateRequest>(req, CancellationToken.None);

							// Send ANOTHER renegotiate response, at which point the DNOI RP should give up.
							renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
							renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256;
							renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256;
							return await op.Channel.PrepareResponseAsync(renegotiateResponse, CancellationToken.None);

						default:
							throw Assumes.NotReachable();
					}
				});
			var rp = this.CreateRelyingParty();
			var association = await rp.AssociationManager.GetOrCreateAssociationAsync(new ProviderEndpointDescription(OPUri, protocol.Version), CancellationToken.None);
			Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves.");
		}
		public async Task RPRejectsMismatchingAssociationAndSessionBitLengths() {
			Protocol protocol = Protocol.V20;
			this.HandleProvider(
				async (op, req) => {
					// Receive initial request.
					var request = await op.Channel.ReadFromRequestAsync<AssociateRequest>(req, CancellationToken.None);

					// Send a mismatched response
					AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
					renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
					renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256;
					return await op.Channel.PrepareResponseAsync(renegotiateResponse);
				});
			var rp = this.CreateRelyingParty();
			var association = await rp.AssociationManager.GetOrCreateAssociationAsync(new ProviderEndpointDescription(OPUri, protocol.Version), CancellationToken.None);
			Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves.");
		}
		public async Task RPRejectsUnrecognizedAssociationType() {
			Protocol protocol = Protocol.V20;
			HandleProvider(
				async (op, req) => {
					// Receive initial request.
					var request = await op.Channel.ReadFromRequestAsync<AssociateRequest>(req, CancellationToken.None);

					// Send a response that suggests a foreign association type.
					var renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
					renegotiateResponse.AssociationType = "HMAC-UNKNOWN";
					renegotiateResponse.SessionType = "DH-UNKNOWN";
					return await op.Channel.PrepareResponseAsync(renegotiateResponse);
				});
			var rp = this.CreateRelyingParty();
			var association = await rp.AssociationManager.GetOrCreateAssociationAsync(new ProviderEndpointDescription(OPUri, protocol.Version), CancellationToken.None);
			Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves.");
		}
 public override void SetUp()
 {
     base.SetUp();
     var request = new AssociateUnencryptedRequest(Protocol.V20.Version, new Uri("http://host"));
     this.response = new AssociateUnsuccessfulResponse(request.Version, request);
 }
		/// <summary>
		/// Analyzes an incoming request message payload to discover what kind of
		/// message is embedded in it and returns the type, or null if no match is found.
		/// </summary>
		/// <param name="request">The message that was sent as a request that resulted in the response.</param>
		/// <param name="fields">The name/value pairs that make up the message payload.</param>
		/// <returns>
		/// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can
		/// deserialize to.  Null if the request isn't recognized as a valid protocol message.
		/// </returns>
		public IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) {
			DirectResponseBase message = null;

			// Discern the OpenID version of the message.
			Protocol protocol = Protocol.V11;
			string ns;
			if (fields.TryGetValue(Protocol.V20.openidnp.ns, out ns)) {
				ErrorUtilities.VerifyProtocol(string.Equals(ns, Protocol.OpenId2Namespace, StringComparison.Ordinal), MessagingStrings.UnexpectedMessagePartValue, Protocol.V20.openidnp.ns, ns);
				protocol = Protocol.V20;
			}

			// Handle error messages generally.
			if (fields.ContainsKey(protocol.openidnp.error)) {
				message = new DirectErrorResponse(protocol.Version, request);
			}

			var associateRequest = request as AssociateRequest;
			if (associateRequest != null) {
				if (protocol.Version.Major >= 2 && fields.ContainsKey(protocol.openidnp.error_code)) {
					// This is a special recognized error case that we create a special message for.
					message = new AssociateUnsuccessfulResponse(protocol.Version, associateRequest);
				} else if (message == null) {
					if (OpenIdUtilities.IsDiffieHellmanPresent) {
						var associateDiffieHellmanRequest = request as AssociateDiffieHellmanRequest;
						if (associateDiffieHellmanRequest != null) {
							message = new AssociateDiffieHellmanRelyingPartyResponse(protocol.Version, associateDiffieHellmanRequest);
						}
					}

					var associateUnencryptedRequest = request as AssociateUnencryptedRequest;
					if (associateUnencryptedRequest != null) {
						message = new AssociateUnencryptedResponseRelyingParty(protocol.Version, associateUnencryptedRequest);
					}
				}
			}

			var checkAuthenticationRequest = request as CheckAuthenticationRequest;
			if (checkAuthenticationRequest != null && message == null) {
				message = new CheckAuthenticationResponse(protocol.Version, checkAuthenticationRequest);
			}

			if (message != null) {
				message.SetAsIncoming();
			}

			return message;
		}