< Summary

Class:Microsoft.Azure.ServiceBus.Primitives.SharedAccessSignatureToken
Assembly:Microsoft.Azure.ServiceBus
File(s):C:\Git\azure-sdk-for-net\sdk\servicebus\Microsoft.Azure.ServiceBus\src\Primitives\SharedAccessSignatureToken.cs
Covered lines:0
Uncovered lines:44
Coverable lines:44
Total lines:148
Line coverage:0% (0 of 44)
Covered branches:0
Total branches:28
Branch coverage:0% (0 of 28)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-0%100%
.ctor(...)-0%100%
Validate(...)-0%0%
ExtractFieldValues(...)-0%0%
GetAudienceFromToken(...)-0%0%
GetExpirationDateTimeUtcFromToken(...)-0%0%
Decode(...)-0%0%

File(s)

C:\Git\azure-sdk-for-net\sdk\servicebus\Microsoft.Azure.ServiceBus\src\Primitives\SharedAccessSignatureToken.cs

#LineLine coverage
 1// Copyright (c) Microsoft. All rights reserved.
 2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 3
 4namespace Microsoft.Azure.ServiceBus.Primitives
 5{
 6    using System;
 7    using System.Collections.Generic;
 8    using System.Globalization;
 9    using System.Net;
 10
 11    /// <summary>
 12    /// A WCF SecurityToken that wraps a Shared Access Signature
 13    /// </summary>
 14    internal class SharedAccessSignatureToken : SecurityToken
 15    {
 16        internal const string SharedAccessSignature = "SharedAccessSignature";
 17        internal const string SignedResource = "sr";
 18        internal const string Signature = "sig";
 19        internal const string SignedKeyName = "skn";
 20        internal const string SignedExpiry = "se";
 21        internal const int MaxKeyNameLength = 256;
 22        internal const int MaxKeyLength = 256;
 23
 24        const string SignedResourceFullFieldName = SharedAccessSignature + " " + SignedResource;
 25        const string SasPairSeparator = "&";
 26        const string SasKeyValueSeparator = "=";
 27
 028        static readonly Func<string, string> Decoder = WebUtility.UrlDecode;
 29
 30        /// <summary>
 31        /// Creates a new instance of the <see cref="SharedAccessSignatureToken"/> class.
 32        /// </summary>
 33        /// <param name="tokenString">The token</param>
 34        public SharedAccessSignatureToken(string tokenString)
 035            : base(tokenString, GetExpirationDateTimeUtcFromToken(tokenString), GetAudienceFromToken(tokenString), Const
 36        {
 037        }
 38
 39        internal static void Validate(string sharedAccessSignature)
 40        {
 041            if (string.IsNullOrEmpty(sharedAccessSignature))
 42            {
 043                throw new ArgumentNullException(nameof(sharedAccessSignature));
 44            }
 45
 046            IDictionary<string, string> parsedFields = ExtractFieldValues(sharedAccessSignature);
 47
 48            string signature;
 049            if (!parsedFields.TryGetValue(Signature, out signature))
 50            {
 051                throw new ArgumentNullException(Signature);
 52            }
 53
 54            string expiry;
 055            if (!parsedFields.TryGetValue(SignedExpiry, out expiry))
 56            {
 057                throw new ArgumentNullException(SignedExpiry);
 58            }
 59
 60            string keyName;
 061            if (!parsedFields.TryGetValue(SignedKeyName, out keyName))
 62            {
 063                throw new ArgumentNullException(SignedKeyName);
 64            }
 65
 66            string encodedAudience;
 067            if (!parsedFields.TryGetValue(SignedResource, out encodedAudience))
 68            {
 069                throw new ArgumentNullException(SignedResource);
 70            }
 071        }
 72
 73        static IDictionary<string, string> ExtractFieldValues(string sharedAccessSignature)
 74        {
 075            string[] tokenLines = sharedAccessSignature.Split();
 76
 077            if (!string.Equals(tokenLines[0].Trim(), SharedAccessSignature, StringComparison.OrdinalIgnoreCase) || token
 78            {
 079                throw new ArgumentNullException(nameof(sharedAccessSignature));
 80            }
 81
 082            IDictionary<string, string> parsedFields = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 083            string[] tokenFields = tokenLines[1].Trim().Split(new[] { SasPairSeparator }, StringSplitOptions.None);
 84
 085            foreach (string tokenField in tokenFields)
 86            {
 087                if (tokenField != string.Empty)
 88                {
 089                    string[] fieldParts = tokenField.Split(new[] { SasKeyValueSeparator }, StringSplitOptions.None);
 090                    if (string.Equals(fieldParts[0], SignedResource, StringComparison.OrdinalIgnoreCase))
 91                    {
 92                        // We need to preserve the casing of the escape characters in the audience,
 93                        // so defer decoding the URL until later.
 094                        parsedFields.Add(fieldParts[0], fieldParts[1]);
 95                    }
 96                    else
 97                    {
 098                        parsedFields.Add(fieldParts[0], WebUtility.UrlDecode(fieldParts[1]));
 99                    }
 100                }
 101            }
 102
 0103            return parsedFields;
 104        }
 105
 106        static string GetAudienceFromToken(string token)
 107        {
 0108            IDictionary<string, string> decodedToken = Decode(token, Decoder, Decoder, SasKeyValueSeparator, SasPairSepa
 0109            if (!decodedToken.TryGetValue(SignedResourceFullFieldName, out var audience))
 110            {
 0111                throw new FormatException(Resources.TokenMissingAudience);
 112            }
 113
 0114            return audience;
 115        }
 116
 117        static DateTime GetExpirationDateTimeUtcFromToken(string token)
 118        {
 0119            IDictionary<string, string> decodedToken = Decode(token, Decoder, Decoder, SasKeyValueSeparator, SasPairSepa
 0120            if (!decodedToken.TryGetValue(SignedExpiry, out var expiresIn))
 121            {
 0122                throw new FormatException(Resources.TokenMissingExpiresOn);
 123            }
 124
 0125            var expiresOn = (Constants.EpochTime + TimeSpan.FromSeconds(double.Parse(expiresIn, CultureInfo.InvariantCul
 126
 0127            return expiresOn;
 128        }
 129
 130        static IDictionary<string, string> Decode(string encodedString, Func<string, string> keyDecoder, Func<string, st
 131        {
 0132            IDictionary<string, string> dictionary = new Dictionary<string, string>();
 0133            IEnumerable<string> valueEncodedPairs = encodedString.Split(new[] { pairSeparator }, StringSplitOptions.None
 0134            foreach (string valueEncodedPair in valueEncodedPairs)
 135            {
 0136                string[] pair = valueEncodedPair.Split(new[] { keyValueSeparator }, StringSplitOptions.None);
 0137                if (pair.Length != 2)
 138                {
 0139                    throw new FormatException(Resources.InvalidEncoding);
 140                }
 141
 0142                dictionary.Add(keyDecoder(pair[0]), valueDecoder(pair[1]));
 143            }
 144
 0145            return dictionary;
 146        }
 147    }
 148}