< Summary

Class:Azure.Storage.Sas.DataLakeSasBuilder
Assembly:Azure.Storage.Files.DataLake
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Files.DataLake\src\Sas\DataLakeSasBuilder.cs
Covered lines:144
Uncovered lines:10
Coverable lines:154
Total lines:443
Line coverage:93.5% (144 of 154)
Covered branches:22
Total branches:26
Branch coverage:84.6% (22 of 26)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
get_Version()-100%100%
get_Protocol()-100%100%
get_StartsOn()-100%100%
get_ExpiresOn()-100%100%
get_Permissions()-100%100%
get_IPRange()-100%100%
get_Identifier()-100%100%
get_FileSystemName()-100%100%
get_Path()-100%100%
get_Resource()-100%100%
get_CacheControl()-0%100%
get_ContentDisposition()-0%100%
get_ContentEncoding()-0%100%
get_ContentLanguage()-0%100%
get_ContentType()-0%100%
SetPermissions(...)-100%100%
SetPermissions(...)-0%100%
SetPermissions(...)-100%100%
SetPermissions(...)-100%100%
SetPermissions(...)-100%100%
.cctor()-100%100%
ToSasQueryParameters(...)-100%66.67%
ToSasQueryParameters(...)-100%66.67%
GetCanonicalName(...)-100%100%
ComputeHMACSHA256(...)-100%100%
EnsureState()-100%100%
ToString()-0%100%
Equals(...)-0%100%
GetHashCode()-0%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Files.DataLake\src\Sas\DataLakeSasBuilder.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.ComponentModel;
 7using System.Security.Cryptography;
 8using System.Text;
 9using Azure.Storage.Files.DataLake;
 10using Azure.Storage.Files.DataLake.Models;
 11
 12namespace Azure.Storage.Sas
 13{
 14    /// <summary>
 15    /// <see cref="DataLakeSasBuilder"/> is used to generate a Shared Access
 16    /// Signature (SAS) for a Data Lake file system or path
 17    ///
 18    /// For more information, see
 19    /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas">
 20    /// Constructing a Service SAS</see>.
 21    /// </summary>
 22    public class DataLakeSasBuilder
 23    {
 24        /// <summary>
 25        /// The storage service version to use to authenticate requests made
 26        /// with this shared access signature, and the service version to use
 27        /// when handling requests made with this shared access signature.
 28        /// </summary>
 36829        public string Version { get; set; }
 30
 31        /// <summary>
 32        /// The optional signed protocol field specifies the protocol
 33        /// permitted for a request made with the SAS.  Possible values are
 34        /// <see cref="SasProtocol.HttpsAndHttp"/>,
 35        /// <see cref="SasProtocol.Https"/>, and
 36        /// <see cref="SasProtocol.None"/>.
 37        /// </summary>
 26038        public SasProtocol Protocol { get; set; }
 39
 40        /// <summary>
 41        /// Optionally specify the time at which the shared access signature
 42        /// becomes valid.  If omitted when DateTimeOffset.MinValue is used,
 43        /// start time for this call is assumed to be the time when the
 44        /// storage service receives the request.
 45        /// </summary>
 26846        public DateTimeOffset StartsOn { get; set; }
 47
 48        /// <summary>
 49        /// The time at which the shared access signature becomes invalid.
 50        /// This field must be omitted if it has been specified in an
 51        /// associated stored access policy.
 52        /// </summary>
 35653        public DateTimeOffset ExpiresOn { get; set; }
 54
 55        /// <summary>
 56        /// The permissions associated with the shared access signature. The
 57        /// user is restricted to operations allowed by the permissions. This
 58        /// field must be omitted if it has been specified in an associated
 59        /// stored access policy.  The <see cref="DataLakeSasPermissions"/>,
 60        /// <see cref="DataLakeFileSystemSasPermissions"/>
 61        /// or <see cref="DataLakeAccountSasPermissions"/> can be used to create the
 62        /// permissions string.
 63        /// </summary>
 36464        public string Permissions { get; private set; }
 65
 66        /// <summary>
 67        /// Specifies an IP address or a range of IP addresses from which to
 68        /// accept requests. If the IP address from which the request
 69        /// originates does not match the IP address or address range
 70        /// specified on the SAS token, the request is not authenticated.
 71        /// When specifying a range of IP addresses, note that the range is
 72        /// inclusive.
 73        /// </summary>
 26074        public SasIPRange IPRange { get; set; }
 75
 76        /// <summary>
 77        /// An optional unique value up to 64 characters in length that
 78        /// correlates to an access policy specified for the file system.
 79        /// </summary>
 22880        public string Identifier { get; set; }
 81
 82        /// <summary>
 83        /// The name of the file system being made accessible.
 84        /// </summary>
 18485        public string FileSystemName { get; set; }
 86
 87        /// <summary>
 88        /// The name of the path being made accessible, or
 89        /// <see cref="String.Empty"/> for a file system SAS.
 90        /// </summary>
 22491        public string Path { get; set; }
 92
 93        /// <summary>
 94        /// Specifies which resources are accessible via the shared access
 95        /// signature.
 96        ///
 97        /// Specify "b" if the shared resource is a blob. This grants access to
 98        /// the content and metadata of the blob.
 99        ///
 100        /// Specify "c" if the shared resource is a blob container. This grants
 101        /// access to the content and metadata of any blob in the container,
 102        /// and to the list of blobs in the container.
 103        ///
 104        /// Beginning in version 2018-11-09, specify "bs" if the shared resource
 105        /// is a blob snapshot.  This grants access to the content and
 106        /// metadata of the specific snapshot, but not the corresponding root
 107        /// blob.
 108        /// </summary>
 276109        public string Resource { get; set; }
 110
 111        /// <summary>
 112        /// Override the value returned for Cache-Control response header.
 113        /// </summary>
 0114        public string CacheControl { get; set; }
 115
 116        /// <summary>
 117        /// Override the value returned for Content-Disposition response
 118        /// header.
 119        /// </summary>
 0120        public string ContentDisposition { get; set; }
 121
 122        /// <summary>
 123        /// Override the value returned for Cache-Encoding response header.
 124        /// </summary>
 0125        public string ContentEncoding { get; set; }
 126
 127        /// <summary>
 128        /// Override the value returned for Cache-Language response header.
 129        /// </summary>
 0130        public string ContentLanguage { get; set; }
 131
 132        /// <summary>
 133        /// Override the value returned for Cache-Type response header.
 134        /// </summary>
 0135        public string ContentType { get; set; }
 136
 137        /// <summary>
 138        /// Sets the permissions for a file SAS.
 139        /// </summary>
 140        /// <param name="permissions">
 141        /// <see cref="DataLakeSasPermissions"/> containing the allowed permissions.
 142        /// </param>
 143        public void SetPermissions(DataLakeSasPermissions permissions)
 144        {
 44145            Permissions = permissions.ToPermissionsString();
 44146        }
 147
 148        /// <summary>
 149        /// Sets the permissions for a path account level SAS.
 150        /// </summary>
 151        /// <param name="permissions">
 152        /// <see cref="DataLakeAccountSasPermissions"/> containing the allowed permissions.
 153        /// </param>
 154        public void SetPermissions(DataLakeAccountSasPermissions permissions)
 155        {
 0156            Permissions = permissions.ToPermissionsString();
 0157        }
 158
 159        /// <summary>
 160        /// Sets the permissions for a file system SAS.
 161        /// </summary>
 162        /// <param name="permissions">
 163        /// <see cref="DataLakeFileSystemSasPermissions"/> containing the allowed permissions.
 164        /// </param>
 165        public void SetPermissions(DataLakeFileSystemSasPermissions permissions)
 166        {
 36167            Permissions = permissions.ToPermissionsString();
 36168        }
 169
 170        /// <summary>
 171        /// Sets the permissions for the SAS using a raw permissions string.
 172        /// </summary>
 173        /// <param name="rawPermissions">
 174        /// Raw permissions string for the SAS.
 175        /// </param>
 176        /// <param name="normalize">
 177        /// If the permissions should be validated and correctly ordered.
 178        /// </param>
 179        public void SetPermissions(
 180            string rawPermissions,
 181            bool normalize = default)
 182        {
 8183            if (normalize)
 184            {
 8185                rawPermissions = SasExtensions.ValidateAndSanitizeRawPermissions(
 8186                    permissions: rawPermissions,
 8187                    validPermissionsInOrder: s_validPermissionsInOrder);
 188            }
 189
 8190            SetPermissions(rawPermissions);
 8191        }
 192
 193        /// <summary>
 194        /// Sets the permissions for the SAS using a raw permissions string.
 195        /// </summary>
 196        /// <param name="rawPermissions">Raw permissions string for the SAS.</param>
 197        public void SetPermissions(string rawPermissions)
 198        {
 8199            Permissions = rawPermissions;
 8200        }
 201
 2202        private static readonly List<char> s_validPermissionsInOrder = new List<char>
 2203        {
 2204            Constants.Sas.Permissions.Read,
 2205            Constants.Sas.Permissions.Add,
 2206            Constants.Sas.Permissions.Create,
 2207            Constants.Sas.Permissions.Write,
 2208            Constants.Sas.Permissions.Delete,
 2209            Constants.Sas.Permissions.DeleteBlobVersion,
 2210            Constants.Sas.Permissions.List,
 2211            Constants.Sas.Permissions.Tag,
 2212            Constants.Sas.Permissions.Update,
 2213            Constants.Sas.Permissions.Process
 2214        };
 215
 216        /// <summary>
 217        /// Use an account's <see cref="StorageSharedKeyCredential"/> to sign this
 218        /// shared access signature values to produce the proper SAS query
 219        /// parameters for authenticating requests.
 220        /// </summary>
 221        /// <param name="sharedKeyCredential">
 222        /// The storage account's <see cref="StorageSharedKeyCredential"/>.
 223        /// </param>
 224        /// <returns>
 225        /// The <see cref="DataLakeSasQueryParameters"/> used for authenticating
 226        /// requests.
 227        /// </returns>
 228        public DataLakeSasQueryParameters ToSasQueryParameters(StorageSharedKeyCredential sharedKeyCredential)
 229        {
 60230            sharedKeyCredential = sharedKeyCredential ?? throw Errors.ArgumentNull(nameof(sharedKeyCredential));
 231
 60232            EnsureState();
 233
 60234            var startTime = SasExtensions.FormatTimesForSasSigning(StartsOn);
 60235            var expiryTime = SasExtensions.FormatTimesForSasSigning(ExpiresOn);
 236
 237            // See http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
 60238            var stringToSign = String.Join("\n",
 60239                Permissions,
 60240                startTime,
 60241                expiryTime,
 60242                GetCanonicalName(sharedKeyCredential.AccountName, FileSystemName ?? String.Empty, Path ?? String.Empty),
 60243                Identifier,
 60244                IPRange.ToString(),
 60245                SasExtensions.ToProtocolString(Protocol),
 60246                Version,
 60247                Resource,
 60248                null, // snapshot
 60249                CacheControl,
 60250                ContentDisposition,
 60251                ContentEncoding,
 60252                ContentLanguage,
 60253                ContentType);
 254
 60255            var signature = StorageSharedKeyCredentialInternals.ComputeSasSignature(sharedKeyCredential, stringToSign);
 256
 60257            var p = new DataLakeSasQueryParameters(
 60258                version: Version,
 60259                services: default,
 60260                resourceTypes: default,
 60261                protocol: Protocol,
 60262                startsOn: StartsOn,
 60263                expiresOn: ExpiresOn,
 60264                ipRange: IPRange,
 60265                identifier: Identifier,
 60266                resource: Resource,
 60267                permissions: Permissions,
 60268                signature: signature,
 60269                cacheControl: CacheControl,
 60270                contentDisposition: ContentDisposition,
 60271                contentEncoding: ContentEncoding,
 60272                contentLanguage: ContentLanguage,
 60273                contentType: ContentType);
 60274            return p;
 275        }
 276
 277        /// <summary>
 278        /// Use an account's <see cref="UserDelegationKey"/> to sign this
 279        /// shared access signature values to produce the proper SAS query
 280        /// parameters for authenticating requests.
 281        /// </summary>
 282        /// <param name="userDelegationKey">
 283        /// A <see cref="UserDelegationKey"/> returned from
 284        /// <see cref="DataLakeServiceClient.GetUserDelegationKeyAsync"/>.
 285        /// </param>
 286        /// <param name="accountName">The name of the storage account.</param>
 287        /// <returns>
 288        /// The <see cref="DataLakeSasQueryParameters"/> used for authenticating requests.
 289        /// </returns>
 290        public DataLakeSasQueryParameters ToSasQueryParameters(UserDelegationKey userDelegationKey, string accountName)
 291        {
 32292            userDelegationKey = userDelegationKey ?? throw Errors.ArgumentNull(nameof(userDelegationKey));
 293
 32294            EnsureState();
 295
 32296            var startTime = SasExtensions.FormatTimesForSasSigning(StartsOn);
 32297            var expiryTime = SasExtensions.FormatTimesForSasSigning(ExpiresOn);
 32298            var signedStart = SasExtensions.FormatTimesForSasSigning(userDelegationKey.SignedStartsOn);
 32299            var signedExpiry = SasExtensions.FormatTimesForSasSigning(userDelegationKey.SignedExpiresOn);
 300
 301            // See http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
 32302            var stringToSign = String.Join("\n",
 32303                Permissions,
 32304                startTime,
 32305                expiryTime,
 32306                GetCanonicalName(accountName, FileSystemName ?? String.Empty, Path ?? String.Empty),
 32307                userDelegationKey.SignedObjectId,
 32308                userDelegationKey.SignedTenantId,
 32309                signedStart,
 32310                signedExpiry,
 32311                userDelegationKey.SignedService,
 32312                userDelegationKey.SignedVersion,
 32313                IPRange.ToString(),
 32314                SasExtensions.ToProtocolString(Protocol),
 32315                Version,
 32316                Resource,
 32317                null, // snapshot
 32318                CacheControl,
 32319                ContentDisposition,
 32320                ContentEncoding,
 32321                ContentLanguage,
 32322                ContentType);
 323
 32324            var signature = ComputeHMACSHA256(userDelegationKey.Value, stringToSign);
 325
 32326            var p = new DataLakeSasQueryParameters(
 32327                version: Version,
 32328                services: default,
 32329                resourceTypes: default,
 32330                protocol: Protocol,
 32331                startsOn: StartsOn,
 32332                expiresOn: ExpiresOn,
 32333                ipRange: IPRange,
 32334                identifier: null,
 32335                resource: Resource,
 32336                permissions: Permissions,
 32337                keyOid: userDelegationKey.SignedObjectId,
 32338                keyTid: userDelegationKey.SignedTenantId,
 32339                keyStart: userDelegationKey.SignedStartsOn,
 32340                keyExpiry: userDelegationKey.SignedExpiresOn,
 32341                keyService: userDelegationKey.SignedService,
 32342                keyVersion: userDelegationKey.SignedVersion,
 32343                signature: signature,
 32344                cacheControl: CacheControl,
 32345                contentDisposition: ContentDisposition,
 32346                contentEncoding: ContentEncoding,
 32347                contentLanguage: ContentLanguage,
 32348                contentType: ContentType);
 32349            return p;
 350        }
 351
 352        /// <summary>
 353        /// Computes the canonical name for a container or blob resource for SAS signing.
 354        /// Container: "/blob/account/containername"
 355        /// Blob: "/blob/account/containername/blobname"
 356        /// </summary>
 357        /// <param name="account">The name of the storage account.</param>
 358        /// <param name="fileSystemName">The name of the container.</param>
 359        /// <param name="path">The name of the blob.</param>
 360        /// <returns>The canonical resource name.</returns>
 361        private static string GetCanonicalName(string account, string fileSystemName, string path)
 92362            => !String.IsNullOrEmpty(path)
 92363               ? $"/blob/{account}/{fileSystemName}/{path.Replace("\\", "/")}"
 92364               : $"/blob/{account}/{fileSystemName}";
 365
 366        /// <summary>
 367        /// ComputeHMACSHA256 generates a base-64 hash signature string for an
 368        /// HTTP request or for a SAS.
 369        /// </summary>
 370        /// <param name="userDelegationKeyValue">
 371        /// A <see cref="UserDelegationKey.Value"/> used to sign with a key
 372        /// representing AD credentials.
 373        /// </param>
 374        /// <param name="message">The message to sign.</param>
 375        /// <returns>The signed message.</returns>
 376        private static string ComputeHMACSHA256(string userDelegationKeyValue, string message) =>
 32377            Convert.ToBase64String(
 32378                new HMACSHA256(
 32379                    Convert.FromBase64String(userDelegationKeyValue))
 32380                .ComputeHash(Encoding.UTF8.GetBytes(message)));
 381
 382        /// <summary>
 383        /// Ensure the <see cref="DataLakeSasBuilder"/>'s properties are in a
 384        /// consistent state.
 385        /// </summary>
 386        internal void EnsureState()
 387        {
 388            // Identifier is not present
 100389            if (string.IsNullOrEmpty(Identifier))
 390            {
 92391                if (string.IsNullOrEmpty(Permissions))
 392                {
 4393                    throw Errors.SasMissingData(nameof(Permissions));
 394                }
 395
 88396                if (ExpiresOn == default)
 397                {
 4398                    throw Errors.SasMissingData(nameof(ExpiresOn));
 399                }
 400            }
 401
 402            // File System
 92403            if (string.IsNullOrEmpty(Path))
 404            {
 60405                Resource = Constants.Sas.Resource.Container;
 406            }
 407
 408            // Path
 409            else
 410            {
 32411                Resource = Constants.Sas.Resource.Blob;
 412            }
 92413            if (string.IsNullOrEmpty(Version))
 414            {
 92415                Version = SasQueryParameters.DefaultSasVersion;
 416            }
 92417        }
 418
 419        /// <summary>
 420        /// Returns a string that represents the current object.
 421        /// </summary>
 422        /// <returns>A string that represents the current object.</returns>
 423        [EditorBrowsable(EditorBrowsableState.Never)]
 424        public override string ToString() =>
 0425            base.ToString();
 426
 427        /// <summary>
 428        /// Check if two BlobSasBuilder instances are equal.
 429        /// </summary>
 430        /// <param name="obj">The instance to compare to.</param>
 431        /// <returns>True if they're equal, false otherwise.</returns>
 432        [EditorBrowsable(EditorBrowsableState.Never)]
 433        public override bool Equals(object obj)
 0434            => base.Equals(obj);
 435
 436        /// <summary>
 437        /// Get a hash code for the BlobSasBuilder.
 438        /// </summary>
 439        /// <returns>Hash code for the BlobSasBuilder.</returns>
 440        [EditorBrowsable(EditorBrowsableState.Never)]
 0441        public override int GetHashCode() => base.GetHashCode();
 442    }
 443}