/// <summary> /// Verifies the signature by unrecognized handle. /// </summary> /// <param name="message">The message.</param> /// <param name="signedMessage">The signed message.</param> /// <param name="protectionsApplied">The protections applied.</param> /// <returns> /// The applied protections. /// </returns> protected override MessageProtections VerifySignatureByUnrecognizedHandle(IProtocolMessage message, ITamperResistantOpenIdMessage signedMessage, MessageProtections protectionsApplied) { // We did not recognize the association the provider used to sign the message. // Ask the provider to check the signature then. var indirectSignedResponse = (IndirectSignedResponse)signedMessage; var checkSignatureRequest = new CheckAuthenticationRequest(indirectSignedResponse, this.Channel); var checkSignatureResponse = this.Channel.Request<CheckAuthenticationResponse>(checkSignatureRequest); if (!checkSignatureResponse.IsValid) { Logger.Bindings.Error("Provider reports signature verification failed."); throw new InvalidSignatureException(message); } // If the OP confirms that a handle should be invalidated as well, do that. if (!string.IsNullOrEmpty(checkSignatureResponse.InvalidateHandle)) { if (this.rpAssociations != null) { this.rpAssociations.RemoveAssociation(indirectSignedResponse.ProviderEndpoint, checkSignatureResponse.InvalidateHandle); } } // When we're in dumb mode we can't provide our own replay protection, // but for OpenID 2.0 Providers we can rely on them providing it as part // of signature verification. if (message.Version.Major >= 2) { protectionsApplied |= MessageProtections.ReplayProtection; } return protectionsApplied; }
public void IsValid() { Protocol protocol = Protocol.Default; var request = new CheckAuthenticationRequest(protocol.Version, OPUri); var response = new CheckAuthenticationResponse(protocol.Version, request); var dictionary = this.MessageDescriptions.GetAccessor(response); Assert.AreEqual("false", dictionary["is_valid"]); response.IsValid = true; Assert.AreEqual("true", dictionary["is_valid"]); }
/// <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; }
/// <summary> /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class /// in order to perform signature verification at the Provider. /// </summary> /// <param name="previouslySignedMessage">The previously signed message.</param> /// <param name="channel">The channel. This is used only within the constructor and is not stored in a field.</param> internal IndirectSignedResponse(CheckAuthenticationRequest previouslySignedMessage, Channel channel) : base(GetVersion(previouslySignedMessage), previouslySignedMessage.ReturnTo, Protocol.Lookup(GetVersion(previouslySignedMessage)).Args.Mode.id_res) { Requires.NotNull(channel, "channel"); // Copy all message parts from the check_authentication message into this one, // except for the openid.mode parameter. MessageDictionary checkPayload = channel.MessageDescriptions.GetAccessor(previouslySignedMessage); 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="IndirectSignedResponse"/> class /// in order to perform signature verification at the Provider. /// </summary> /// <param name="previouslySignedMessage">The previously signed message.</param> /// <param name="channel">The channel. This is used only within the constructor and is not stored in a field.</param> internal IndirectSignedResponse(CheckAuthenticationRequest previouslySignedMessage, Channel channel) : base(GetVersion(previouslySignedMessage), previouslySignedMessage.ReturnTo, Protocol.Lookup(GetVersion(previouslySignedMessage)).Args.Mode.id_res) { Contract.Requires<ArgumentNullException>(channel != null); // Copy all message parts from the check_authentication message into this one, // except for the openid.mode parameter. MessageDictionary checkPayload = channel.MessageDescriptions.GetAccessor(previouslySignedMessage); 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 ExactPositiveAssertionPreservation() { var rp = CreateRelyingParty(true); // Initialize the positive assertion response with some data that is NOT in normalized form. var positiveAssertion = new PositiveAssertionResponse(Protocol.Default.Version, RPUri) { ClaimedIdentifier = "https://HOST:443/a", ProviderEndpoint = new Uri("https://anotherHOST:443/b"), }; var checkAuth = new CheckAuthenticationRequest(positiveAssertion, rp.Channel); var actual = rp.Channel.MessageDescriptions.GetAccessor(checkAuth); Assert.AreEqual("https://HOST:443/a", actual["openid.claimed_id"]); Assert.AreEqual("https://anotherHOST:443/b", actual["openid.op_endpoint"]); }
/// <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="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="CheckAuthenticationResponse"/> class /// for use by the Relying Party. /// </summary> /// <param name="responseVersion">The OpenID version of the response message.</param> /// <param name="request">The request that this message is responding to.</param> internal CheckAuthenticationResponse(Version responseVersion, CheckAuthenticationRequest request) : base(responseVersion, request) { }
/// <summary> /// Performs any transformation on an incoming message that may be necessary and/or /// validates an incoming message based on the rules of this channel binding element. /// </summary> /// <param name="message">The incoming message to process.</param> /// <returns> /// The protections (if any) that this binding element applied to the message. /// Null if this binding element did not even apply to this binding element. /// </returns> /// <exception cref="ProtocolException"> /// Thrown when the binding element rules indicate that this message is invalid and should /// NOT be processed. /// </exception> public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) { var signedMessage = message as ITamperResistantOpenIdMessage; if (signedMessage != null) { Logger.Bindings.DebugFormat("Verifying incoming {0} message signature of: {1}", message.GetType().Name, signedMessage.Signature); MessageProtections protectionsApplied = MessageProtections.TamperProtection; this.EnsureParametersRequiringSignatureAreSigned(signedMessage); Association association = this.GetSpecificAssociation(signedMessage); if (association != null) { string signature = this.GetSignature(signedMessage, association); if (!MessagingUtilities.EqualsConstantTime(signedMessage.Signature, signature)) { Logger.Bindings.Error("Signature verification failed."); throw new InvalidSignatureException(message); } } else { ErrorUtilities.VerifyInternal(this.Channel != null, "Cannot verify private association signature because we don't have a channel."); // If we're on the Provider, then the RP sent us a check_auth with a signature // we don't have an association for. (It may have expired, or it may be a faulty RP). if (this.IsOnProvider) { throw new InvalidSignatureException(message); } // We did not recognize the association the provider used to sign the message. // Ask the provider to check the signature then. var indirectSignedResponse = (IndirectSignedResponse)signedMessage; var checkSignatureRequest = new CheckAuthenticationRequest(indirectSignedResponse, this.Channel); var checkSignatureResponse = this.Channel.Request<CheckAuthenticationResponse>(checkSignatureRequest); if (!checkSignatureResponse.IsValid) { Logger.Bindings.Error("Provider reports signature verification failed."); throw new InvalidSignatureException(message); } // If the OP confirms that a handle should be invalidated as well, do that. if (!string.IsNullOrEmpty(checkSignatureResponse.InvalidateHandle)) { if (this.rpAssociations != null) { this.rpAssociations.RemoveAssociation(indirectSignedResponse.ProviderEndpoint, checkSignatureResponse.InvalidateHandle); } } // When we're in dumb mode we can't provide our own replay protection, // but for OpenID 2.0 Providers we can rely on them providing it as part // of signature verification. if (message.Version.Major >= 2) { protectionsApplied |= MessageProtections.ReplayProtection; } } return protectionsApplied; } return null; }