Skip to content

Commit e7f2275

Browse files
authored
Implement copy source authorization (#317)
* Implement copy source authorization * Implement testing * Nil check * Bump timeout * Fix time format * Reduce test code dupe * Correct timezone issue
1 parent 7e62913 commit e7f2275

21 files changed

+427
-1157
lines changed

azblob/access_conditions.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ type ModifiedAccessConditions struct {
1313
}
1414

1515
// pointers is for internal infrastructure. It returns the fields as pointers.
16-
func (ac ModifiedAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *string, inme *string) {
16+
func (ac ModifiedAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *ETag, inme *ETag) {
1717
if !ac.IfModifiedSince.IsZero() {
1818
ims = &ac.IfModifiedSince
1919
}
2020
if !ac.IfUnmodifiedSince.IsZero() {
2121
ius = &ac.IfUnmodifiedSince
2222
}
2323
if ac.IfMatch != ETagNone {
24-
ime = (*string)(&ac.IfMatch)
24+
ime = &ac.IfMatch
2525
}
2626
if ac.IfNoneMatch != ETagNone {
27-
inme = (*string)(&ac.IfNoneMatch)
27+
inme = &ac.IfNoneMatch
2828
}
2929
return
3030
}

azblob/url_append_blob.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac
9999

100100
// AppendBlockFromURL copies a new block of data from source URL to the end of the existing append blob.
101101
// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block-from-url.
102-
func (ab AppendBlobURL) AppendBlockFromURL(ctx context.Context, sourceURL url.URL, offset int64, count int64, destinationAccessConditions AppendBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, transactionalMD5 []byte, cpk ClientProvidedKeyOptions) (*AppendBlobAppendBlockFromURLResponse, error) {
102+
func (ab AppendBlobURL) AppendBlockFromURL(ctx context.Context, sourceURL url.URL, offset int64, count int64, destinationAccessConditions AppendBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, transactionalMD5 []byte, cpk ClientProvidedKeyOptions, sourceAuthorization TokenCredential) (*AppendBlobAppendBlockFromURLResponse, error) {
103103
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers()
104104
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
105105
ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := destinationAccessConditions.AppendPositionAccessConditions.pointers()
@@ -111,7 +111,7 @@ func (ab AppendBlobURL) AppendBlockFromURL(ctx context.Context, sourceURL url.UR
111111
ifMaxSizeLessThanOrEqual, ifAppendPositionEqual,
112112
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
113113
nil, // Blob ifTags
114-
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil, nil)
114+
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil, tokenCredentialPointers(sourceAuthorization))
115115
}
116116

117117
type AppendBlobAccessConditions struct {

azblob/url_block_blob.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,12 @@ func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, bod
103103
// StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList.
104104
// If count is CountToEnd (0), then data is read from specified offset to the end.
105105
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url.
106-
func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, destinationAccessConditions LeaseAccessConditions, sourceAccessConditions ModifiedAccessConditions, cpk ClientProvidedKeyOptions) (*BlockBlobStageBlockFromURLResponse, error) {
106+
func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, destinationAccessConditions LeaseAccessConditions, sourceAccessConditions ModifiedAccessConditions, cpk ClientProvidedKeyOptions, sourceAuthorization TokenCredential) (*BlockBlobStageBlockFromURLResponse, error) {
107107
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
108108
return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, sourceURL.String(), httpRange{offset: offset, count: count}.pointers(), nil, nil, nil,
109109
cpk.EncryptionKey, cpk.EncryptionKeySha256, cpk.EncryptionAlgorithm, // CPK
110110
cpk.EncryptionScope, // CPK-N
111-
destinationAccessConditions.pointers(), sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil, nil)
111+
destinationAccessConditions.pointers(), sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil, tokenCredentialPointers(sourceAuthorization))
112112
}
113113

