public async Task CreateClientFormsTheCorrectEndpoint()
        {
            var options      = new EventHubClientOptions();
            var host         = "my.eventhub.com";
            var eventHubPath = "some-path";
            var resource     = $"amqps://{ host }/{ eventHubPath }";
            var signature    = new SharedAccessSignature(resource, "keyName", "KEY", TimeSpan.FromHours(1));
            var credential   = new SharedAccessSignatureCredential(signature);
            var client       = (AmqpEventHubClient)TrackOneEventHubClient.CreateClient(host, eventHubPath, credential, options);

            try
            {
                var endpoint = client.ConnectionStringBuilder.Endpoint;
                Assert.That(endpoint.Scheme.ToLowerInvariant(), Contains.Substring(options.TransportType.GetUriScheme().ToLowerInvariant()), "The scheme should be part of the endpoint.");
                Assert.That(endpoint.Host.ToLowerInvariant(), Contains.Substring(host.ToLowerInvariant()), "The host should be part of the endpoint.");
                Assert.That(endpoint.AbsolutePath.ToLowerInvariant(), Contains.Substring(eventHubPath.ToLowerInvariant()), "The host should be part of the endpoint.");
            }
            finally
            {
                await client?.CloseAsync();
            }
        }
Пример #2
0
        public void AsSharedAccessSignatureCredentialShouldRefreshTokenValidityForSharedKeys()
        {
            var beforeResource    = "amqps://before/path";
            var afterResource     = "amqps://after/path";
            var beforeSpan        = TimeSpan.FromHours(4);
            var afterSpan         = TimeSpan.FromHours(8);
            var keyName           = "keyName";
            var keyValue          = "keyValue";
            var expectedSignature = new SharedAccessSignature(beforeResource, keyName, keyValue, beforeSpan);
            var keyCredential     = new EventHubsSharedAccessKeyCredential(keyName, keyValue);

            SharedAccessSignatureCredential sasCredential   = keyCredential.AsSharedAccessSignatureCredential(beforeResource, beforeSpan);
            SharedAccessSignature           beforeSignature = GetSharedAccessSignature(sasCredential);

            Assert.That(beforeSignature.SignatureExpiration, Is.EqualTo(expectedSignature.SignatureExpiration).Within(TimeSpan.FromSeconds(5)), "The expiration should match.");

            expectedSignature = new SharedAccessSignature(afterResource, keyName, keyValue, afterSpan);
            sasCredential     = keyCredential.AsSharedAccessSignatureCredential(afterResource, afterSpan);
            SharedAccessSignature afterSignature = GetSharedAccessSignature(sasCredential);

            Assert.That(afterSignature.SignatureExpiration, Is.EqualTo(expectedSignature.SignatureExpiration).Within(TimeSpan.FromSeconds(5)), "The expiration should match.");
        }
Пример #3
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="ServiceBusConnection"/> class.
        /// </summary>
        ///
        /// <param name="connectionString">The connection string to use for connecting to the Service Bus namespace.</param>
        /// <param name="options">A set of options to apply when configuring the connection.</param>
        ///
        /// <remarks>
        ///   If the connection string is copied from the Service Bus entity itself, it will contain the name of the desired Service Bus entity,
        ///   and can be used directly without passing the  name="entityName" />.  The name of the Service Bus entity should be
        ///   passed only once, either as part of the connection string or separately.
        /// </remarks>
        ///
        internal ServiceBusConnection(
            string connectionString,
            ServiceBusClientOptions options)
        {
            Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString));
            ValidateConnectionOptions(options);

            var connectionStringProperties = ServiceBusConnectionStringProperties.Parse(connectionString);

            ValidateConnectionStringProperties(connectionStringProperties, nameof(connectionString));

            FullyQualifiedNamespace = connectionStringProperties.Endpoint.Host;
            TransportType           = options.TransportType;
            EntityPath   = connectionStringProperties.EntityPath;
            RetryOptions = options.RetryOptions;

            SharedAccessSignature sharedAccessSignature;

            if (string.IsNullOrEmpty(connectionStringProperties.SharedAccessSignature))
            {
                sharedAccessSignature = new SharedAccessSignature(
                    BuildConnectionResource(options.TransportType, FullyQualifiedNamespace, EntityPath),
                    connectionStringProperties.SharedAccessKeyName,
                    connectionStringProperties.SharedAccessKey);
            }
            else
            {
                sharedAccessSignature = new SharedAccessSignature(connectionStringProperties.SharedAccessSignature);
            }

            var sharedCredential = new SharedAccessSignatureCredential(sharedAccessSignature);
            var tokenCredential  = new ServiceBusTokenCredential(
                sharedCredential,
                BuildConnectionResource(TransportType, FullyQualifiedNamespace, EntityPath));

#pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes.
            _innerClient = CreateTransportClient(tokenCredential, options);
