/// <summary>
        /// Creates the association at the provider side after the association request has been received.
        /// </summary>
        /// <param name="request">The association request.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>The newly created association.</returns>
        /// <remarks>
        /// The response message is updated to include the details of the created association by this method,
        /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.
        /// </remarks>
        protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(request, "request");
            var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;
            ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, "request");
            ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");

            this.SessionType = this.SessionType ?? request.SessionType;

            // Go ahead and create the association first, complete with its secret that we're about to share.
            Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings);

            // We now need to securely communicate the secret to the relying party using Diffie-Hellman.
            // We do this by performing a DH algorithm on the secret and setting a couple of properties
            // that will be transmitted to the Relying Party.  The RP will perform an inverse operation
            // using its part of a DH secret in order to decrypt the shared secret we just invented
            // above when we created the association.
            DiffieHellman dh = new DiffieHellmanManaged(
                diffieHellmanRequest.DiffieHellmanModulus ?? AssociateDiffieHellmanRequest.DefaultMod,
                diffieHellmanRequest.DiffieHellmanGen ?? AssociateDiffieHellmanRequest.DefaultGen,
                AssociateDiffieHellmanRequest.DefaultX);
            HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(this.Protocol, this.SessionType);
            this.DiffieHellmanServerPublic = DiffieHellmanUtilities.EnsurePositive(dh.CreateKeyExchange());
            this.EncodedMacKey = DiffieHellmanUtilities.SHAHashXorSecret(hasher, dh, diffieHellmanRequest.DiffieHellmanConsumerPublic, association.SecretKey);

            return association;
        }
		/// <summary>
		/// Creates a new association of a given type at an OpenID Provider.
		/// </summary>
		/// <param name="protocol">The protocol.</param>
		/// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param>
		/// <param name="associationUse">A value indicating whether the new association will be used privately by the Provider for "dumb mode" authentication
		/// or shared with the Relying Party for "smart mode" authentication.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings of the Provider.</param>
		/// <returns>
		/// The newly created association.
		/// </returns>
		/// <remarks>
		/// The new association is NOT automatically put into an association store.  This must be done by the caller.
		/// </remarks>
		internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(protocol, "protocol");
			Requires.NotNullOrEmpty(associationType, "associationType");
			Requires.NotNull(associationStore, "associationStore");
			Requires.NotNull(securitySettings, "securitySettings");
			Contract.Ensures(Contract.Result<HmacShaAssociation>() != null);

			int secretLength = HmacShaAssociation.GetSecretLength(protocol, associationType);

			// Generate the secret that will be used for signing
			byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength);

			TimeSpan lifetime;
			if (associationUse == AssociationRelyingPartyType.Smart) {
				if (!securitySettings.AssociationLifetimes.TryGetValue(associationType, out lifetime)) {
					lifetime = DefaultMaximumLifetime;
				}
			} else {
				lifetime = HmacShaAssociation.DumbSecretLifetime;
			}

			string handle = associationStore.Serialize(secret, DateTime.UtcNow + lifetime, associationUse == AssociationRelyingPartyType.Dumb);

			Contract.Assert(protocol != null); // All the way up to the method call, the condition holds, yet we get a Requires failure next
			Contract.Assert(secret != null);
			Contract.Assert(!string.IsNullOrEmpty(associationType));
			var result = HmacShaAssociation.Create(protocol, associationType, handle, secret, lifetime);
			return result;
		}
		/// <summary>
		/// Initializes a new instance of the SigningBindingElement class for use by a Provider.
		/// </summary>
		/// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
		/// <param name="securitySettings">The security settings.</param>
		internal SigningBindingElement(IAssociationStore<AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings) {
			Contract.Requires<ArgumentNullException>(associationStore != null);
			Contract.Requires<ArgumentNullException>(securitySettings != null);

			this.opAssociations = associationStore;
			this.opSecuritySettings = securitySettings;
		}
		/// <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>
        /// Initializes a new instance of the <see cref="AutoResponsiveRequest"/> class
        /// for a response to an unrecognizable request.
        /// </summary>
        /// <param name="response">The response that is ready for transmittal.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal AutoResponsiveRequest(IProtocolMessage response, ProviderSecuritySettings securitySettings)
            : base(IndirectResponseBase.GetVersion(response), securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(response, "response");

            this.response = response;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AutoResponsiveRequest"/> class.
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="response">The response that is ready for transmittal.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal AutoResponsiveRequest(IDirectedProtocolMessage request, IProtocolMessage response, ProviderSecuritySettings securitySettings)
            : base(request, securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(response, "response");

            this.response = response;
        }
		/// <summary>
		/// Initializes a new instance of the <see cref="ProviderSigningBindingElement"/> class.
		/// </summary>
		/// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
		/// <param name="securitySettings">The security settings.</param>
		internal ProviderSigningBindingElement(IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(associationStore, "associationStore");
			Requires.NotNull(securitySettings, "securitySettings");

			this.opAssociations = associationStore;
			this.opSecuritySettings = securitySettings;
		}
		/// <summary>
		/// Adapts the default security settings to the requirements of this behavior.
		/// </summary>
		/// <param name="securitySettings">The original security settings.</param>
		void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings) {
			if (securitySettings.MaximumHashBitLength < 256) {
				securitySettings.MaximumHashBitLength = 256;
			}

			SetMaximumAssociationLifetimeToNotExceed(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA256, MaximumAssociationLifetime, securitySettings);
			SetMaximumAssociationLifetimeToNotExceed(Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, MaximumAssociationLifetime, securitySettings);
		}
        /// <summary>
        /// Initializes a new instance of the SigningBindingElement class for use by a Provider.
        /// </summary>
        /// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal SigningBindingElement(IAssociationStore<AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(associationStore, "associationStore");
            ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");

            this.opAssociations = associationStore;
            this.opSecuritySettings = securitySettings;
        }
