Example #1
0
 static string GetCanonicalizedResource(bool liteAlgorithm, string uriPath, RequestQueryParameters queryParams, string accountName)
 {
     string commonPrefix = "/" + accountName + uriPath;
     if (liteAlgorithm)
     {
         var compParam = queryParams.Value<string>("comp");
         return commonPrefix + (!String.IsNullOrWhiteSpace(compParam) ? "?comp=" + compParam : "");
     }
     else
     {
         if (queryParams.Any())
         {
             return commonPrefix + "\n" + String.Join("\n", queryParams
                 .OrderBy(queryParam => queryParam.Key, StringComparer.OrdinalIgnoreCase)
                 .Select(queryParam => SharedKeySignature.FormatCanonicalizedValues(queryParam)));
         }
         return commonPrefix;
     }
 }
Example #2
0
        public static async Task<bool> IsAuthorizedAsync(IHttpRequestWrapper request, RequestHeaders headers, RequestQueryParameters queryParams, bool ignoreRequestAge)
        {
            var requestUriParts = request.UriParts;
            string resourceType = String.Empty;
            DateTimeOffset? start = queryParams.Value(ParamStartTime, DateTimeOffset.UtcNow);
            DateTimeOffset? expiry = queryParams.Value(ParamExpiryTime, DateTimeOffset.MinValue);
            DateTimeOffset sasVersion = queryParams.Value(ParamVersion, StorageServiceVersions.Version_2009_09_19);
            bool accountSas = queryParams.Contains(ParamResourceTypeEx);
            if (accountSas)
            {
                resourceType = queryParams.Value<string>(ParamResourceTypeEx).ToLowerInvariant();
            }
            else
            {
                resourceType = queryParams.Value<string>(ParamResourceType).ToLowerInvariant();
            }
            if (expiry == DateTimeOffset.MinValue)
            {
                expiry = null;
            }
            SharedAccessBlobPermissions permissions = PermissionsFromString(queryParams.Value(ParamPermissions, String.Empty)); 
            // Determine validity of the structure first
            if (requestUriParts.IsAccountRequest)
            {
                if (sasVersion < StorageServiceVersions.Version_2015_04_05 || !resourceType.Contains('s'))
                {
                    // SAS keys are not valid for account operations before 2015-04-05
                    return false;
                }
            }
            else if (requestUriParts.IsContainerRequest)
            {
                if (resourceType != "c")
                {
                    return false;
                }
            }
            else if (requestUriParts.IsBlobRequest)
            {
                if (resourceType.IndexOfAny(new[] { 'c', 'b', 'o' }) == -1)
                {
                    return false;
                }
            }
            if (!accountSas)
            {
                var storedPolicyId = queryParams.Value<string>(ParamStoredPolicy);
                if (!String.IsNullOrWhiteSpace(storedPolicyId))
                {
                    // Validate that we're not duplicating values for both stored access policy & url
                    // Allow stored policy to the specified from a different container for test purposes - this isn't a security violation as it must come from the same account.
                    var aclContainer = headers.Value("StoredPolicyContainer", String.Empty);
                    if (String.IsNullOrEmpty(aclContainer))
                    {
                        aclContainer = requestUriParts.Container;
                    }
                    var storedPolicy = await GetStoredPolicyForContainer(aclContainer, storedPolicyId);
                    if (storedPolicy == null)
                    {
                        return false;
                    }
                    if (storedPolicy.SharedAccessStartTime.HasValue)
                    {
                        start = storedPolicy.SharedAccessStartTime;
                    }
                    if (storedPolicy.SharedAccessExpiryTime.HasValue)
                    {
                        if (expiry.HasValue)
                        {
                            return false;
                        }
                        expiry = storedPolicy.SharedAccessExpiryTime;
                    }
                    if (queryParams.Contains(ParamPermissions))
                    {
                        return false;
                    }
                    permissions = storedPolicy.Permissions;
                }
            }
            else
            {
                if (!queryParams.Value<string>(ParamServices, String.Empty).Contains('b'))
                {
                    // SAS must include blob service
                    return false;
                }
            }
            if (!expiry.HasValue || permissions == SharedAccessBlobPermissions.None)
            {
                return false;
            }
            else if (!ignoreRequestAge && (start.Value > DateTimeOffset.UtcNow || expiry.Value < DateTimeOffset.UtcNow))
            {
                return false;
            }
            else if (!IsProtocolMatched(request, queryParams.Value<string>(ParamProtocol)))
            {
                return false;
            }
            else if (!IsSourceAddressInRange(request, queryParams.Value<string>(ParamSourceIP)))
            {
                return false;
            }

            // Verify the assigned permissions line up with the requested operation
            StorageOperationTypes requestOperation = StorageOperations.GetBlobOperation(request);
            switch (requestOperation)
            {
                case StorageOperationTypes.GetBlob:
                case StorageOperationTypes.GetBlobMetadata:
                case StorageOperationTypes.GetBlobProperties:
                case StorageOperationTypes.GetBlockList:
                case StorageOperationTypes.GetPageRanges:
                case StorageOperationTypes.GetBlobServiceProperties:
                case StorageOperationTypes.GetBlobServiceStats:
                case StorageOperationTypes.GetContainerProperties:
                case StorageOperationTypes.GetContainerMetadata:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.Read))
                    {
                        return false;
                    }
                    break;

                case StorageOperationTypes.AbortCopyBlob:
                case StorageOperationTypes.CopyBlob:
                case StorageOperationTypes.LeaseBlob:
                case StorageOperationTypes.PutBlob:
                case StorageOperationTypes.PutBlock:
                case StorageOperationTypes.PutBlockList:
                case StorageOperationTypes.PutPage:
                case StorageOperationTypes.SetBlobMetadata:
                case StorageOperationTypes.SetBlobProperties:
                case StorageOperationTypes.SnapshotBlob:
                case StorageOperationTypes.SetBlobServiceProperties:
                case StorageOperationTypes.CreateContainer:
                case StorageOperationTypes.SetContainerMetadata:
                case StorageOperationTypes.LeaseContainer:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.Write))
                    {
                        return false;
                    }
                    break;

                case StorageOperationTypes.DeleteBlob:
                case StorageOperationTypes.DeleteContainer:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.Delete))
                    {
                        return false;
                    }
                    break;

                case StorageOperationTypes.ListBlobs:
                case StorageOperationTypes.ListContainers:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.List))
                    {
                        return false;
                    }
                    break;

                default:
                    // All other operations are not supported by SAS uris
                    return false;
            }
            Func<string> stringToSignFactory = null;
            if (!accountSas)
            {
                Func<string> baseStringToSign = () => String.Format("{0}\n{1}\n{2}\n{3}\n{4}",
                                                                    queryParams.Value<string>(ParamPermissions),
                                                                    queryParams.Value<string>(ParamStartTime),
                                                                    queryParams.Value<string>(ParamExpiryTime),
                                                                    GetCanonicalizedResource(requestUriParts, resourceType, sasVersion),
                                                                    queryParams.Value<string>(ParamStoredPolicy));
                Func<string> ipAndProtocolSnippet = () => String.Format("{0}\n{1}\n",
                                                                    queryParams.Value<string>(ParamSourceIP),
                                                                    queryParams.Value<string>(ParamProtocol));
                Func<string> v2012_02_12StringToSign = () => String.Format("{0}\n{1}{2}",
                                                                            baseStringToSign(),
                                                                            sasVersion >= StorageServiceVersions.Version_2015_04_05 ? ipAndProtocolSnippet() : String.Empty,
                                                                            sasVersion.ToVersionString());

                if (sasVersion < StorageServiceVersions.Version_2012_02_12)
                {
                    stringToSignFactory = baseStringToSign;
                }
                else if (sasVersion == StorageServiceVersions.Version_2012_02_12)
                {
                    stringToSignFactory = v2012_02_12StringToSign;
                }
                else
                {
                    stringToSignFactory = () => String.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}",
                                                                v2012_02_12StringToSign(),
                                                                queryParams.Value<string>(ParamCacheControl),
                                                                queryParams.Value<string>(ParamContentDisposition),
                                                                queryParams.Value<string>(ParamContentEncoding),
                                                                queryParams.Value<string>(ParamContentLang),
                                                                queryParams.Value<string>(ParamContentType));
                }
            }
            else
            {
                stringToSignFactory = () => String.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n",
                                                                SharedKeySignature.AccountName,
                                                                queryParams.Value<string>(ParamPermissions),
                                                                queryParams.Value<string>(ParamServices),
                                                                queryParams.Value<string>(ParamResourceTypeEx),
                                                                queryParams.Value<string>(ParamStartTime),
                                                                queryParams.Value<string>(ParamExpiryTime),
                                                                queryParams.Value<string>(ParamSourceIP),
                                                                queryParams.Value<string>(ParamProtocol),
                                                                sasVersion.ToVersionString());
            }
            string signature = queryParams.Value<string>(ParamSignature);
            var usingPrimaryKey = new[] { true, false };
            string stringToSign = stringToSignFactory();
            int matchIndex = Array.FindIndex(usingPrimaryKey, usePrimaryKey => VerifySignature(signature, usePrimaryKey, stringToSign));
            if (matchIndex != -1)
            {
                // We can't sign the redirection response when the request uses a SAS key - preserve the matching key, however
                request.AuthenticationScheme = String.Empty;
                request.AuthenticationKey = usingPrimaryKey[matchIndex] ? SharedKeySignature.PrimaryAccountKey : SharedKeySignature.SecondaryAccountKey;
                return true;
            }
            return false;
        }
