public static void ParseAuthorizationToken()

in Microsoft.Azure.Cosmos/src/Authorization/AuthorizationHelper.cs [196:310]


        public static void ParseAuthorizationToken(
            string authorizationTokenString,
            out ReadOnlyMemory<char> typeOutput,
            out ReadOnlyMemory<char> versionOutput,
            out ReadOnlyMemory<char> tokenOutput)
        {
            typeOutput = default;
            versionOutput = default;
            tokenOutput = default;

            if (string.IsNullOrEmpty(authorizationTokenString))
            {
                DefaultTrace.TraceError("Auth token missing");
                throw new UnauthorizedException(RMResources.MissingAuthHeader);
            }

            int authorizationTokenLength = authorizationTokenString.Length;

            authorizationTokenString = HttpUtility.UrlDecode(authorizationTokenString);
 
            // Format of the token being deciphered is 
            // type=<master/resource/system>&ver=<version>&sig=<base64encodedstring>

            // Step 1. split the tokens into type/ver/token.
            // when parsing for the last token, I use , as a separator to skip any redundant authorization headers

            ReadOnlyMemory<char> authorizationToken = authorizationTokenString.AsMemory();
            int typeSeparatorPosition = authorizationToken.Span.IndexOf('&');
            if (typeSeparatorPosition == -1)
            {
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat);
            }
            ReadOnlyMemory<char> authType = authorizationToken.Slice(0, typeSeparatorPosition);

            authorizationToken = authorizationToken.Slice(typeSeparatorPosition + 1, authorizationToken.Length - typeSeparatorPosition - 1);
            int versionSepartorPosition = authorizationToken.Span.IndexOf('&');
            if (versionSepartorPosition == -1)
            {
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat);
            }
            ReadOnlyMemory<char> version = authorizationToken.Slice(0, versionSepartorPosition);

            authorizationToken = authorizationToken.Slice(versionSepartorPosition + 1, authorizationToken.Length - versionSepartorPosition - 1);
            ReadOnlyMemory<char> token = authorizationToken;
            int tokenSeparatorPosition = authorizationToken.Span.IndexOf(',');
            if (tokenSeparatorPosition != -1)
            {
                token = authorizationToken.Slice(0, tokenSeparatorPosition);
            }

            // Step 2. For each token, split to get the right half of '='
            // Additionally check for the left half to be the expected scheme type
            int typeKeyValueSepartorPosition = authType.Span.IndexOf('=');
            if (typeKeyValueSepartorPosition == -1
                || !authType.Span.Slice(0, typeKeyValueSepartorPosition).SequenceEqual(Constants.Properties.AuthSchemaType.AsSpan())
                || !authType.Span.Slice(0, typeKeyValueSepartorPosition).ToString().Equals(Constants.Properties.AuthSchemaType, StringComparison.OrdinalIgnoreCase))
            {
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat);
            }

            ReadOnlyMemory<char> authTypeValue = authType.Slice(typeKeyValueSepartorPosition + 1);

            if (MemoryExtensions.Equals(authTypeValue.Span, Constants.Properties.AadToken.AsSpan(), StringComparison.OrdinalIgnoreCase))
            {
                if (authorizationTokenLength > AuthorizationHelper.MaxAadAuthorizationHeaderSize)
                {
                    DefaultTrace.TraceError($"Token of type [{authTypeValue.Span.ToString()}] was of size [{authorizationTokenLength}] while the max allowed size is [{AuthorizationHelper.MaxAadAuthorizationHeaderSize}].");
                    throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat, SubStatusCodes.InvalidAuthHeaderFormat);
                }
            }
            else if (MemoryExtensions.Equals(authTypeValue.Span, Constants.Properties.ResourceToken.AsSpan(), StringComparison.OrdinalIgnoreCase))
            {
                if (authorizationTokenLength > AuthorizationHelper.MaxResourceTokenAuthorizationHeaderSize)
                {
                    DefaultTrace.TraceError($"Token of type [{authTypeValue.Span.ToString()}] was of size [{authorizationTokenLength}] while the max allowed size is [{AuthorizationHelper.MaxResourceTokenAuthorizationHeaderSize}].");
                    throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat, SubStatusCodes.InvalidAuthHeaderFormat);
                }
            }
            else if (authorizationTokenLength > AuthorizationHelper.MaxAuthorizationHeaderSize)
            {
                DefaultTrace.TraceError($"Token of type [{authTypeValue.Span.ToString()}] was of size [{authorizationTokenLength}] while the max allowed size is [{AuthorizationHelper.MaxAuthorizationHeaderSize}].");
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat, SubStatusCodes.InvalidAuthHeaderFormat);
            }

            int versionKeyValueSeparatorPosition = version.Span.IndexOf('=');
            if (versionKeyValueSeparatorPosition == -1
                || !version.Span.Slice(0, versionKeyValueSeparatorPosition).SequenceEqual(Constants.Properties.AuthVersion.AsSpan())
                || !version.Slice(0, versionKeyValueSeparatorPosition).ToString().Equals(Constants.Properties.AuthVersion, StringComparison.OrdinalIgnoreCase))
            {
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat);
            }

            ReadOnlyMemory<char> versionValue = version.Slice(versionKeyValueSeparatorPosition + 1);

            int tokenKeyValueSeparatorPosition = token.Span.IndexOf('=');
            if (tokenKeyValueSeparatorPosition == -1
                || !token.Slice(0, tokenKeyValueSeparatorPosition).Span.SequenceEqual(Constants.Properties.AuthSignature.AsSpan())
                || !token.Slice(0, tokenKeyValueSeparatorPosition).ToString().Equals(Constants.Properties.AuthSignature, StringComparison.OrdinalIgnoreCase))
            {
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat);
            }

            ReadOnlyMemory<char> tokenValue = token.Slice(tokenKeyValueSeparatorPosition + 1);

            if (authTypeValue.IsEmpty ||
                versionValue.IsEmpty ||
                tokenValue.IsEmpty)
            {
                throw new UnauthorizedException(RMResources.InvalidAuthHeaderFormat);
            }

            typeOutput = authTypeValue;
            versionOutput = versionValue;
            tokenOutput = tokenValue;
        }