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="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;
		}
예제 #3
0
		private void ParameterizedAuthenticationTest(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper) {
			Contract.Requires<ArgumentException>(!statelessRP || !sharedAssociation, "The RP cannot be stateless while sharing an association with the OP.");
			Contract.Requires<ArgumentException>(positive || !tamper, "Cannot tamper with a negative response.");
			var securitySettings = new ProviderSecuritySettings();
			var cryptoKeyStore = new MemoryCryptoKeyStore();
			var associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
			Association association = sharedAssociation ? HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, associationStore, securitySettings) : null;
			var coordinator = new OpenIdCoordinator(
				rp => {
					var request = new CheckIdRequest(protocol.Version, OPUri, immediate ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup);

					if (association != null) {
						StoreAssociation(rp, OPUri, association);
						request.AssociationHandle = association.Handle;
					}

					request.ClaimedIdentifier = "http://claimedid";
					request.LocalIdentifier = "http://localid";
					request.ReturnTo = RPUri;
					request.Realm = RPUri;
					rp.Channel.Respond(request);
					if (positive) {
						if (tamper) {
							try {
								rp.Channel.ReadFromRequest<PositiveAssertionResponse>();
								Assert.Fail("Expected exception {0} not thrown.", typeof(InvalidSignatureException).Name);
							} catch (InvalidSignatureException) {
								TestLogger.InfoFormat("Caught expected {0} exception after tampering with signed data.", typeof(InvalidSignatureException).Name);
							}
						} else {
							var response = rp.Channel.ReadFromRequest<PositiveAssertionResponse>();
							Assert.IsNotNull(response);
							Assert.AreEqual(request.ClaimedIdentifier, response.ClaimedIdentifier);
							Assert.AreEqual(request.LocalIdentifier, response.LocalIdentifier);
							Assert.AreEqual(request.ReturnTo, response.ReturnTo);

							// Attempt to replay the message and verify that it fails.
							// Because in various scenarios and protocol versions different components
							// notice the replay, we can get one of two exceptions thrown.
							// When the OP notices the replay we get a generic InvalidSignatureException.
							// When the RP notices the replay we get a specific ReplayMessageException.
							try {
								CoordinatingChannel channel = (CoordinatingChannel)rp.Channel;
								channel.Replay(response);
								Assert.Fail("Expected ProtocolException was not thrown.");
							} catch (ProtocolException ex) {
								Assert.IsTrue(ex is ReplayedMessageException || ex is InvalidSignatureException, "A {0} exception was thrown instead of the expected {1} or {2}.", ex.GetType(), typeof(ReplayedMessageException).Name, typeof(InvalidSignatureException).Name);
							}
						}
					} else {
						var response = rp.Channel.ReadFromRequest<NegativeAssertionResponse>();
						Assert.IsNotNull(response);
						if (immediate) {
							// Only 1.1 was required to include user_setup_url
							if (protocol.Version.Major < 2) {
								Assert.IsNotNull(response.UserSetupUrl);
							}
						} else {
							Assert.IsNull(response.UserSetupUrl);
						}
					}
				},
				op => {
					if (association != null) {
						var key = cryptoKeyStore.GetCurrentKey(ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
						op.CryptoKeyStore.StoreKey(ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
					}

					var request = op.Channel.ReadFromRequest<CheckIdRequest>();
					Assert.IsNotNull(request);
					IProtocolMessage response;
					if (positive) {
						response = new PositiveAssertionResponse(request);
					} else {
						response = new NegativeAssertionResponse(request, op.Channel);
					}
					op.Channel.Respond(response);

					if (positive && (statelessRP || !sharedAssociation)) {
						var checkauthRequest = op.Channel.ReadFromRequest<CheckAuthenticationRequest>();
						var checkauthResponse = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
						checkauthResponse.IsValid = checkauthRequest.IsValid;
						op.Channel.Respond(checkauthResponse);

						if (!tamper) {
							// Respond to the replay attack.
							checkauthRequest = op.Channel.ReadFromRequest<CheckAuthenticationRequest>();
							checkauthResponse = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
							checkauthResponse.IsValid = checkauthRequest.IsValid;
							op.Channel.Respond(checkauthResponse);
						}
					}
				});
			if (tamper) {
				coordinator.IncomingMessageFilter = message => {
					var assertion = message as PositiveAssertionResponse;
					if (assertion != null) {
						// Alter the Local Identifier between the Provider and the Relying Party.
						// If the signature binding element does its job, this should cause the RP
						// to throw.
						assertion.LocalIdentifier = "http://victim";
					}
				};
			}
			if (statelessRP) {
				coordinator.RelyingParty = new OpenIdRelyingParty(null);
			}

			coordinator.Run();
		}
예제 #4
0
		private async Task ParameterizedAuthenticationTestAsync(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper) {
			Requires.That(!statelessRP || !sharedAssociation, null, "The RP cannot be stateless while sharing an association with the OP.");
			Requires.That(positive || !tamper, null, "Cannot tamper with a negative response.");
			var securitySettings = new ProviderSecuritySettings();
			var cryptoKeyStore = new MemoryCryptoKeyStore();
			var associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
			Association association = sharedAssociation ? HmacShaAssociationProvider.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, associationStore, securitySettings) : null;
			int opStep = 0;
			HandleProvider(
				async (op, req) => {
					if (association != null) {
						var key = cryptoKeyStore.GetCurrentKey(
							ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
						op.CryptoKeyStore.StoreKey(
							ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
					}

					switch (++opStep) {
						case 1:
							var request = await op.Channel.ReadFromRequestAsync<CheckIdRequest>(req, CancellationToken.None);
							Assert.IsNotNull(request);
							IProtocolMessage response;
							if (positive) {
								response = new PositiveAssertionResponse(request);
							} else {
								response = await NegativeAssertionResponse.CreateAsync(request, CancellationToken.None, op.Channel);
							}

							return await op.Channel.PrepareResponseAsync(response);
						case 2:
							if (positive && (statelessRP || !sharedAssociation)) {
								var checkauthRequest =
									await op.Channel.ReadFromRequestAsync<CheckAuthenticationRequest>(req, CancellationToken.None);
								var checkauthResponse = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
								checkauthResponse.IsValid = checkauthRequest.IsValid;
								return await op.Channel.PrepareResponseAsync(checkauthResponse);
							}

							throw Assumes.NotReachable();
						case 3:
							if (positive && (statelessRP || !sharedAssociation)) {
								if (!tamper) {
									// Respond to the replay attack.
									var checkauthRequest =
										await op.Channel.ReadFromRequestAsync<CheckAuthenticationRequest>(req, CancellationToken.None);
									var checkauthResponse = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
									checkauthResponse.IsValid = checkauthRequest.IsValid;
									return await op.Channel.PrepareResponseAsync(checkauthResponse);
								}
							}

							throw Assumes.NotReachable();
						default:
							throw Assumes.NotReachable();
					}
				});

			{
				var rp = this.CreateRelyingParty(statelessRP);
				if (tamper) {
					rp.Channel.IncomingMessageFilter = message => {
						var assertion = message as PositiveAssertionResponse;
						if (assertion != null) {
							// Alter the Local Identifier between the Provider and the Relying Party.
							// If the signature binding element does its job, this should cause the RP
							// to throw.
							assertion.LocalIdentifier = "http://victim";
						}
					};
				}

				var request = new CheckIdRequest(
					protocol.Version, OPUri, immediate ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup);

				if (association != null) {
					StoreAssociation(rp, OPUri, association);
					request.AssociationHandle = association.Handle;
				}

				request.ClaimedIdentifier = "http://claimedid";
				request.LocalIdentifier = "http://localid";
				request.ReturnTo = RPUri;
				request.Realm = RPUri;
				var redirectRequest = await rp.Channel.PrepareResponseAsync(request);
				Uri redirectResponse;
				this.HostFactories.AllowAutoRedirects = false;
				using (var httpClient = rp.Channel.HostFactories.CreateHttpClient()) {
					using (var response = await httpClient.GetAsync(redirectRequest.Headers.Location)) {
						Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Redirect));
						redirectResponse = response.Headers.Location;
					}
				}

				var assertionMessage = new HttpRequestMessage(HttpMethod.Get, redirectResponse);
				if (positive) {
					if (tamper) {
						try {
							await rp.Channel.ReadFromRequestAsync<PositiveAssertionResponse>(assertionMessage, CancellationToken.None);
							Assert.Fail("Expected exception {0} not thrown.", typeof(InvalidSignatureException).Name);
						} catch (InvalidSignatureException) {
							TestLogger.InfoFormat(
								"Caught expected {0} exception after tampering with signed data.", typeof(InvalidSignatureException).Name);
						}
					} else {
						var response =
							await rp.Channel.ReadFromRequestAsync<PositiveAssertionResponse>(assertionMessage, CancellationToken.None);
						Assert.IsNotNull(response);
						Assert.AreEqual(request.ClaimedIdentifier, response.ClaimedIdentifier);
						Assert.AreEqual(request.LocalIdentifier, response.LocalIdentifier);
						Assert.AreEqual(request.ReturnTo, response.ReturnTo);

						// Attempt to replay the message and verify that it fails.
						// Because in various scenarios and protocol versions different components
						// notice the replay, we can get one of two exceptions thrown.
						// When the OP notices the replay we get a generic InvalidSignatureException.
						// When the RP notices the replay we get a specific ReplayMessageException.
						try {
							await rp.Channel.ReadFromRequestAsync<PositiveAssertionResponse>(assertionMessage, CancellationToken.None);
							Assert.Fail("Expected ProtocolException was not thrown.");
						} catch (ProtocolException ex) {
							Assert.IsTrue(
								ex is ReplayedMessageException || ex is InvalidSignatureException,
								"A {0} exception was thrown instead of the expected {1} or {2}.",
								ex.GetType(),
								typeof(ReplayedMessageException).Name,
								typeof(InvalidSignatureException).Name);
						}
					}
				} else {
					var response =
						await rp.Channel.ReadFromRequestAsync<NegativeAssertionResponse>(assertionMessage, CancellationToken.None);
					Assert.IsNotNull(response);
					if (immediate) {
						// Only 1.1 was required to include user_setup_url
						if (protocol.Version.Major < 2) {
							Assert.IsNotNull(response.UserSetupUrl);
						}
					} else {
						Assert.IsNull(response.UserSetupUrl);
					}
				}
			}
		}