#pragma warning restore CA2214 // Do not call overridable methods in constructors
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="ServiceBusConnection"/> class.
        /// </summary>
        ///
        /// <param name="connectionString">The connection string to use for connecting to the Service Bus namespace.</param>
        /// <param name="options">A set of options to apply when configuring the connection.</param>
        ///
        /// <remarks>
        ///   If the connection string is copied from the Service Bus entity itself, it will contain the name of the desired Service Bus entity,
        ///   and can be used directly without passing the  name="entityName" />.  The name of the Service Bus entity should be
        ///   passed only once, either as part of the connection string or separately.
        /// </remarks>
        ///
        internal ServiceBusConnection(
            string connectionString,
            ServiceBusClientOptions options)
        {
            Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString));

            options = options?.Clone() ?? new ServiceBusClientOptions();

            ValidateConnectionOptions(options);
            ConnectionStringProperties connectionStringProperties = ConnectionStringParser.Parse(connectionString);

            if (string.IsNullOrEmpty(connectionStringProperties.Endpoint?.Host) ||
                string.IsNullOrEmpty(connectionStringProperties.SharedAccessKeyName) ||
                string.IsNullOrEmpty(connectionStringProperties.SharedAccessKey))
            {
                throw new ArgumentException(Resources1.MissingConnectionInformation, nameof(connectionString));
            }

            FullyQualifiedNamespace = connectionStringProperties.Endpoint.Host;
            TransportType           = options.TransportType;
            EntityPath   = connectionStringProperties.EntityPath;
            Options      = options;
            RetryOptions = options.RetryOptions;

            var sharedAccessSignature = new SharedAccessSignature
                                        (
                BuildAudienceResource(options.TransportType, FullyQualifiedNamespace, EntityPath),
                connectionStringProperties.SharedAccessKeyName,
                connectionStringProperties.SharedAccessKey
                                        );

            var sharedCredential = new SharedAccessSignatureCredential(sharedAccessSignature);
            var tokenCredential  = new ServiceBusTokenCredential(
                sharedCredential,
                BuildAudienceResource(TransportType, FullyQualifiedNamespace, EntityPath));

            _innerClient = CreateTransportClient(tokenCredential, options);
        }
Пример #5
0
        public async Task ConnectionTransportCanRetrievePartitionProperties(EventHubsTransportType transportType)
        {
            var partitionCount = 4;

            await using (EventHubScope scope = await EventHubScope.CreateAsync(partitionCount))
            {
                var options = new EventHubConnectionOptions();

                var credential = new SharedAccessSignatureCredential
                                 (
                    new SharedAccessSignature
                    (
                        $"{ options.TransportType.GetUriScheme() }://{ TestEnvironment.FullyQualifiedNamespace }/{ scope.EventHubName }".ToLowerInvariant(),
                        TestEnvironment.SharedAccessKeyName,
                        TestEnvironment.SharedAccessKey,
                        TimeSpan.FromHours(4)
                    )
                                 );

                await using (var connection = new TestConnectionWithTransport(TestEnvironment.FullyQualifiedNamespace, scope.EventHubName, credential, new EventHubConnectionOptions {
                    TransportType = transportType
                }))
                {
                    var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20));
                    var properties   = await connection.GetPropertiesAsync();

                    var partition           = properties.PartitionIds.First();
                    var partitionProperties = await connection.GetPartitionPropertiesAsync(partition, cancellation.Token);

                    Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned.");
                    Assert.That(partitionProperties.Id, Is.EqualTo(partition), "The partition identifier should match.");
                    Assert.That(partitionProperties.EventHubName, Is.EqualTo(scope.EventHubName).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match.");
                    Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(long)), "The beginning sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(long)), "The last sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.EqualTo(default(long)), "The last offset should have been populated.");
                }
            }
        }
Пример #6
0
        public async Task ClientCanRetrievePartitionProperties()
        {
            var partitionCount = 4;

            await using (var scope = await EventHubScope.CreateAsync(partitionCount))
            {
                var clientOptions        = new EventHubClientOptions();
                var connectionString     = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var connectionProperties = ConnectionStringParser.Parse(connectionString);

                var credential = new SharedAccessSignatureCredential
                                 (
                    new SharedAccessSignature
                    (
                        $"{ clientOptions.TransportType.GetUriScheme() }://{ connectionProperties.Endpoint.Host }/{ connectionProperties.EventHubPath }".ToLowerInvariant(),
                        connectionProperties.SharedAccessKeyName,
                        connectionProperties.SharedAccessKey,
                        TimeSpan.FromHours(4)
                    )
                                 );

                await using (var client = new EventHubClient(connectionProperties.Endpoint.Host, connectionProperties.EventHubPath, credential))
                {
                    var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20));
                    var properties   = await client.GetPropertiesAsync();

                    var partition           = properties.PartitionIds.First();
                    var partitionProperties = await client.GetPartitionPropertiesAsync(partition, cancellation.Token);

                    Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned.");
                    Assert.That(partitionProperties.Id, Is.EqualTo(partition), "The partition identifier should match.");
                    Assert.That(partitionProperties.EventHubPath, Is.EqualTo(connectionProperties.EventHubPath).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match.");
                    Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(Int64)), "The beginning sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(Int64)), "The last sequance number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.Null.Or.Empty, "The last offset should have been populated.");
                }
            }
        }
