I have a C# application which recieves an Azure BLOB container URI and bearer token, and needs to execute a copy of contents from one file to another file, both within the container. I understand that I cannot generate a user delegation SAS since the bearer token is only guaranteed to have container level access (Storage Blob Data Contributor).
When creating a BlobContainerClient with a TokenCredential containing the bearer token and trying to execute the copy:
var sourceClient = m_blobContainerClient.GetBlobClient(source);
var targetClient = m_blobContainerClient.GetBlobClient(target);
return targetClient.StartCopyFromUriAsync(sourceClient.Uri);
I am getting a 404 (the source definitely exists - I am verifying this). Is what I'm trying to do even possible? Is there any solution for copy files without having a SAS URI for the source file?
I do agree with @Gaurav Mantri that it does not depend whether the destination blob is created or not, but it depends the clients.
Bearer Token Method:
using Azure.Core;
using Azure.Storage.Blobs;
using Microsoft.Identity.Client;
class Program
{
static async Task Main(string[] args)
{
string ri_tnt_id = "932rithwikaf6d";
string ri_clnt_id = "828arithwik3efa57";
string clnt_sct = "DyHrithwikiggcjD";
string rith_StrgName = "storagename";
string con_nme = "rithcon";
string ri_src_blb = "hello.txt";
string ri_target_blb = "rithtest.txt";
string blobServiceUri = $"https://{rith_StrgName}.blob.core.windows.net";
string ri_tkn = await RithGetTkn(ri_tnt_id, ri_clnt_id, clnt_sct);
var cred = new BearerTokenCredential(ri_tkn);
var ri_bsc = new BlobServiceClient(new Uri(blobServiceUri), cred);
var ri_bcc = ri_bsc.GetBlobContainerClient(con_nme);
var sbc = ri_bcc.GetBlobClient(ri_src_blb);
var tbc = ri_bcc.GetBlobClient(ri_target_blb);
await RithCpyBlB(sbc, tbc);
Console.WriteLine("Hello Rithwik, Blob is Copied!");
}
static async Task RithCpyBlB(BlobClient sbc, BlobClient tbc)
{
using var ri_data = new MemoryStream();
await sbc.DownloadToAsync(ri_data);
ri_data.Position = 0;
await tbc.UploadAsync(ri_data, overwrite: true);
}
static async Task<string> RithGetTkn(string ri_tnt_id, string ri_clnt_id, string clnt_sct)
{
var app = ConfidentialClientApplicationBuilder.Create(ri_clnt_id)
.WithClientSecret(clnt_sct)
.WithAuthority($"https://login.microsoftonline.com/{ri_tnt_id}")
.Build();
string[] scopes = new[] { "https://storage.azure.com/.default" };
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
return result.AccessToken;
}
}
public class BearerTokenCredential : TokenCredential
{
private readonly string ritoken;
public BearerTokenCredential(string accessToken)
{
ritoken = accessToken;
}
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
return new AccessToken(ritoken, DateTimeOffset.MaxValue);
}
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
return new ValueTask<AccessToken>(new AccessToken(ritoken, DateTimeOffset.MaxValue));
}
}
Output:
Default credential method as an alternative to your code which works for me:
using Azure.Identity;
using Azure.Storage.Blobs;
class Program
{
static async Task Main(string[] args)
{
string ri_tnt_id = "932rithwikaf6d";
string ri_clnt_id = "828arithwik3efa57";
string clnt_sct = "DyHrithwikiggcjD";
string rith_StrgName = "stoargename";
string con_nme = "rithcon";
string ri_src_blb = "hello.txt";
string ri_target_blb = "test.txt";
string blobServiceUri = $"https://{rith_StrgName}.blob.core.windows.net";
var cred = new ClientSecretCredential(ri_tnt_id, ri_clnt_id, clnt_sct);
var ri_bsc = new BlobServiceClient(new Uri(blobServiceUri), cred);
var ri_bcc = ri_bsc.GetBlobContainerClient(con_nme);
var sbc = ri_bcc.GetBlobClient(ri_src_blb);
var tbc = ri_bcc.GetBlobClient(ri_target_blb);
await RithCpyBlB(sbc, tbc);
Console.WriteLine("Hello Rithwik, Blob is Copied!");
}
static async Task RithCpyBlB(BlobClient sbc, BlobClient tbc)
{
using var ri_data = new MemoryStream();
await sbc.DownloadToAsync(ri_data);
ri_data.Position = 0;
await tbc.UploadAsync(ri_data, overwrite: true);
}
}
Output:
Given Storage Blob Data Contributor Role.