Example #3
0
        public static async Task<bool> IsAuthorizedAsync(IHttpRequestWrapper request, RequestHeaders headers, RequestQueryParameters queryParams, bool ignoreRequestAge)
        {
            var requestUriParts = request.UriParts;
            var resourceType = queryParams.Value<string>(ParamResourceType, String.Empty).ToLowerInvariant();
            DateTimeOffset? start = queryParams.Value(ParamStartTime, DateTimeOffset.UtcNow);
            DateTimeOffset? expiry = queryParams.Value(ParamExpiryTime, DateTimeOffset.MinValue);
            if (expiry == DateTimeOffset.MinValue)
            {
                expiry = null;
            }
            SharedAccessBlobPermissions permissions = SharedAccessBlobPolicy.PermissionsFromString(queryParams.Value(ParamPermissions, String.Empty)); 
            // Determine validity of the structure first
            if (requestUriParts.IsAccountRequest)
            {
                // SAS keys are not valid for account operations
                return false;
            }
            else if (requestUriParts.IsContainerRequest && resourceType != "c")
            {
                return false;
            }
            else if (requestUriParts.IsBlobRequest && resourceType.IndexOfAny(new [] { 'c', 'b' }) == -1)
            {
                return false;
            }
            var storedPolicyId = queryParams.Value<string>(ParamStoredPolicy);
            if (!String.IsNullOrWhiteSpace(storedPolicyId))
            {
                // Validate that we're not duplicating values for both stored access policy & url
                var storedPolicy = await GetStoredPolicyForContainer(requestUriParts.Container, storedPolicyId);
                if (storedPolicy == null)
                {
                    return false;
                }
                if (storedPolicy.SharedAccessStartTime.HasValue)
                {
                    start = storedPolicy.SharedAccessStartTime;
                }
                if (storedPolicy.SharedAccessExpiryTime.HasValue)
                {
                    if (expiry.HasValue)
                    {
                        return false;
                    }
                    expiry = storedPolicy.SharedAccessExpiryTime;
                }
                if (queryParams.Contains(ParamPermissions))
                {
                    return false;
                }
                permissions = storedPolicy.Permissions;
            }
            if (!expiry.HasValue || permissions == SharedAccessBlobPermissions.None)
            {
                return false;
            }
            else if (!ignoreRequestAge && (start.Value > DateTimeOffset.UtcNow || expiry.Value < DateTimeOffset.UtcNow))
            {
                return false;
            }
            // Verify the assigned permissions line up with the requested operation
            StorageOperationTypes requestOperation = StorageOperations.GetBlobOperation(request);
            switch (requestOperation)
            {
                case StorageOperationTypes.GetBlob:
                case StorageOperationTypes.GetBlobMetadata:
                case StorageOperationTypes.GetBlobProperties:
                case StorageOperationTypes.GetBlockList:
                case StorageOperationTypes.GetPageRanges:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.Read))
                    {
                        return false;
                    }
                    break;

                case StorageOperationTypes.AbortCopyBlob:
                case StorageOperationTypes.CopyBlob:
                case StorageOperationTypes.LeaseBlob:
                case StorageOperationTypes.PutBlob:
                case StorageOperationTypes.PutBlock:
                case StorageOperationTypes.PutBlockList:
                case StorageOperationTypes.PutPage:
                case StorageOperationTypes.SetBlobMetadata:
                case StorageOperationTypes.SetBlobProperties:
                case StorageOperationTypes.SnapshotBlob:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.Write))
                    {
                        return false;
                    }
                    break;

                case StorageOperationTypes.DeleteBlob:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.Delete))
                    {
                        return false;
                    }
                    break;

                case StorageOperationTypes.ListBlobs:
                    if (!permissions.IsFlagSet(SharedAccessBlobPermissions.List))
                    {
                        return false;
                    }
                    break;

                default:
                    // All other operations are not supported by SAS uris
                    return false;
            }
            DateTimeOffset sasVersion = queryParams.Value(ParamVersion, StorageServiceVersions.Version_2009_09_19);
            Func<string> stringToSignFactory = null;
            Func<string> baseStringToSign = () => String.Format("{0}\n{1}\n{2}\n{3}\n{4}",
                                                                queryParams.Value<string>(ParamPermissions),
                                                                queryParams.Value<string>(ParamStartTime),
                                                                queryParams.Value<string>(ParamExpiryTime),
                                                                GetCanonicalizedResource(requestUriParts, resourceType),
                                                                queryParams.Value<string>(ParamStoredPolicy));
            Func<string> v2012_02_12StringToSign = () => String.Format("{0}\n{1}",
                                                                        baseStringToSign(),
                                                                        queryParams.Value<string>(ParamVersion));

            if (sasVersion < StorageServiceVersions.Version_2012_02_12)
            {
                stringToSignFactory = baseStringToSign;
            }
            else if (sasVersion == StorageServiceVersions.Version_2012_02_12)
            {
                stringToSignFactory = v2012_02_12StringToSign;
            }
            else
            {
                stringToSignFactory = () => String.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}",
                                                            v2012_02_12StringToSign(),
                                                            queryParams.Value<string>(ParamCacheControl),
                                                            queryParams.Value<string>(ParamContentDisposition),
                                                            queryParams.Value<string>(ParamContentEncoding),
                                                            queryParams.Value<string>(ParamContentLang),
                                                            queryParams.Value<string>(ParamContentType));
            }
            string signature = queryParams.Value<string>(ParamSignature);
            var usingPrimaryKey = new[] { true, false };
            int matchIndex = Array.FindIndex(usingPrimaryKey, usePrimaryKey => VerifySignature(signature, usePrimaryKey, stringToSignFactory));
            if (matchIndex != -1)
            {
                // We can't sign the redirection response when the request uses a SAS key - preserve the matching key, however
                request.AuthenticationScheme = String.Empty;
                request.AuthenticationKey = usingPrimaryKey[matchIndex] ? SharedKeySignature.PrimaryAccountKey : SharedKeySignature.SecondaryAccountKey;
                return true;
            }
            return false;
        }