Beispiel #10
0
		public override void SetUp() {
			base.SetUp();

			this.RelyingPartySecuritySettings = OpenIdElement.Configuration.RelyingParty.SecuritySettings.CreateSecuritySettings();
			this.ProviderSecuritySettings = OpenIdElement.Configuration.Provider.SecuritySettings.CreateSecuritySettings();

			this.AutoProviderScenario = Scenarios.AutoApproval;
			Identifier.EqualityOnStrings = true;
			this.HostFactories.InstallUntrustedWebReqestHandler = true;
		}
Beispiel #11
0
		public override void SetUp() {
			base.SetUp();

			this.RelyingPartySecuritySettings = DotNetOpenAuthSection.Configuration.OpenId.RelyingParty.SecuritySettings.CreateSecuritySettings();
			this.ProviderSecuritySettings = DotNetOpenAuthSection.Configuration.OpenId.Provider.SecuritySettings.CreateSecuritySettings();

			this.MockResponder = MockHttpRequest.CreateUntrustedMockHttpHandler();
			this.RequestHandler = this.MockResponder.MockWebRequestHandler;
			this.AutoProviderScenario = Scenarios.AutoApproval;
			Identifier.EqualityOnStrings = true;
		}
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <param name="response">The response.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings for the Provider.  Should be <c>null</c> for Relying Parties.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		/// <remarks>
		/// The response message is updated to include the details of the created association by this method.
		/// This method is called by both the Provider and the Relying Party, but actually performs
		/// quite different operations in either scenario.
		/// </remarks>
		internal static Association CreateAssociation(AssociateRequest request, IAssociateSuccessfulResponseProvider response, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(request, "request");
			Requires.NotNull(response, "response");
			Requires.NotNull(securitySettings, "securitySettings");

			// We need to initialize some common properties based on the created association.
			var association = response.CreateAssociationAtProvider(request, associationStore, securitySettings);
			response.ExpiresIn = association.SecondsTillExpiration;
			response.AssociationHandle = association.Handle;

			return association;
		}
		/// <summary>
		/// Simulates an extension request and response.
		/// </summary>
		/// <param name="protocol">The protocol to use in the roundtripping.</param>
		/// <param name="requests">The extensions to add to the request message.</param>
		/// <param name="responses">The extensions to add to the response message.</param>
		/// <remarks>
		/// This method relies on the extension objects' Equals methods to verify
		/// accurate transport.  The Equals methods should be verified by separate tests.
		/// </remarks>
		internal static void Roundtrip(
			Protocol protocol,
			IEnumerable<IOpenIdMessageExtension> requests,
			IEnumerable<IOpenIdMessageExtension> responses) {
			var securitySettings = new ProviderSecuritySettings();
			var cryptoKeyStore = new MemoryCryptoKeyStore();
			var associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
			Association association = HmacShaAssociationProvider.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, associationStore, securitySettings);
			var coordinator = new OpenIdCoordinator(
				rp => {
					RegisterExtension(rp.Channel, Mocks.MockOpenIdExtension.Factory);
					var requestBase = new CheckIdRequest(protocol.Version, OpenIdTestBase.OPUri, AuthenticationRequestMode.Immediate);
					OpenIdTestBase.StoreAssociation(rp, OpenIdTestBase.OPUri, association);
					requestBase.AssociationHandle = association.Handle;
					requestBase.ClaimedIdentifier = "http://claimedid";
					requestBase.LocalIdentifier = "http://localid";
					requestBase.ReturnTo = OpenIdTestBase.RPUri;

					foreach (IOpenIdMessageExtension extension in requests) {
						requestBase.Extensions.Add(extension);
					}

					rp.Channel.Respond(requestBase);
					var response = rp.Channel.ReadFromRequest<PositiveAssertionResponse>();

					var receivedResponses = response.Extensions.Cast<IOpenIdMessageExtension>();
					CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray());
				},
				op => {
					RegisterExtension(op.Channel, Mocks.MockOpenIdExtension.Factory);
					var key = cryptoKeyStore.GetCurrentKey(ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
					op.CryptoKeyStore.StoreKey(ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
					var request = op.Channel.ReadFromRequest<CheckIdRequest>();
					var response = new PositiveAssertionResponse(request);
					var receivedRequests = request.Extensions.Cast<IOpenIdMessageExtension>();
					CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(requests.ToArray(), receivedRequests.ToArray());

					foreach (var extensionResponse in responses) {
						response.Extensions.Add(extensionResponse);
					}

					op.Channel.Respond(response);
				});
			coordinator.Run();
		}
		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 the binding elements.
		/// </summary>
		/// <param name="cryptoKeyStore">The OpenID Provider's crypto key store.</param>
		/// <param name="nonceStore">The nonce store to use.</param>
		/// <param name="securitySettings">The security settings to apply.  Must be an instance of either RelyingPartySecuritySettings or ProviderSecuritySettings.</param>
		/// <returns>
		/// An array of binding elements which may be used to construct the channel.
		/// </returns>
		private static IChannelBindingElement[] InitializeBindingElements(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(cryptoKeyStore, "cryptoKeyStore");
			Requires.NotNull(securitySettings, "securitySettings");
			Requires.NotNull(nonceStore, "nonceStore");

			SigningBindingElement signingElement;
			signingElement = new ProviderSigningBindingElement(cryptoKeyStore, securitySettings);

			var extensionFactory = OpenIdExtensionFactoryAggregator.LoadFromConfiguration();

			List<IChannelBindingElement> elements = new List<IChannelBindingElement>(8);
			elements.Add(new ExtensionsBindingElement(extensionFactory, securitySettings, true));
			elements.Add(new StandardReplayProtectionBindingElement(nonceStore, true));
			elements.Add(new StandardExpirationBindingElement());
			elements.Add(signingElement);

			return elements.ToArray();
		}
		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);
		}
		/// <summary>
		/// Creates a Provider's response to an incoming association request.
		/// </summary>
		/// <param name="requestMessage">The request message.</param>
		/// <param name="associationStore">The association store.</param>
		/// <param name="securitySettings">The security settings on the Provider.</param>
		/// <returns>
		/// The appropriate association response that is ready to be sent back to the Relying Party.
		/// </returns>
		/// <remarks>
		///   <para>If an association is created, it will be automatically be added to the provided
		/// association store.</para>
		///   <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>.
		/// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para>
		/// </remarks>
		internal static IProtocolMessage CreateResponse(IAssociateRequestProvider requestMessage, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(requestMessage, "requestMessage");
			Requires.NotNull(associationStore, "associationStore");
			Requires.NotNull(securitySettings, "securitySettings");

			AssociateRequest request = (AssociateRequest)requestMessage;
			IProtocolMessage response;
			var protocol = requestMessage.GetProtocol();
			if (securitySettings.IsAssociationInPermittedRange(protocol, request.AssociationType) &&
				HmacShaAssociation.IsDHSessionCompatible(protocol, request.AssociationType, request.SessionType)) {
				response = requestMessage.CreateResponseCore();

				// Create and store the association if this is a successful response.
				var successResponse = response as IAssociateSuccessfulResponseProvider;
				if (successResponse != null) {
					OpenIdProviderUtilities.CreateAssociation(request, successResponse, associationStore, securitySettings);
				}
			} else {
				response = CreateUnsuccessfulResponse(requestMessage, securitySettings);
			}

			return response;
		}
        /// <summary>
        /// Called to create the Association based on a request previously given by the Relying Party.
        /// </summary>
        /// <param name="request">The prior request for an association.</param>
        /// <param name="response">The response.</param>
        /// <param name="associationStore">The Provider's association store.</param>
        /// <param name="securitySettings">The security settings for the Provider.  Should be <c>null</c> for Relying Parties.</param>
        /// <returns>
        /// The created association.
        /// </returns>
        /// <remarks>
        /// The response message is updated to include the details of the created association by this method.
        /// This method is called by both the Provider and the Relying Party, but actually performs
        /// quite different operations in either scenario.
        /// </remarks>
        internal static Association CreateAssociation(AssociateRequest request, IAssociateSuccessfulResponseProvider response, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(request, "request");
            Requires.NotNull(response, "response");
            Requires.NotNull(securitySettings, "securitySettings");

            // We need to initialize some common properties based on the created association.
            var association = response.CreateAssociationAtProvider(request, associationStore, securitySettings);

            response.ExpiresIn         = association.SecondsTillExpiration;
            response.AssociationHandle = association.Handle;

            return(association);
        }
		/// <summary>
		/// Creates a deep clone of this instance.
		/// </summary>
		/// <returns>A new instance that is a deep clone of this instance.</returns>
		internal ProviderSecuritySettings Clone() {
			var securitySettings = new ProviderSecuritySettings();
			foreach (var pair in this.AssociationLifetimes) {
				securitySettings.AssociationLifetimes.Add(pair);
			}

			securitySettings.MaximumHashBitLength = this.MaximumHashBitLength;
			securitySettings.MinimumHashBitLength = this.MinimumHashBitLength;
			securitySettings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks;
			securitySettings.RequireSsl = this.RequireSsl;
			securitySettings.SignOutgoingExtensions = this.SignOutgoingExtensions;
			securitySettings.UnsolicitedAssertionVerification = this.UnsolicitedAssertionVerification;

			return securitySettings;
		}
