// This function is used by Compute internal static string GenerateUrlEncodedAuthorizationTokenWithHashCore( string verb, string resourceId, string resourceType, INameValueCollection headers, IComputeHash stringHMACSHA256Helper, out ArrayOwner payload) { // resourceId can be null for feed-read of /dbs if (string.IsNullOrEmpty(verb)) { throw new ArgumentException(RMResources.StringArgumentNullOrEmpty, nameof(verb)); } if (resourceType == null) { throw new ArgumentNullException(nameof(resourceType)); // can be empty } if (stringHMACSHA256Helper == null) { throw new ArgumentNullException(nameof(stringHMACSHA256Helper)); } if (headers == null) { throw new ArgumentNullException(nameof(headers)); } // Order of the values included in the message payload is a protocol that clients/BE need to follow exactly. // More headers can be added in the future. // If any of the value is optional, it should still have the placeholder value of "" // OperationType -> ResourceType -> ResourceId/OwnerId -> XDate -> Date string verbInput = verb ?? string.Empty; string resourceIdInput = resourceId ?? string.Empty; string resourceTypeInput = resourceType ?? string.Empty; string authResourceId = AuthorizationHelper.GetAuthorizationResourceIdOrFullName(resourceTypeInput, resourceIdInput); int capacity = AuthorizationHelper.ComputeMemoryCapacity(verbInput, authResourceId, resourceTypeInput); byte[] buffer = ArrayPool <byte> .Shared.Rent(capacity); try { Span <byte> payloadBytes = buffer; int length = AuthorizationHelper.SerializeMessagePayload( payloadBytes, verbInput, authResourceId, resourceTypeInput, headers); payload = new ArrayOwner(ArrayPool <byte> .Shared, new ArraySegment <byte>(buffer, 0, length)); byte[] hashPayLoad = stringHMACSHA256Helper.ComputeHash(payload.Buffer); return(AuthorizationHelper.OptimizedConvertToBase64string(hashPayLoad)); } catch { ArrayPool <byte> .Shared.Return(buffer); throw; } }