< Summary

Class:Azure.Iot.Hub.Service.Authentication.IotHubSasCredential
Assembly:Azure.Iot.Hub.Service
File(s):C:\Git\azure-sdk-for-net\sdk\iot\Azure.Iot.Hub.Service\src\Authentication\IotHubSasCredential.cs
Covered lines:49
Uncovered lines:0
Coverable lines:49
Total lines:143
Line coverage:100% (49 of 49)
Covered branches:8
Total branches:8
Branch coverage:100% (8 of 8)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-100%100%
.ctor(...)-100%100%
SetCredentials(...)-100%100%
get_Endpoint()-100%100%
get_SharedAccessPolicy()-100%100%
get_SharedAccessKey()-100%100%
get_SasTokenTimeToLive()-100%100%
BuildEndpointUriFromHostName(...)-100%100%
GetSasToken()-100%100%
TokenShouldBeGenerated()-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\iot\Azure.Iot.Hub.Service\src\Authentication\IotHubSasCredential.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using Azure.Core;
 6
 7namespace Azure.Iot.Hub.Service.Authentication
 8{
 9    /// <summary>
 10    /// The IoT Hub credentials, to be used for authenticating against an IoT Hub instance via SAS tokens.
 11    /// </summary>
 12    public class IotHubSasCredential : ISasTokenProvider
 13    {
 14        // Time buffer before expiry when the token should be renewed, expressed as a percentage of the time to live.
 15        // The token will be renewed when it has 15% or less of the sas token's lifespan left.
 16        private const int RenewalTimeBufferPercentage = 15;
 17
 8818        private readonly object _lock = new object();
 19
 20        private string _cachedSasToken;
 21        private DateTimeOffset _tokenExpiryTime;
 22
 7623        internal IotHubSasCredential(string connectionString)
 24        {
 7625            Argument.AssertNotNullOrWhiteSpace(connectionString, nameof(connectionString));
 26
 7627            var iotHubConnectionString = ConnectionString.Parse(connectionString);
 28
 7629            var sharedAccessPolicy = iotHubConnectionString.GetRequired(SharedAccessSignatureConstants.SharedAccessPolic
 7630            var sharedAccessKey = iotHubConnectionString.GetRequired(SharedAccessSignatureConstants.SharedAccessKeyIdent
 31
 7632            Endpoint = BuildEndpointUriFromHostName(iotHubConnectionString.GetRequired(SharedAccessSignatureConstants.Ho
 7633            SetCredentials(sharedAccessPolicy, sharedAccessKey);
 7634        }
 35
 36        /// <summary>
 37        /// Initializes a new instance of <see cref="IotHubSasCredential"/> class.
 38        /// </summary>
 39        /// <param name="sharedAccessPolicy">
 40        /// The IoT Hub access permission, which can be either "iothubowner", "service", "registryRead" or "registryRead
 41        /// For more information, see <see href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-securit
 42        /// </param>
 43        /// <param name="sharedAccessKey">
 44        /// The IoT Hub shared access key associated with the shared access policy permissions.
 45        /// </param>
 46        /// <param name="timeToLive">
 47        /// (Optional) The validity duration of the generated shared access signature token used for authentication.
 48        /// The token will be renewed when at 15% or less of it's lifespan. The default value is 30 minutes.
 49        /// </param>
 1250        public IotHubSasCredential(string sharedAccessPolicy, string sharedAccessKey, TimeSpan timeToLive = default)
 51        {
 1252            Argument.AssertNotNullOrWhiteSpace(sharedAccessPolicy, nameof(sharedAccessPolicy));
 1053            Argument.AssertNotNullOrWhiteSpace(sharedAccessKey, nameof(sharedAccessKey));
 54
 855            SetCredentials(sharedAccessPolicy, sharedAccessKey, timeToLive);
 656        }
 57
 58        private void SetCredentials(string sharedAccessPolicy, string sharedAccessKey, TimeSpan timeToLive = default)
 59        {
 8460            SharedAccessPolicy = sharedAccessPolicy;
 8461            SharedAccessKey = sharedAccessKey;
 62
 8463            if (!timeToLive.Equals(TimeSpan.Zero))
 64            {
 665                if (timeToLive.CompareTo(TimeSpan.Zero) < 0)
 66                {
 267                    throw new ArgumentException("The value for SasTokenTimeToLive cannot be a negative TimeSpan", nameof
 68                }
 69
 470                SasTokenTimeToLive = timeToLive;
 71            }
 72
 8273            _cachedSasToken = null;
 8274        }
 75
 76        /// <summary>
 77        /// The IoT Hub service instance endpoint to connect to.
 78        /// </summary>
 46679        public Uri Endpoint { get; internal set; }
 80
 81        /// <summary>
 82        /// The IoT Hub access permission, which can be either "iothubowner", "service", "registryRead" or "registryRead
 83        /// For more information, see <see href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-securit
 84        /// </summary>
 16685        public string SharedAccessPolicy { get; private set; }
 86
 87        /// <summary>
 88        /// The IoT Hub shared access key associated with the shared access policy permissions.
 89        /// </summary>
 16690        public string SharedAccessKey { get; private set; }
 91
 92        /// <summary>
 93        /// The validity duration of the generated shared access signature token used for authentication.
 94        /// The token will be renewed when at 15% or less of its lifespan. The default value is 30 minutes.
 95        /// </summary>
 57696        public TimeSpan SasTokenTimeToLive { get; private set; } = TimeSpan.FromMinutes(30);
 97
 98        private static Uri BuildEndpointUriFromHostName(string hostName)
 99        {
 76100            return new UriBuilder
 76101            {
 76102                Scheme = Uri.UriSchemeHttps,
 76103                Host = hostName
 76104            }.Uri;
 105        }
 106
 107        public string GetSasToken()
 108        {
 398109            lock (_lock)
 110            {
 398111                if (TokenShouldBeGenerated())
 112                {
 82113                    var builder = new SharedAccessSignatureBuilder
 82114                    {
 82115                        HostName = Endpoint.Host,
 82116                        SharedAccessPolicy = SharedAccessPolicy,
 82117                        SharedAccessKey = SharedAccessKey,
 82118                        TimeToLive = SasTokenTimeToLive,
 82119                    };
 120
 82121                    _tokenExpiryTime = DateTimeOffset.UtcNow.Add(SasTokenTimeToLive);
 82122                    _cachedSasToken = builder.ToSignature();
 123                }
 124
 398125                return _cachedSasToken;
 126            }
 398127        }
 128
 129        private bool TokenShouldBeGenerated()
 130        {
 131            // The token needs to be generated if this is the first time it is being accessed (not cached yet)
 132            // or the current time is greater than or equal to the token expiry time, less 15% buffer.
 398133            if (_cachedSasToken == null)
 134            {
 80135                return true;
 136            }
 137
 318138            var bufferTimeInMilliseconds = (double)RenewalTimeBufferPercentage / 100 * SasTokenTimeToLive.TotalMilliseco
 318139            DateTimeOffset tokenExpiryTimeWithBuffer = _tokenExpiryTime.AddMilliseconds(-bufferTimeInMilliseconds);
 318140            return DateTimeOffset.UtcNow.CompareTo(tokenExpiryTimeWithBuffer) >= 0;
 141        }
 142    }
 143}