Beispiel #20
0
        /// <summary>
        /// Creates a new association of a given type at an OpenID Provider.
        /// </summary>
        /// <param name="protocol">The protocol.</param>
        /// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param>
        /// <param name="associationUse">A value indicating whether the new association will be used privately by the Provider for "dumb mode" authentication
        /// or shared with the Relying Party for "smart mode" authentication.</param>
        /// <param name="associationStore">The Provider's association store.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>
        /// The newly created association.
        /// </returns>
        /// <remarks>
        /// The new association is NOT automatically put into an association store.  This must be done by the caller.
        /// </remarks>
        internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(protocol, "protocol");
            Requires.NotNullOrEmpty(associationType, "associationType");
            Requires.NotNull(associationStore, "associationStore");
            Requires.NotNull(securitySettings, "securitySettings");

            int secretLength = HmacShaAssociation.GetSecretLength(protocol, associationType);

            // Generate the secret that will be used for signing
            byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength);

            TimeSpan lifetime;

            if (associationUse == AssociationRelyingPartyType.Smart)
            {
                if (!securitySettings.AssociationLifetimes.TryGetValue(associationType, out lifetime))
                {
                    lifetime = DefaultMaximumLifetime;
                }
            }
            else
            {
                lifetime = HmacShaAssociation.DumbSecretLifetime;
            }

            string handle = associationStore.Serialize(secret, DateTime.UtcNow + lifetime, associationUse == AssociationRelyingPartyType.Dumb);

            Assumes.True(protocol != null);             // All the way up to the method call, the condition holds, yet we get a Requires failure next
            Assumes.True(secret != null);
            Assumes.True(!string.IsNullOrEmpty(associationType));
            var result = HmacShaAssociation.Create(protocol, associationType, handle, secret, lifetime);

            return(result);
        }
		/// <summary>
		/// Initializes a new instance of the <see cref="OpenIdProviderChannel"/> class.
		/// </summary>
		/// <param name="cryptoKeyStore">The OpenID Provider's association store or handle encoder.</param>
		/// <param name="nonceStore">The nonce store to use.</param>
		/// <param name="securitySettings">The security settings.</param>
		internal OpenIdProviderChannel(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
			: this(cryptoKeyStore, nonceStore, new OpenIdProviderMessageFactory(), securitySettings) {
			Requires.NotNull(cryptoKeyStore, "cryptoKeyStore");
			Requires.NotNull(securitySettings, "securitySettings");
		}
Beispiel #22
0
		/// <summary>
		/// Simulates an extension request and response.
		/// </summary>
		/// <param name="protocol">The protocol to use in the roundtripping.</param>
		/// <param name="requests">The extensions to add to the request message.</param>
		/// <param name="responses">The extensions to add to the response message.</param>
		/// <remarks>
		/// This method relies on the extension objects' Equals methods to verify
		/// accurate transport.  The Equals methods should be verified by separate tests.
		/// </remarks>
		internal async Task RoundtripAsync(
			Protocol protocol, IEnumerable<IOpenIdMessageExtension> requests, IEnumerable<IOpenIdMessageExtension> responses) {
			var securitySettings = new ProviderSecuritySettings();
			var cryptoKeyStore = new MemoryCryptoKeyStore();
			var associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
			Association association = HmacShaAssociationProvider.Create(
				protocol,
				protocol.Args.SignatureAlgorithm.Best,
				AssociationRelyingPartyType.Smart,
				associationStore,
				securitySettings);

			this.HandleProvider(
				async (op, req) => {
					ExtensionTestUtilities.RegisterExtension(op.Channel, Mocks.MockOpenIdExtension.Factory);
					var key = cryptoKeyStore.GetCurrentKey(
						ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
					op.CryptoKeyStore.StoreKey(
						ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
					var request = await op.Channel.ReadFromRequestAsync<CheckIdRequest>(req, CancellationToken.None);
					var response = new PositiveAssertionResponse(request);
					var receivedRequests = request.Extensions.Cast<IOpenIdMessageExtension>();
					CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(requests.ToArray(), receivedRequests.ToArray());

					foreach (var extensionResponse in responses) {
						response.Extensions.Add(extensionResponse);
					}

					return await op.Channel.PrepareResponseAsync(response);
				});

			{
				var rp = this.CreateRelyingParty();
				ExtensionTestUtilities.RegisterExtension(rp.Channel, Mocks.MockOpenIdExtension.Factory);
				var requestBase = new CheckIdRequest(protocol.Version, OpenIdTestBase.OPUri, AuthenticationRequestMode.Immediate);
				OpenIdTestBase.StoreAssociation(rp, OpenIdTestBase.OPUri, association);
				requestBase.AssociationHandle = association.Handle;
				requestBase.ClaimedIdentifier = "http://claimedid";
				requestBase.LocalIdentifier = "http://localid";
				requestBase.ReturnTo = OpenIdTestBase.RPUri;

				foreach (IOpenIdMessageExtension extension in requests) {
					requestBase.Extensions.Add(extension);
				}

				var redirectingRequest = await rp.Channel.PrepareResponseAsync(requestBase);
				Uri redirectingResponseUri;
				this.HostFactories.AllowAutoRedirects = false;
				using (var httpClient = rp.Channel.HostFactories.CreateHttpClient()) {
					using (var redirectingResponse = await httpClient.GetAsync(redirectingRequest.Headers.Location)) {
						Assert.AreEqual(HttpStatusCode.Found, redirectingResponse.StatusCode);
						redirectingResponseUri = redirectingResponse.Headers.Location;
					}
				}

				var response =
					await
					rp.Channel.ReadFromRequestAsync<PositiveAssertionResponse>(
						new HttpRequestMessage(HttpMethod.Get, redirectingResponseUri), CancellationToken.None);
				var receivedResponses = response.Extensions.Cast<IOpenIdMessageExtension>();
				CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray());
			}
		}
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings of the Provider.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		Association IAssociateSuccessfulResponseProvider.CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Requires.NotNull(request, "request");
			Requires.NotNull(associationStore, "associationStore");
			Requires.NotNull(securitySettings, "securitySettings");
			throw new NotImplementedException();
		}
		/// <summary>
		/// Applies a well known set of security requirements to a default set of security settings.
		/// </summary>
		/// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
		/// <remarks>
		/// Care should be taken to never decrease security when applying a profile.
		/// Profiles should only enhance security requirements to avoid being
		/// incompatible with each other.
		/// </remarks>
		void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings) {
			// No special security to apply here.
		}
		/// <summary>
		/// Creates a new association of a given type.
		/// </summary>
		/// <param name="protocol">The protocol.</param>
		/// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param>
		/// <param name="associationUse">A value indicating whether the new association will be used privately by the Provider for "dumb mode" authentication
		/// or shared with the Relying Party for "smart mode" authentication.</param>
		/// <param name="securitySettings">The security settings of the Provider.</param>
		/// <returns>The newly created association.</returns>
		/// <remarks>
		/// The new association is NOT automatically put into an association store.  This must be done by the caller.
		/// </remarks>
		internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, ProviderSecuritySettings securitySettings) {
			Contract.Requires<ArgumentNullException>(protocol != null);
			Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(associationType));
			Contract.Requires<ArgumentNullException>(securitySettings != null);
			Contract.Ensures(Contract.Result<HmacShaAssociation>() != null);

			int secretLength = GetSecretLength(protocol, associationType);

			// Generate the handle.  It must be unique, and preferably unpredictable,
			// so we use a time element and a random data element to generate it.
			string uniq = MessagingUtilities.GetCryptoRandomDataAsBase64(4);
			string handle = string.Format(
				CultureInfo.InvariantCulture,
				"{{{0}}}{{{1}}}{{{2}}}",
				DateTime.UtcNow.Ticks,
				uniq,
				secretLength);

			// Generate the secret that will be used for signing
			byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength);

			TimeSpan lifetime;
			if (associationUse == AssociationRelyingPartyType.Smart) {
				if (!securitySettings.AssociationLifetimes.TryGetValue(associationType, out lifetime)) {
					lifetime = DefaultMaximumLifetime;
				}
			} else {
				lifetime = DumbSecretLifetime;
			}

			Contract.Assert(protocol != null); // All the way up to the method call, the condition holds, yet we get a Requires failure next
			Contract.Assert(secret != null);
			Contract.Assert(!String.IsNullOrEmpty(associationType));
			return Create(protocol, associationType, handle, secret, lifetime);
		}