114114
// CommitBlockList writes a blob by specifying the list of block IDs that make up the blob.
@@ -146,7 +146,7 @@ func (bb BlockBlobURL) GetBlockList(ctx context.Context, listType BlockListType,
146146

147147
// CopyFromURL synchronously copies the data at the source URL to a block blob, with sizes up to 256 MB.
148148
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url.
149-
func (bb BlockBlobURL) CopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions, srcContentMD5 []byte, tier AccessTierType, blobTagsMap BlobTagsMap, immutability ImmutabilityPolicyOptions) (*BlobCopyFromURLResponse, error) {
149+
func (bb BlockBlobURL) CopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions, srcContentMD5 []byte, tier AccessTierType, blobTagsMap BlobTagsMap, immutability ImmutabilityPolicyOptions, sourceAuthorization TokenCredential) (*BlobCopyFromURLResponse, error) {
150150
srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
151151
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
152152
dstLeaseID := dstac.LeaseAccessConditions.pointers()
@@ -161,12 +161,12 @@ func (bb BlockBlobURL) CopyFromURL(ctx context.Context, source url.URL, metadata
161161
dstLeaseID, nil, srcContentMD5,
162162
blobTagsString, // Blob tags
163163
// immutability policy
164-
immutabilityExpiry, immutabilityMode, legalHold, nil)
164+
immutabilityExpiry, immutabilityMode, legalHold, tokenCredentialPointers(sourceAuthorization))
165165
}
166166

167167
// PutBlobFromURL synchronously creates a new Block Blob with data from the source URL up to a max length of 256MB.
168168
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-blob-from-url.
169-
func (bb BlockBlobURL) PutBlobFromURL(ctx context.Context, h BlobHTTPHeaders, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions, srcContentMD5 []byte, dstContentMD5 []byte, tier AccessTierType, blobTagsMap BlobTagsMap, cpk ClientProvidedKeyOptions) (*BlockBlobPutBlobFromURLResponse, error) {
169+
func (bb BlockBlobURL) PutBlobFromURL(ctx context.Context, h BlobHTTPHeaders, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions, srcContentMD5 []byte, dstContentMD5 []byte, tier AccessTierType, blobTagsMap BlobTagsMap, cpk ClientProvidedKeyOptions, sourceAuthorization TokenCredential) (*BlockBlobPutBlobFromURLResponse, error) {
170170

171171
srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
172172
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
@@ -178,5 +178,5 @@ func (bb BlockBlobURL) PutBlobFromURL(ctx context.Context, h BlobHTTPHeaders, so
178178
metadata, dstLeaseID, &h.ContentDisposition, cpk.EncryptionKey, cpk.EncryptionKeySha256,
179179
cpk.EncryptionAlgorithm, cpk.EncryptionScope, tier, dstIfModifiedSince, dstIfUnmodifiedSince,
180180
dstIfMatchETag, dstIfNoneMatchETag, nil, srcIfModifiedSince, srcIfUnmodifiedSince,
181-
srcIfMatchETag, srcIfNoneMatchETag, nil, nil, srcContentMD5, blobTagsString, nil, nil)
181+
srcIfMatchETag, srcIfNoneMatchETag, nil, nil, srcContentMD5, blobTagsString, nil, tokenCredentialPointers(sourceAuthorization))
182182
}

azblob/url_page_blob.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.Rea
103103
// The destOffset specifies the start offset of data in page blob will be written to.
104104
// The count must be a multiple of 512 bytes.
105105
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page-from-url.
106-
func (pb PageBlobURL) UploadPagesFromURL(ctx context.Context, sourceURL url.URL, sourceOffset int64, destOffset int64, count int64, transactionalMD5 []byte, destinationAccessConditions PageBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, cpk ClientProvidedKeyOptions) (*PageBlobUploadPagesFromURLResponse, error) {
106+
func (pb PageBlobURL) UploadPagesFromURL(ctx context.Context, sourceURL url.URL, sourceOffset int64, destOffset int64, count int64, transactionalMD5 []byte, destinationAccessConditions PageBlobAccessConditions, sourceAccessConditions ModifiedAccessConditions, cpk ClientProvidedKeyOptions, sourceAuthorization TokenCredential) (*PageBlobUploadPagesFromURLResponse, error) {
107107
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := destinationAccessConditions.ModifiedAccessConditions.pointers()
108108
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag := sourceAccessConditions.pointers()
109109
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := destinationAccessConditions.SequenceNumberAccessConditions.pointers()
@@ -115,7 +115,7 @@ func (pb PageBlobURL) UploadPagesFromURL(ctx context.Context, sourceURL url.URL,
115115
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual,
116116
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
117117
nil, // Blob ifTags
118-
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil, nil)
118+
sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatchETag, sourceIfNoneMatchETag, nil, tokenCredentialPointers(sourceAuthorization))
119119
}
120120

