/// <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;
        }
Example #4
0
		/// <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="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 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;
		}
Example #13
0
 /// <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)
 {
 }