Beispiel #26
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AutoResponsiveRequest"/> class.
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="response">The response that is ready for transmittal.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal AutoResponsiveRequest(IDirectedProtocolMessage request, IProtocolMessage response, ProviderSecuritySettings securitySettings)
            : base(request, securitySettings)
        {
            Requires.NotNull(response, "response");

            this.response = response;
        }
		/// <summary>
		/// Called to create the Association based on a request previously given by the Relying Party.
		/// </summary>
		/// <param name="request">The prior request for an association.</param>
		/// <param name="associationStore">The Provider's association store.</param>
		/// <param name="securitySettings">The security settings of the Provider.</param>
		/// <returns>
		/// The created association.
		/// </returns>
		/// <remarks>
		///   <para>The caller will update this message's
		///   <see cref="AssociateSuccessfulResponse.ExpiresIn"/> and
		///   <see cref="AssociateSuccessfulResponse.AssociationHandle"/>
		/// properties based on the <see cref="Association"/> returned by this method, but any other
		/// association type specific properties must be set by this method.</para>
		///   <para>The response message is updated to include the details of the created association by this method,
		/// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
		/// </remarks>
		public Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Association association = HmacShaAssociationProvider.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings);
			this.MacKey = association.SecretKey;
			return association;
		}
        /// <summary>
        /// Initializes a new instance of the <see cref="AutoResponsiveRequest"/> class.
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="response">The response that is ready for transmittal.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal AutoResponsiveRequest(IDirectedProtocolMessage request, IProtocolMessage response, ProviderSecuritySettings securitySettings)
            : base(request, securitySettings)
        {
            Contract.Requires <ArgumentNullException>(response != null);

            this.response = response;
        }
		/// <summary>
		/// Initializes a new instance of the <see cref="OpenIdProviderChannel"/> class.
		/// </summary>
		/// <param name="cryptoKeyStore">The association store to use.</param>
		/// <param name="nonceStore">The nonce store to use.</param>
		/// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
		/// <param name="securitySettings">The security settings.</param>
		private OpenIdProviderChannel(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, ProviderSecuritySettings securitySettings)
			: base(messageTypeProvider, InitializeBindingElements(cryptoKeyStore, nonceStore, securitySettings)) {
			Requires.NotNull(cryptoKeyStore, "cryptoKeyStore");
			Requires.NotNull(messageTypeProvider, "messageTypeProvider");
			Requires.NotNull(securitySettings, "securitySettings");
		}
		/// <summary>
		/// Applies a well known set of security requirements to a default set of security settings.
		/// </summary>
		/// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
		/// <remarks>
		/// Care should be taken to never decrease security when applying a profile.
		/// Profiles should only enhance security requirements to avoid being
		/// incompatible with each other.
		/// </remarks>
		void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings) {
			// Nothing to do here.
		}