121121
// ClearPages frees the specified pages from the page blob.

azblob/zc_credential_token.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ type TokenCredential interface {
2323
SetToken(newToken string)
2424
}
2525

26+
func tokenCredentialPointers(credential TokenCredential) *string {
27+
if credential == nil {
28+
return nil
29+
}
30+
31+
out := "Bearer " + credential.Token()
32+
return &out
33+
}
34+
2635
// NewTokenCredential creates a token credential for use with role-based access control (RBAC) access to Azure Storage
2736
// resources. You initialize the TokenCredential with an initial token value. If you pass a non-nil value for
2837
// tokenRefresher, then the function you pass will be called immediately so it can refresh and change the
@@ -68,7 +77,7 @@ func (f *tokenCredentialWithRefresh) New(next pipeline.Policy, po *pipeline.Poli
6877
return f.token.New(next, po)
6978
}
7079

71-
///////////////////////////////////////////////////////////////////////////////
80+
// /////////////////////////////////////////////////////////////////////////////
7281

7382
// tokenCredential is a pipeline.Factory is the credential's policy factory.
7483
type tokenCredential struct {

azblob/zt_blob_tags_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,15 +258,15 @@ func (s *aztestsSuite) TestStageBlockFromURLWithTags(c *chk.C) {
258258
srcBlobURLWithSAS := srcBlobParts.URL()
259259

260260
blockID1, blockID2 := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))), base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 1)))
261-
stageResp1, err := destBlob.StageBlockFromURL(ctx, blockID1, srcBlobURLWithSAS, 0, 4*1024*1024, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{})
261+
stageResp1, err := destBlob.StageBlockFromURL(ctx, blockID1, srcBlobURLWithSAS, 0, 4*1024*1024, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{}, nil)
262262
c.Assert(err, chk.IsNil)
263263
c.Assert(stageResp1.Response().StatusCode, chk.Equals, 201)
264264
c.Assert(stageResp1.ContentMD5(), chk.Not(chk.Equals), "")
265265
c.Assert(stageResp1.RequestID(), chk.Not(chk.Equals), "")
266266
c.Assert(stageResp1.Version(), chk.Not(chk.Equals), "")
267267
c.Assert(stageResp1.Date().IsZero(), chk.Equals, false)
268268

269-
stageResp2, err := destBlob.StageBlockFromURL(ctx, blockID2, srcBlobURLWithSAS, 4*1024*1024, CountToEnd, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{})
269+
stageResp2, err := destBlob.StageBlockFromURL(ctx, blockID2, srcBlobURLWithSAS, 4*1024*1024, CountToEnd, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{}, nil)
270270
c.Assert(err, chk.IsNil)
271271
c.Assert(stageResp2.Response().StatusCode, chk.Equals, 201)
272272
c.Assert(stageResp2.ContentMD5(), chk.Not(chk.Equals), "")
@@ -283,7 +283,7 @@ func (s *aztestsSuite) TestStageBlockFromURLWithTags(c *chk.C) {
283283
listResp, err := destBlob.CommitBlockList(ctx, []string{blockID1, blockID2}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, blobTagsMap, ClientProvidedKeyOptions{}, ImmutabilityPolicyOptions{})
284284
c.Assert(err, chk.IsNil)
285285
c.Assert(listResp.Response().StatusCode, chk.Equals, 201)
286-
//versionId := listResp.VersionID()
286+
// versionId := listResp.VersionID()
287287

288288
downloadResp, err := destBlob.BlobURL.Download(ctx, 0, CountToEnd, BlobAccessConditions{}, false, ClientProvidedKeyOptions{})
289289
c.Assert(err, chk.IsNil)
@@ -340,7 +340,7 @@ func (s *aztestsSuite) TestCopyBlockBlobFromURLWithTags(c *chk.C) {
340340

341341
srcBlobURLWithSAS := srcBlobParts.URL()
342342

343-
resp, err := destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{"foo": "bar"}, ModifiedAccessConditions{}, BlobAccessConditions{}, sourceDataMD5Value[:], DefaultAccessTier, nil, ImmutabilityPolicyOptions{})
343+
resp, err := destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{"foo": "bar"}, ModifiedAccessConditions{}, BlobAccessConditions{}, sourceDataMD5Value[:], DefaultAccessTier, nil, ImmutabilityPolicyOptions{}, nil)
344344
c.Assert(err, chk.IsNil)
345345
c.Assert(resp.Response().StatusCode, chk.Equals, 202)
346346
c.Assert(resp.ETag(), chk.Not(chk.Equals), "")
@@ -360,10 +360,10 @@ func (s *aztestsSuite) TestCopyBlockBlobFromURLWithTags(c *chk.C) {
360360
c.Assert(len(downloadResp.NewMetadata()), chk.Equals, 1)
361361

362362
_, badMD5 := getRandomDataAndReader(16)
363-
_, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, badMD5, DefaultAccessTier, blobTagsMap, ImmutabilityPolicyOptions{})
363+
_, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, badMD5, DefaultAccessTier, blobTagsMap, ImmutabilityPolicyOptions{}, nil)
364364
c.Assert(err, chk.NotNil)
365365

