internal AnonymousRequest(OpenIdProvider provider, SignedResponseRequest request) : base(provider, request) { Contract.Requires<ArgumentNullException>(provider != null); Contract.Requires<ArgumentException>(!(request is CheckIdRequest), "Instantiate " + typeof(AuthenticationRequest).Name + " to handle this kind of message."); this.positiveResponse = new IndirectSignedResponse(request); }
internal AnonymousRequest(OpenIdProvider provider, SignedResponseRequest request) : base(provider, request) { Contract.Requires<ArgumentNullException>(provider != null); Contract.Requires<ArgumentException>(!(request is CheckIdRequest)); this.positiveResponse = new IndirectSignedResponse(request); }
public override void SetUp() { base.SetUp(); IndirectSignedResponse responseMessage = new IndirectSignedResponse(Protocol.Default.Version, RPUri); this.extensions = responseMessage.Extensions; this.response = new DotNetOpenAuth.OpenId.RelyingParty.PositiveAnonymousResponse(responseMessage); }
internal AnonymousRequest(OpenIdProvider provider, SignedResponseRequest request) : base(provider, request) { Requires.NotNull(provider, "provider"); Requires.True(!(request is CheckIdRequest), "request"); this.positiveResponse = new IndirectSignedResponse(request); }
public void ProviderTest() { var responseMessage = new IndirectSignedResponse(Protocol.V20.Version, this.returnTo); responseMessage.ProviderEndpoint = OPUri; var response = new PositiveAnonymousResponse(responseMessage); Assert.IsNotNull(response.Provider); Assert.AreEqual(OPUri, response.Provider.Uri); Assert.AreEqual(responseMessage.Version, response.Provider.Version); }
internal AnonymousRequest(OpenIdProvider provider, SignedResponseRequest request) : base(provider, request) { Contract.Requires(provider != null); Contract.Requires(!(request is CheckIdRequest), "Instantiate " + typeof(AuthenticationRequest).Name + " to handle this kind of message."); ErrorUtilities.VerifyInternal(!(request is CheckIdRequest), "Instantiate {0} to handle this kind of message.", typeof(AuthenticationRequest).Name); this.positiveResponse = new IndirectSignedResponse(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="recipient">The intended or actual recipient of the request message.</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 IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { ErrorUtilities.VerifyArgumentNotNull(recipient, "recipient"); ErrorUtilities.VerifyArgumentNotNull(fields, "fields"); RequestBase message = null; // Discern the OpenID version of the message. Protocol protocol = Protocol.V11; string ns; if (fields.TryGetValue(Protocol.V20.openid.ns, out ns)) { ErrorUtilities.VerifyProtocol(string.Equals(ns, Protocol.OpenId2Namespace, StringComparison.Ordinal), MessagingStrings.UnexpectedMessagePartValue, Protocol.V20.openid.ns, ns); protocol = Protocol.V20; } string mode; if (fields.TryGetValue(protocol.openid.mode, out mode)) { if (string.Equals(mode, protocol.Args.Mode.associate)) { if (fields.ContainsKey(protocol.openid.dh_consumer_public)) { message = new AssociateDiffieHellmanRequest(protocol.Version, recipient.Location); } else { message = new AssociateUnencryptedRequest(protocol.Version, recipient.Location); } } else if (string.Equals(mode, protocol.Args.Mode.checkid_setup) || string.Equals(mode, protocol.Args.Mode.checkid_immediate)) { AuthenticationRequestMode authMode = string.Equals(mode, protocol.Args.Mode.checkid_immediate) ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup; if (fields.ContainsKey(protocol.openid.identity)) { message = new CheckIdRequest(protocol.Version, recipient.Location, authMode); } else { ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent); message = new SignedResponseRequest(protocol.Version, recipient.Location, authMode); } } else if (string.Equals(mode, protocol.Args.Mode.cancel) || (string.Equals(mode, protocol.Args.Mode.setup_needed) && (protocol.Version.Major >= 2 || fields.ContainsKey(protocol.openid.user_setup_url)))) { message = new NegativeAssertionResponse(protocol.Version, recipient.Location, mode); } else if (string.Equals(mode, protocol.Args.Mode.id_res)) { if (fields.ContainsKey(protocol.openid.identity)) { message = new PositiveAssertionResponse(protocol.Version, recipient.Location); } else { ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent); message = new IndirectSignedResponse(protocol.Version, recipient.Location); } } else if (string.Equals(mode, protocol.Args.Mode.check_authentication)) { message = new CheckAuthenticationRequest(protocol.Version, recipient.Location); } else if (string.Equals(mode, protocol.Args.Mode.error)) { message = new IndirectErrorResponse(protocol.Version, recipient.Location); } else { ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessagePartValue, protocol.openid.mode, mode); } } if (message != null) { message.SetAsIncoming(); } return message; }
public override void SetUp() { base.SetUp(); this.protocol = Protocol.V20; this.request = new CheckIdRequest(this.protocol.Version, OPUri, AuthenticationRequestMode.Setup); this.request.ReturnTo = RPUri; this.response = new IndirectSignedResponse(this.request); this.unsolicited = new IndirectSignedResponse(this.protocol.Version, RPUri); }
public void CtorAndProperties() { var responseMessage = new IndirectSignedResponse(Protocol.V20.Version, this.returnTo); var ext = new ClaimsResponse(); responseMessage.Extensions.Add(ext); var response = new PositiveAnonymousResponse(responseMessage); Assert.AreEqual(AuthenticationStatus.ExtensionsOnly, response.Status); Assert.AreSame(responseMessage, response.Response); Assert.IsNull(response.ClaimedIdentifier); Assert.IsNull(response.FriendlyIdentifierForDisplay); Assert.IsNull(response.Exception); Assert.IsNull(response.Provider); Assert.AreSame(ext, response.GetUntrustedExtension<ClaimsResponse>()); }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationRequest"/> class /// based on the contents of some signed message whose signature must be verified. /// </summary> /// <param name="message">The message whose signature should be verified.</param> /// <param name="channel">The channel. This is used only within the constructor and is not stored in a field.</param> internal CheckAuthenticationRequest(IndirectSignedResponse message, Channel channel) : base(message.Version, message.ProviderEndpoint, GetProtocolConstant(message.Version, p => p.Args.Mode.check_authentication), MessageTransport.Direct) { Requires.NotNull(channel, "channel"); // Copy all message parts from the id_res message into this one, // except for the openid.mode parameter. MessageDictionary checkPayload = channel.MessageDescriptions.GetAccessor(message, true); MessageDictionary thisPayload = channel.MessageDescriptions.GetAccessor(this); foreach (var pair in checkPayload) { if (!string.Equals(pair.Key, this.Protocol.openid.mode)) { thisPayload[pair.Key] = pair.Value; } } }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationResponseProvider"/> class. /// </summary> /// <param name="request">The request that this message is responding to.</param> /// <param name="provider">The OpenID Provider that is preparing to send this response.</param> internal CheckAuthenticationResponseProvider(CheckAuthenticationRequest request, OpenIdProvider provider) : base(request.Version, request) { Requires.NotNull(provider, "provider"); // The channel's binding elements have already set the request's IsValid property // appropriately. We just copy it into the response message. this.IsValid = request.IsValid; // Confirm the RP should invalidate the association handle only if the association // is not valid (any longer). OpenID 2.0 section 11.4.2.2. IndirectSignedResponse signedResponse = new IndirectSignedResponse(request, provider.Channel); string invalidateHandle = ((ITamperResistantOpenIdMessage)signedResponse).InvalidateHandle; if (!string.IsNullOrEmpty(invalidateHandle) && !provider.AssociationStore.IsValid(signedResponse, false, invalidateHandle)) { this.InvalidateHandle = invalidateHandle; } }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationResponse"/> class /// for use by the Provider. /// </summary> /// <param name="request">The request that this message is responding to.</param> /// <param name="provider">The OpenID Provider that is preparing to send this response.</param> internal CheckAuthenticationResponse(CheckAuthenticationRequest request, OpenIdProvider provider) : base(request.Version, request) { Contract.Requires<ArgumentNullException>(provider != null); // The channel's binding elements have already set the request's IsValid property // appropriately. We just copy it into the response message. this.IsValid = request.IsValid; // Confirm the RP should invalidate the association handle only if the association // really doesn't exist. OpenID 2.0 section 11.4.2.2. IndirectSignedResponse signedResponse = new IndirectSignedResponse(request, provider.Channel); string invalidateHandle = ((ITamperResistantOpenIdMessage)signedResponse).InvalidateHandle; if (!string.IsNullOrEmpty(invalidateHandle) && provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, invalidateHandle) == null) { this.InvalidateHandle = invalidateHandle; } }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationRequest"/> class /// based on the contents of some signed message whose signature must be verified. /// </summary> /// <param name="message">The message whose signature should be verified.</param> internal CheckAuthenticationRequest(IndirectSignedResponse message) : base(message.Version, message.ProviderEndpoint, GetProtocolConstant(message.Version, p => p.Args.Mode.check_authentication), MessageTransport.Direct) { // Copy all message parts from the id_res message into this one, // except for the openid.mode parameter. MessageDictionary checkPayload = new MessageDictionary(message); MessageDictionary thisPayload = new MessageDictionary(this); foreach (var pair in checkPayload) { if (!string.Equals(pair.Key, this.Protocol.openid.mode)) { thisPayload[pair.Key] = pair.Value; } } }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationRequest"/> class /// based on the contents of some signed message whose signature must be verified. /// </summary> /// <param name="message">The message whose signature should be verified.</param> /// <param name="channel">The channel. This is used only within the constructor and is not stored in a field.</param> internal CheckAuthenticationRequest(IndirectSignedResponse message, Channel channel) : base(message.Version, message.ProviderEndpoint, GetProtocolConstant(message.Version, p => p.Args.Mode.check_authentication), MessageTransport.Direct) { Contract.Requires <ArgumentNullException>(channel != null); // Copy all message parts from the id_res message into this one, // except for the openid.mode parameter. MessageDictionary checkPayload = channel.MessageDescriptions.GetAccessor(message, true); MessageDictionary thisPayload = channel.MessageDescriptions.GetAccessor(this); foreach (var pair in checkPayload) { if (!string.Equals(pair.Key, this.Protocol.openid.mode)) { thisPayload[pair.Key] = pair.Value; } } }
public void SignaturesMatchKnownGood() { Protocol protocol = Protocol.V20; var settings = new ProviderSecuritySettings(); var store = new AssociationMemoryStore<AssociationRelyingPartyType>(); byte[] associationSecret = Convert.FromBase64String("rsSwv1zPWfjPRQU80hciu8FPDC+GONAMJQ/AvSo1a2M="); Association association = HmacShaAssociation.Create("mock", associationSecret, TimeSpan.FromDays(1)); store.StoreAssociation(AssociationRelyingPartyType.Smart, association); SigningBindingElement signer = new SigningBindingElement(store, settings); signer.Channel = new TestChannel(this.MessageDescriptions); IndirectSignedResponse message = new IndirectSignedResponse(protocol.Version, new Uri("http://rp")); ITamperResistantOpenIdMessage signedMessage = message; message.ProviderEndpoint = new Uri("http://provider"); signedMessage.UtcCreationDate = DateTime.Parse("1/1/2009"); signedMessage.AssociationHandle = association.Handle; Assert.IsNotNull(signer.ProcessOutgoingMessage(message)); Assert.AreEqual("o9+uN7qTaUS9v0otbHTuNAtbkpBm14+es9QnNo6IHD4=", signedMessage.Signature); }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationResponse"/> class /// for use by the Provider. /// </summary> /// <param name="request">The request that this message is responding to.</param> /// <param name="provider">The OpenID Provider that is preparing to send this response.</param> internal CheckAuthenticationResponse(CheckAuthenticationRequest request, OpenIdProvider provider) : base(request.Version, request) { ErrorUtilities.VerifyArgumentNotNull(provider, "provider"); // The channel's binding elements have already set the request's IsValid property // appropriately. We just copy it into the response message. this.IsValid = request.IsValid; // Confirm the RP should invalidate the association handle only if the association // really doesn't exist. OpenID 2.0 section 11.4.2.2. IndirectSignedResponse signedResponse = new IndirectSignedResponse(request); string invalidateHandle = ((ITamperResistantOpenIdMessage)signedResponse).InvalidateHandle; if (invalidateHandle != null && provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, invalidateHandle) == null) { this.InvalidateHandle = invalidateHandle; } }
/// <summary> /// Initializes a new instance of the <see cref="CheckAuthenticationResponseProvider"/> class. /// </summary> /// <param name="request">The request that this message is responding to.</param> /// <param name="provider">The OpenID Provider that is preparing to send this response.</param> internal CheckAuthenticationResponseProvider(CheckAuthenticationRequest request, OpenIdProvider provider) : base(request.Version, request) { Requires.NotNull(provider, "provider"); // The channel's binding elements have already set the request's IsValid property // appropriately. We just copy it into the response message. this.IsValid = request.IsValid; // Confirm the RP should invalidate the association handle only if the association // is not valid (any longer). OpenID 2.0 section 11.4.2.2. IndirectSignedResponse signedResponse = new IndirectSignedResponse(request, provider.Channel); string invalidateHandle = ((ITamperResistantOpenIdMessage)signedResponse).InvalidateHandle; if (!string.IsNullOrEmpty(invalidateHandle) && !provider.AssociationStore.IsValid(signedResponse, false, invalidateHandle)) { this.InvalidateHandle = invalidateHandle; } }
public void SignaturesMatchKnownGood() { Protocol protocol = Protocol.V20; var settings = new ProviderSecuritySettings(); var cryptoStore = new MemoryCryptoKeyStore(); byte[] associationSecret = Convert.FromBase64String("rsSwv1zPWfjPRQU80hciu8FPDC+GONAMJQ/AvSo1a2M="); string handle = "mock"; cryptoStore.StoreKey(ProviderAssociationKeyStorage.SharedAssociationBucket, handle, new CryptoKey(associationSecret, DateTime.UtcNow.AddDays(1))); var store = new ProviderAssociationKeyStorage(cryptoStore); SigningBindingElement signer = new ProviderSigningBindingElement(store, settings); signer.Channel = new TestChannel(this.MessageDescriptions); IndirectSignedResponse message = new IndirectSignedResponse(protocol.Version, new Uri("http://rp")); ITamperResistantOpenIdMessage signedMessage = message; message.ProviderEndpoint = new Uri("http://provider"); signedMessage.UtcCreationDate = DateTime.Parse("1/1/2009"); signedMessage.AssociationHandle = handle; Assert.IsNotNull(signer.ProcessOutgoingMessage(message)); Assert.AreEqual("o9+uN7qTaUS9v0otbHTuNAtbkpBm14+es9QnNo6IHD4=", signedMessage.Signature); }
public void GetReturnToArgumentAndNames() { UriBuilder returnToBuilder = new UriBuilder(this.response.ReturnTo); returnToBuilder.AppendQueryArgs(new Dictionary<string, string> { { "a", "b" } }); this.request.ReturnTo = returnToBuilder.Uri; // First pretend that the return_to args were signed. this.response = new IndirectSignedResponse(this.request); this.response.ReturnToParametersSignatureValidated = true; Assert.AreEqual(1, this.response.GetReturnToParameterNames().Count()); Assert.IsTrue(this.response.GetReturnToParameterNames().Contains("a")); Assert.AreEqual("b", this.response.GetReturnToArgument("a")); // Now simulate them NOT being signed. They should still be visible at this level. this.response = new IndirectSignedResponse(this.request); this.response.ReturnToParametersSignatureValidated = false; Assert.AreEqual(1, this.response.GetReturnToParameterNames().Count()); Assert.IsTrue(this.response.GetReturnToParameterNames().Contains("a")); Assert.AreEqual("b", this.response.GetReturnToArgument("a")); }
public void SignedResponsesIncludeExtraDataInSignature() { Protocol protocol = Protocol.Default; SigningBindingElement sbe = new ProviderSigningBindingElement(new ProviderAssociationHandleEncoder(new MemoryCryptoKeyStore()), new ProviderSecuritySettings()); sbe.Channel = new TestChannel(this.MessageDescriptions); IndirectSignedResponse response = new IndirectSignedResponse(protocol.Version, RPUri); response.ReturnTo = RPUri; response.ProviderEndpoint = OPUri; response.ExtraData["someunsigned"] = "value"; response.ExtraData["openid.somesigned"] = "value"; Assert.IsNotNull(sbe.ProcessOutgoingMessage(response)); ITamperResistantOpenIdMessage signedResponse = (ITamperResistantOpenIdMessage)response; // Make sure that the extra parameters are signed. // Since the signing algorithm only allows for signing parameters that start with // 'openid.', other parameters should not be signed. Assert.IsNotNull(signedResponse.SignedParameterOrder); string[] signedParameters = signedResponse.SignedParameterOrder.Split(','); Assert.IsTrue(signedParameters.Contains("somesigned")); Assert.IsFalse(signedParameters.Contains("someunsigned")); }
/// <summary> /// Creates a response message with one extensions. /// </summary> /// <param name="protocol">The protocol to construct the message with.</param> /// <returns>The message ready to send from OP to RP.</returns> private IndirectSignedResponse CreateResponseWithExtensions(Protocol protocol) { ErrorUtilities.VerifyArgumentNotNull(protocol, "protocol"); IndirectSignedResponse response = new IndirectSignedResponse(protocol.Version, RPUri); response.ProviderEndpoint = OPUri; response.Extensions.Add(new MockOpenIdExtension("pv", "ev")); return response; }
public void MissingSignedParameter() { var cryptoStore = new MemoryCryptoKeyStore(); byte[] associationSecret = Convert.FromBase64String("rsSwv1zPWfjPRQU80hciu8FPDC+GONAMJQ/AvSo1a2M="); string handle = "{634477555066085461}{TTYcIg==}{32}"; cryptoStore.StoreKey(ProviderAssociationKeyStorage.PrivateAssociationBucket, handle, new CryptoKey(associationSecret, DateTime.UtcNow.AddDays(1))); var signer = new ProviderSigningBindingElement(new ProviderAssociationKeyStorage(cryptoStore), new ProviderSecuritySettings()); var testChannel = new TestChannel(new OpenIdProviderMessageFactory()); signer.Channel = testChannel; var buggyRPMessage = new Dictionary<string, string>() { { "openid.assoc_handle", "{634477555066085461}{TTYcIg==}{32}" }, { "openid.claimed_id", "https://openid.stackexchange.com/user/f5e91123-e5b4-43c5-871f-5f276c75d31a" }, { "openid.identity", "https://openid.stackexchange.com/user/f5e91123-e5b4-43c5-871f-5f276c75d31a" }, { "openid.mode", "check_authentication" }, { "openid.op_endpoint", "https://openid.stackexchange.com/openid/provider" }, { "openid.response_nonce", "2011-08-01T00:32:10Zvdyt3efw" }, { "openid.return_to", "http://openid-consumer.appspot.com/finish?session_id=1543025&janrain_nonce=2011-08-01T00%3A32%3A09ZIPGz7D" }, { "openid.sig", "b0Rll6Kt1KKBWWBEg/qBvW3sQYtmhOUmpI0/UREBVZ0=" }, { "openid.signed", "claimed_id,identity,assoc_handle,op_endpoint,return_to,response_nonce,ns.sreg,sreg.email,sreg.fullname" }, { "openid.sreg.email", "*****@*****.**" }, { "openid.sreg.fullname", "Kevin K Montrose" }, }; var message = (CheckAuthenticationRequest)testChannel.Receive(buggyRPMessage, new MessageReceivingEndpoint(OPUri, HttpDeliveryMethods.PostRequest)); var originalResponse = new IndirectSignedResponse(message, signer.Channel); signer.ProcessIncomingMessage(originalResponse); }
/// <summary> /// Creates a response message with one extensions. /// </summary> /// <param name="protocol">The protocol to construct the message with.</param> /// <returns>The message ready to send from OP to RP.</returns> private IndirectSignedResponse CreateResponseWithExtensions(Protocol protocol) { Requires.NotNull(protocol, "protocol"); var response = new IndirectSignedResponse(protocol.Version, RPUri); response.ProviderEndpoint = OPUri; response.Extensions.Add(new MockOpenIdExtension("pv", "ev")); return response; }
/// <summary> /// Verifies the integrity and applicability of an incoming message. /// </summary> /// <param name="message">The message just received.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A task that completes with the asynchronous operation. /// </returns> /// <exception cref="ProtocolException">Thrown when the message is somehow invalid, except for check_authentication messages. /// This can be due to tampering, replay attack or expiration, among other things.</exception> protected override async Task ProcessIncomingMessageAsync(IProtocolMessage message, CancellationToken cancellationToken) { var checkAuthRequest = message as CheckAuthenticationRequest; if (checkAuthRequest != null) { IndirectSignedResponse originalResponse = new IndirectSignedResponse(checkAuthRequest, this); try { await base.ProcessIncomingMessageAsync(originalResponse, cancellationToken); checkAuthRequest.IsValid = true; } catch (ProtocolException) { checkAuthRequest.IsValid = false; } } else { await base.ProcessIncomingMessageAsync(message, cancellationToken); } // Convert an OpenID indirect error message, which we never expect // between two good OpenID implementations, into an exception. // We don't process DirectErrorResponse because associate negotiations // commonly get a derivative of that message type and handle it. var errorMessage = message as IndirectErrorResponse; if (errorMessage != null) { string exceptionMessage = string.Format( CultureInfo.CurrentCulture, OpenIdStrings.IndirectErrorFormattedMessage, errorMessage.ErrorMessage, errorMessage.Contact, errorMessage.Reference); throw new ProtocolException(exceptionMessage, message); } }
/// <summary> /// Determines whether the relying party sending an authentication request is /// vulnerable to replay attacks. /// </summary> /// <param name="request">The request message from the Relying Party. Useful, but may be null for conservative estimate results.</param> /// <param name="response">The response message to be signed.</param> /// <returns> /// <c>true</c> if the relying party is vulnerable; otherwise, <c>false</c>. /// </returns> private static bool IsRelyingPartyVulnerableToReplays(SignedResponseRequest request, IndirectSignedResponse response) { Contract.Requires<ArgumentNullException>(response != null); // OpenID 2.0 includes replay protection as part of the protocol. if (response.Version.Major >= 2) { return false; } // This library's RP may be on the remote end, and may be using 1.x merely because // discovery on the Claimed Identifier suggested this was a 1.x OP. // Since this library's RP has a built-in request_nonce parameter for replay // protection, we'll allow for that. var returnToArgs = HttpUtility.ParseQueryString(response.ReturnTo.Query); if (!string.IsNullOrEmpty(returnToArgs[ReturnToNonceBindingElement.NonceParameter])) { return false; } // If the OP endpoint _AND_ RP return_to URL uses HTTPS then no one // can steal and replay the positive assertion. // We can only ascertain this if the request message was handed to us // so we know what our own OP endpoint is. If we don't have a request // message, then we'll default to assuming it's insecure. if (request != null) { if (request.Recipient.IsTransportSecure() && response.Recipient.IsTransportSecure()) { return false; } } // Nothing left to protect against replays. RP is vulnerable. return true; }
/// <summary> /// Creates a response message with one extensions. /// </summary> /// <param name="protocol">The protocol to construct the message with.</param> /// <returns>The message ready to send from OP to RP.</returns> private IndirectSignedResponse CreateResponseWithExtensions(Protocol protocol) { Contract.Requires<ArgumentNullException>(protocol != null); IndirectSignedResponse response = new IndirectSignedResponse(protocol.Version, RPUri); response.ProviderEndpoint = OPUri; response.Extensions.Add(new MockOpenIdExtension("pv", "ev")); return response; }