Beispiel #31
0
		/// <summary>
		/// Creates a Provider's response to an incoming association request.
		/// </summary>
		/// <param name="associationStore">The association store.</param>
		/// <param name="securitySettings">The security settings on the Provider.</param>
		/// <returns>
		/// The appropriate association response that is ready to be sent back to the Relying Party.
		/// </returns>
		/// <remarks>
		///   <para>If an association is created, it will be automatically be added to the provided
		/// association store.</para>
		///   <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>.
		/// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para>
		/// </remarks>
		internal IProtocolMessage CreateResponse(IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) {
			Contract.Requires<ArgumentNullException>(associationStore != null);
			Contract.Requires<ArgumentNullException>(securitySettings != null);

			IProtocolMessage response;
			if (securitySettings.IsAssociationInPermittedRange(Protocol, this.AssociationType) &&
				HmacShaAssociation.IsDHSessionCompatible(Protocol, this.AssociationType, this.SessionType)) {
				response = this.CreateResponseCore();

				// Create and store the association if this is a successful response.
				var successResponse = response as AssociateSuccessfulResponse;
				if (successResponse != null) {
					successResponse.CreateAssociation(this, associationStore, securitySettings);
				}
			} else {
				response = this.CreateUnsuccessfulResponse(securitySettings);
			}

			return response;
		}
		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();
		}