Пример #7
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="EventHubConnection"/> class.
        /// </summary>
        ///
        /// <param name="connectionString">The connection string to use for connecting to the Event Hubs namespace; it is expected that the shared key properties are contained in this connection string, but not the Event Hub name.</param>
        /// <param name="eventHubName">The name of the specific Event Hub to associate the connection with.</param>
        /// <param name="connectionOptions">A set of options to apply when configuring the connection.</param>
        ///
        /// <remarks>
        ///   If the connection string is copied from the Event Hub itself, it will contain the name of the desired Event Hub,
        ///   and can be used directly without passing the <paramref name="eventHubName" />.  The name of the Event Hub should be
        ///   passed only once, either as part of the connection string or separately.
        /// </remarks>
        ///
        public EventHubConnection(string connectionString,
                                  string eventHubName,
                                  EventHubConnectionOptions connectionOptions)
        {
            Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString));

            connectionOptions = connectionOptions?.Clone() ?? new EventHubConnectionOptions();
            ValidateConnectionOptions(connectionOptions);

            ConnectionStringProperties connectionStringProperties = ConnectionStringParser.Parse(connectionString);

            ValidateConnectionProperties(connectionStringProperties, eventHubName, nameof(connectionString));

            var fullyQualifiedNamespace = connectionStringProperties.Endpoint.Host;

            if (string.IsNullOrEmpty(eventHubName))
            {
                eventHubName = connectionStringProperties.EventHubName;
            }

            var sharedAccessSignature = new SharedAccessSignature
                                        (
                BuildAudienceResource(connectionOptions.TransportType, fullyQualifiedNamespace, eventHubName),
                connectionStringProperties.SharedAccessKeyName,
                connectionStringProperties.SharedAccessKey
                                        );

            var sharedCredentials = new SharedAccessSignatureCredential(sharedAccessSignature);
            var tokenCredentials  = new EventHubTokenCredential(sharedCredentials, BuildAudienceResource(connectionOptions.TransportType, fullyQualifiedNamespace, eventHubName));

            FullyQualifiedNamespace = fullyQualifiedNamespace;
            EventHubName            = eventHubName;
            Options = connectionOptions;

#pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes.
            InnerClient = CreateTransportClient(fullyQualifiedNamespace, eventHubName, tokenCredentials, connectionOptions);
#pragma warning restore CA2214 // Do not call overridable methods in constructors.
        }
Пример #8
0
        public async Task CreateClientPopulatesTheProxy()
        {
            var options = new EventHubClientOptions
            {
                TransportType = TransportType.AmqpWebSockets,
                Proxy         = Mock.Of <IWebProxy>()
            };

            var host         = "my.eventhub.com";
            var eventHubPath = "some-path";
            var signature    = new SharedAccessSignature(options.TransportType, host, eventHubPath, "keyName", "KEY", TimeSpan.FromHours(1));
            var credential   = new SharedAccessSignatureCredential(signature);
            var client       = (AmqpEventHubClient)TrackOneEventHubClient.CreateClient(host, eventHubPath, credential, options);

            try
            {
                Assert.That(client.WebProxy, Is.SameAs(options.Proxy), "The client should honor the proxy.");
            }
            finally
            {
                await client?.CloseAsync();
            }
        }
Пример #9
0
        public async Task ConnectionCanConnectToEventHubsUsingArguments()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var options = new EventHubConnectionOptions();

                var credential = new SharedAccessSignatureCredential
                                 (
                    new SharedAccessSignature
                    (
                        $"{ options.TransportType.GetUriScheme() }://{ TestEnvironment.FullyQualifiedNamespace }/{ scope.EventHubName }".ToLowerInvariant(),
                        TestEnvironment.SharedAccessKeyName,
                        TestEnvironment.SharedAccessKey,
                        TimeSpan.FromHours(4)
                    )
                                 );

                await using (var connection = new TestConnectionWithTransport(TestEnvironment.FullyQualifiedNamespace, scope.EventHubName, credential))
                {
                    Assert.That(() => connection.GetPropertiesAsync(), Throws.Nothing);
                }
            }
        }
Пример #10
0
 /// <summary>
 ///   Retrieves the shared access signature from the credential using its private accessor.
 /// </summary>
 ///
 /// <param name="instance">The instance to retrieve the key from.</param>
 ///
 /// <returns>The shared access key</returns>
 ///
 private static SharedAccessSignature GetSharedAccessSignature(SharedAccessSignatureCredential instance) =>
 (SharedAccessSignature)
 typeof(SharedAccessSignatureCredential)
 .GetProperty("SharedAccessSignature", BindingFlags.Instance | BindingFlags.NonPublic)
 .GetValue(instance, null);