366-
resp, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, nil, DefaultAccessTier, blobTagsMap, ImmutabilityPolicyOptions{})
366+
resp, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, nil, DefaultAccessTier, blobTagsMap, ImmutabilityPolicyOptions{}, nil)
367367
c.Assert(err, chk.IsNil)
368368
c.Assert(resp.Response().StatusCode, chk.Equals, 202)
369369
c.Assert(resp.XMsContentCrc64(), chk.Not(chk.Equals), "")
@@ -575,8 +575,8 @@ func (s *aztestsSuite) TestFindBlobsByTags(c *chk.C) {
575575
c.Assert(err, chk.IsNil)
576576
c.Assert(lResp.Blobs, chk.HasLen, 0)
577577

578-
//where = "\"tag1\"='firsttag'AND\"tag2\"='secondtag'AND\"@container\"='"+ containerName1 + "'"
579-
//TODO: Figure out how to do a composite query based on container.
578+
// where = "\"tag1\"='firsttag'AND\"tag2\"='secondtag'AND\"@container\"='"+ containerName1 + "'"
579+
// TODO: Figure out how to do a composite query based on container.
580580
where = "\"tag1\"='firsttag'AND\"tag2\"='secondtag'"
581581

582582
lResp, err = bsu.FindBlobsByTags(ctx, nil, nil, &where, Marker{}, nil)

azblob/zt_blob_versioning_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func (s *aztestsSuite) TestCopyBlobFromURLWithSASReturnsVID(c *chk.C) {
247247

248248
srcBlobURLWithSAS := srcBlobParts.URL()
249249

250-
resp, err := destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{"foo": "bar"}, ModifiedAccessConditions{}, BlobAccessConditions{}, sourceDataMD5Value[:], DefaultAccessTier, nil, ImmutabilityPolicyOptions{})
250+
resp, err := destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{"foo": "bar"}, ModifiedAccessConditions{}, BlobAccessConditions{}, sourceDataMD5Value[:], DefaultAccessTier, nil, ImmutabilityPolicyOptions{}, nil)
251251
c.Assert(err, chk.IsNil)
252252
c.Assert(resp.Response().StatusCode, chk.Equals, 202)
253253
c.Assert(resp.Version(), chk.Not(chk.Equals), "")
@@ -263,10 +263,10 @@ func (s *aztestsSuite) TestCopyBlobFromURLWithSASReturnsVID(c *chk.C) {
263263
c.Assert(downloadResp.Response().Header.Get("x-ms-version-id"), chk.NotNil)
264264
c.Assert(len(downloadResp.NewMetadata()), chk.Equals, 1)
265265
_, badMD5 := getRandomDataAndReader(16)
266-
_, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, badMD5, DefaultAccessTier, nil, ImmutabilityPolicyOptions{})
266+
_, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, badMD5, DefaultAccessTier, nil, ImmutabilityPolicyOptions{}, nil)
267267
c.Assert(err, chk.NotNil)
268268

269-
resp, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, nil, DefaultAccessTier, nil, ImmutabilityPolicyOptions{})
269+
resp, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, nil, DefaultAccessTier, nil, ImmutabilityPolicyOptions{}, nil)
270270
c.Assert(err, chk.IsNil)
271271
c.Assert(resp.Response().StatusCode, chk.Equals, 202)
272272
c.Assert(resp.XMsContentCrc64(), chk.Not(chk.Equals), "")

0 commit comments

Comments
 (0)