Beispiel #33
0
 /// <summary>
 /// Applies a well known set of security requirements to a default set of security settings.
 /// </summary>
 /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
 /// <remarks>
 /// Care should be taken to never decrease security when applying a profile.
 /// Profiles should only enhance security requirements to avoid being
 /// incompatible with each other.
 /// </remarks>
 void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings)
 {
     Contract.Requires <ArgumentNullException>(securitySettings != null);
     throw new System.NotImplementedException();
 }
 /// <summary>
 /// Initializes a programmatically manipulatable bag of these security settings with the settings from the config file.
 /// </summary>
 /// <returns>The newly created security settings object.</returns>
 public ProviderSecuritySettings CreateSecuritySettings()
 {
     ProviderSecuritySettings settings = new ProviderSecuritySettings();
     settings.MinimumHashBitLength = this.MinimumHashBitLength;
     settings.MaximumHashBitLength = this.MaximumHashBitLength;
     settings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks;
     foreach (AssociationTypeElement element in this.AssociationLifetimes) {
         Contract.Assume(element != null);
         settings.AssociationLifetimes.Add(element.AssociationType, element.MaximumLifetime);
     }
     return settings;
 }
Beispiel #35
0
 /// <summary>
 /// Applies a well known set of security requirements to a default set of security settings.
 /// </summary>
 /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
 /// <remarks>
 /// Care should be taken to never decrease security when applying a profile.
 /// Profiles should only enhance security requirements to avoid being
 /// incompatible with each other.
 /// </remarks>
 void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings)
 {
     Requires.NotNull(securitySettings, "securitySettings");
     throw new System.NotImplementedException();
 }
Beispiel #36
0
        /// <summary>
        /// Creates a Provider's response to an incoming association request.
        /// </summary>
        /// <param name="associationStore">The association store where a new association (if created) will be stored.  Must not be null.</param>
        /// <param name="securitySettings">The security settings on the Provider.</param>
        /// <returns>
        /// The appropriate association response that is ready to be sent back to the Relying Party.
        /// </returns>
        /// <remarks>
        /// <para>If an association is created, it will be automatically be added to the provided
        /// association store.</para>
        /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>.
        /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para>
        /// </remarks>
        internal IProtocolMessage CreateResponse(IAssociationStore<AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(associationStore, "associationStore");
            ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");

            IProtocolMessage response;
            if (securitySettings.IsAssociationInPermittedRange(Protocol, this.AssociationType) &&
                HmacShaAssociation.IsDHSessionCompatible(Protocol, this.AssociationType, this.SessionType)) {
                response = this.CreateResponseCore();

                // Create and store the association if this is a successful response.
                var successResponse = response as AssociateSuccessfulResponse;
                if (successResponse != null) {
                    Association association = successResponse.CreateAssociation(this, securitySettings);
                    associationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association);
                }
            } else {
                response = this.CreateUnsuccessfulResponse(securitySettings);
            }

            return response;
        }