Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9fba771
Init
souravgupta-msft Jan 4, 2023
62e45d0
Reformat code
souravgupta-msft Jan 5, 2023
0493788
Adding transforms
souravgupta-msft Jan 5, 2023
9ddaf65
Adding transforms
souravgupta-msft Jan 5, 2023
023f75a
Adding transforms
souravgupta-msft Jan 5, 2023
51235e4
Typo
souravgupta-msft Jan 5, 2023
340204f
Updating go version
souravgupta-msft Jan 6, 2023
264812d
Converting to time.Time
souravgupta-msft Jan 12, 2023
8967e3a
Adding service client
souravgupta-msft Jan 16, 2023
b6f6c3f
Updating autorest version
souravgupta-msft Jan 18, 2023
01c699d
Adding changelog and build.go files
souravgupta-msft Jan 18, 2023
c1a8c31
Merge branch 'sourav/auto-generation' of https://github.com/Azure/azu…
souravgupta-msft Jan 18, 2023
e111ae0
Adding methods in share client
souravgupta-msft Jan 18, 2023
5ad7696
Adding lease methods in share client
souravgupta-msft Jan 18, 2023
fb5c2c5
Pulling from feature branch
souravgupta-msft Jan 23, 2023
09adce6
changes in lease share methods
souravgupta-msft Jan 23, 2023
cc31841
Adding methods for directory client
souravgupta-msft Jan 24, 2023
dfa3679
Adding methods for file client
souravgupta-msft Jan 25, 2023
70a31a5
File client methods
souravgupta-msft Jan 27, 2023
0e12299
Format checks
souravgupta-msft Jan 27, 2023
e2c970c
Format checks
souravgupta-msft Jan 27, 2023
b660ce0
Changing type of Etag from *string to *azcore.Etag
souravgupta-msft Feb 1, 2023
2cf6002
Capitalise NTFS and SMB fields
souravgupta-msft Feb 1, 2023
b22ae02
Adding download methods same as azblob
souravgupta-msft Feb 2, 2023
7f715dd
Adding lease client
souravgupta-msft Feb 2, 2023
de69fe8
Capitalise SMB
souravgupta-msft Feb 2, 2023
d557aa3
Renaming the lease methods
souravgupta-msft Feb 9, 2023
0b73838
autorest transform - remove item suffix
souravgupta-msft Feb 13, 2023
65d93fd
Renaming FileID to ID and capitalising cors
souravgupta-msft Feb 13, 2023
ee4e518
adding internal package code
souravgupta-msft Feb 15, 2023
734fe0e
Review comments
souravgupta-msft Feb 15, 2023
604da07
Merge branch 'sourav/serviceClient' of https://github.com/Azure/azure…
souravgupta-msft Feb 15, 2023
6f891f4
Service properties rename
souravgupta-msft Feb 15, 2023
ed2407b
Merge branch 'sourav/serviceClient' of https://github.com/Azure/azure…
souravgupta-msft Feb 16, 2023
f4b2d3b
Adding list and set properties
souravgupta-msft Feb 16, 2023
88b392f
service client tests
souravgupta-msft Feb 16, 2023
a454119
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-go into…
souravgupta-msft Feb 17, 2023
de3a239
Merge branch 'feature/azfile' of https://github.com/Azure/azure-sdk-f…
souravgupta-msft Feb 17, 2023
706b503
Merge branch 'sourav/serviceClient' of https://github.com/Azure/azure…
souravgupta-msft Feb 17, 2023
d997002
Adding error codes
souravgupta-msft Feb 17, 2023
da163c1
Merging from feature branch
souravgupta-msft Feb 17, 2023
226ef3b
removing container error code
souravgupta-msft Feb 20, 2023
58a7389
Removing client creation using OAuth
souravgupta-msft Feb 20, 2023
84d3a03
Adding assets.json
souravgupta-msft Feb 20, 2023
13a982c
Adding few recordings
souravgupta-msft Feb 20, 2023
d9edf3a
Few tests to unrecorded
souravgupta-msft Feb 20, 2023
3f62bc7
account and service SAS
souravgupta-msft Feb 21, 2023
0f917c8
GetSASURL() and url_parts.go
souravgupta-msft Feb 21, 2023
a33d051
Adding sas based tests
souravgupta-msft Feb 22, 2023
a387962
small change
souravgupta-msft Feb 22, 2023
28cadaf
Merging from feature branch
souravgupta-msft Feb 23, 2023
4b4326e
use directory and file path
souravgupta-msft Feb 23, 2023
4eadd55
Adding resource type parsing
souravgupta-msft Feb 24, 2023
b472d97
Review comments
souravgupta-msft Feb 27, 2023
2502a50
Few changes
souravgupta-msft Feb 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions sdk/storage/azfile/directory/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ func NewClientWithSharedKeyCredential(directoryURL string, cred *SharedKeyCreden
// NewClientFromConnectionString creates an instance of Client with the specified values.
// - connectionString - a connection string for the desired storage account
// - shareName - the name of the share within the storage account
// - directoryName - the name of the directory within the storage account
// - directoryPath - the path of the directory within the share
// - options - client options; pass nil to accept the default values
func NewClientFromConnectionString(connectionString string, shareName string, directoryName string, options *ClientOptions) (*Client, error) {
func NewClientFromConnectionString(connectionString string, shareName string, directoryPath string, options *ClientOptions) (*Client, error) {
return nil, nil
}

Expand Down
5 changes: 2 additions & 3 deletions sdk/storage/azfile/file/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ func NewClientWithSharedKeyCredential(fileURL string, cred *SharedKeyCredential,
// NewClientFromConnectionString creates an instance of Client with the specified values.
// - connectionString - a connection string for the desired storage account
// - shareName - the name of the share within the storage account
// - directoryName - the name of the directory within the storage account
// - fileName - the name of the file within the storage account
// - filePath - the path of the file within the share
// - options - client options; pass nil to accept the default values
func NewClientFromConnectionString(connectionString string, shareName string, directoryName string, fileName string, options *ClientOptions) (*Client, error) {
func NewClientFromConnectionString(connectionString string, shareName string, filePath string, options *ClientOptions) (*Client, error) {
return nil, nil
}

Expand Down
5 changes: 5 additions & 0 deletions sdk/storage/azfile/fileerror/error_codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,8 @@ const (
UnsupportedQueryParameter Code = "UnsupportedQueryParameter"
UnsupportedXMLNode Code = "UnsupportedXmlNode"
)

var (
// MissingSharedKeyCredential - Error is returned when SAS URL is being created without SharedKeyCredential.
MissingSharedKeyCredential = errors.New("SAS can only be signed with a SharedKeyCredential")
)
20 changes: 20 additions & 0 deletions sdk/storage/azfile/internal/shared/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package shared
import (
"errors"
"fmt"
"net"
"strings"
)

Expand Down Expand Up @@ -108,3 +109,22 @@ func ParseConnectionString(connectionString string) (ParsedConnectionString, err
AccountKey: accountKey,
}, nil
}

// IsIPEndpointStyle checks if URL's host is IP, in this case the storage account endpoint will be composed as:
// http(s)://IP(:port)/storageaccount/share(||container||etc)/...
// As url's Host property, host could be both host or host:port
func IsIPEndpointStyle(host string) bool {
if host == "" {
return false
}
if h, _, err := net.SplitHostPort(host); err == nil {
host = h
}
// For IPv6, there could be case where SplitHostPort fails for cannot finding port.
// In this case, eliminate the '[' and ']' in the URL.
// For details about IPv6 URL, please refer to https://tools.ietf.org/html/rfc2732
if host[0] == '[' && host[len(host)-1] == ']' {
host = host[1 : len(host)-1]
}
return net.ParseIP(host) != nil
}
183 changes: 183 additions & 0 deletions sdk/storage/azfile/sas/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package sas

import (
"bytes"
"errors"
"fmt"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/exported"
)

// SharedKeyCredential contains an account's name and its primary or secondary key.
type SharedKeyCredential = exported.SharedKeyCredential

// AccountSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-an-account-sas
type AccountSignatureValues struct {
Version string `param:"sv"` // If not specified, this format to SASVersion
Protocol Protocol `param:"spr"` // See the SASProtocol* constants
StartTime time.Time `param:"st"` // Not specified if IsZero
ExpiryTime time.Time `param:"se"` // Not specified if IsZero
Permissions string `param:"sp"` // Create by initializing a AccountSASPermissions and then call String()
IPRange IPRange `param:"sip"`
ResourceTypes string `param:"srt"` // Create by initializing AccountSASResourceTypes and then call String()
}

// SignWithSharedKey uses an account's shared key credential to sign this signature values to produce
// the proper SAS query parameters.
func (v AccountSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKeyCredential) (QueryParameters, error) {
// https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS
if v.ExpiryTime.IsZero() || v.Permissions == "" || v.ResourceTypes == "" {
return QueryParameters{}, errors.New("account SAS is missing at least one of these: ExpiryTime, Permissions, Service, or ResourceType")
}
if v.Version == "" {
v.Version = Version
}
perms, err := parseAccountPermissions(v.Permissions)
if err != nil {
return QueryParameters{}, err
}
v.Permissions = perms.String()

resources, err := parseAccountResourceTypes(v.ResourceTypes)
if err != nil {
return QueryParameters{}, err
}
v.ResourceTypes = resources.String()

startTime, expiryTime, _ := formatTimesForSigning(v.StartTime, v.ExpiryTime, time.Time{})

stringToSign := strings.Join([]string{
sharedKeyCredential.AccountName(),
v.Permissions,
"f", // file service
v.ResourceTypes,
startTime,
expiryTime,
v.IPRange.String(),
string(v.Protocol),
v.Version,
""}, // That is right, the account SAS requires a terminating extra newline
"\n")

signature, err := exported.ComputeHMACSHA256(sharedKeyCredential, stringToSign)
if err != nil {
return QueryParameters{}, err
}
p := QueryParameters{
// Common SAS parameters
version: v.Version,
protocol: v.Protocol,
startTime: v.StartTime,
expiryTime: v.ExpiryTime,
permissions: v.Permissions,
ipRange: v.IPRange,

// Account-specific SAS parameters
services: "f", // will always be "f" for Azure File
resourceTypes: v.ResourceTypes,

// Calculated SAS signature
signature: signature,
}

return p, nil
}

// AccountPermissions type simplifies creating the permissions string for an Azure Storage Account SAS.
// Initialize an instance of this type and then call its String method to set AccountSASSignature value's Permissions field.
type AccountPermissions struct {
Read, Write, Delete, List, Create bool
}

// String produces the SAS permissions string for an Azure Storage account.
// Call this method to set AccountSignatureValues' Permissions field.
func (p *AccountPermissions) String() string {
var buffer bytes.Buffer
if p.Read {
buffer.WriteRune('r')
}
if p.Write {
buffer.WriteRune('w')
}
if p.Delete {
buffer.WriteRune('d')
}
if p.List {
buffer.WriteRune('l')
}
if p.Create {
buffer.WriteRune('c')
}
return buffer.String()
}

// parseAccountPermissions initializes the AccountSASPermissions' fields from a string.
func parseAccountPermissions(s string) (AccountPermissions, error) {
p := AccountPermissions{} // Clear out the flags
for _, r := range s {
switch r {
case 'r':
p.Read = true
case 'w':
p.Write = true
case 'd':
p.Delete = true
case 'l':
p.List = true
case 'c':
p.Create = true
default:
return AccountPermissions{}, fmt.Errorf("invalid permission character: '%v'", r)
}
}
return p, nil
}

// AccountResourceTypes type simplifies creating the resource types string for an Azure Storage Account SAS.
// Initialize an instance of this type and then call its String method to set AccountSignatureValues' ResourceTypes field.
type AccountResourceTypes struct {
Service, Container, Object bool
}

// String produces the SAS resource types string for an Azure Storage account.
// Call this method to set AccountSignatureValues' ResourceTypes field.
func (rt *AccountResourceTypes) String() string {
Comment thread
souravgupta-msft marked this conversation as resolved.
var buffer bytes.Buffer
if rt.Service {
buffer.WriteRune('s')
}
if rt.Container {
buffer.WriteRune('c')
}
if rt.Object {
buffer.WriteRune('o')
}
return buffer.String()
}

// parseAccountResourceTypes initializes the AccountResourceTypes' fields from a string.
func parseAccountResourceTypes(s string) (AccountResourceTypes, error) {
rt := AccountResourceTypes{}
for _, r := range s {
switch r {
case 's':
rt.Service = true
case 'c':
rt.Container = true
case 'o':
rt.Object = true
default:
return AccountResourceTypes{}, fmt.Errorf("invalid resource type character: '%v'", r)
}
}
return rt, nil
}
124 changes: 124 additions & 0 deletions sdk/storage/azfile/sas/account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package sas

import (
"github.com/stretchr/testify/require"
"testing"
)

func TestAccountPermissions_String(t *testing.T) {
testdata := []struct {
input AccountPermissions
expected string
}{
{input: AccountPermissions{Read: true}, expected: "r"},
{input: AccountPermissions{Write: true}, expected: "w"},
{input: AccountPermissions{Delete: true}, expected: "d"},
{input: AccountPermissions{List: true}, expected: "l"},
{input: AccountPermissions{Create: true}, expected: "c"},
{input: AccountPermissions{
Read: true,
Write: true,
Delete: true,
List: true,
Create: true,
}, expected: "rwdlc"},
}
for _, c := range testdata {
require.Equal(t, c.expected, c.input.String())
}
}

func TestAccountPermissions_Parse(t *testing.T) {
testdata := []struct {
input string
expected AccountPermissions
}{
{expected: AccountPermissions{Read: true}, input: "r"},
{expected: AccountPermissions{Write: true}, input: "w"},
{expected: AccountPermissions{Delete: true}, input: "d"},
{expected: AccountPermissions{List: true}, input: "l"},
{expected: AccountPermissions{Create: true}, input: "c"},
{expected: AccountPermissions{
Read: true,
Write: true,
Delete: true,
List: true,
Create: true,
}, input: "rwdlc"},
{expected: AccountPermissions{
Read: true,
Write: true,
Delete: true,
List: true,
Create: true,
}, input: "rcdlw"},
}
for _, c := range testdata {
permissions, err := parseAccountPermissions(c.input)
require.Nil(t, err)
require.Equal(t, c.expected, permissions)
}
}

func TestAccountPermissions_ParseNegative(t *testing.T) {
_, err := parseAccountPermissions("rwldcz") // Here 'z' is invalid
require.NotNil(t, err)
require.Contains(t, err.Error(), "122")
}

func TestAccountResourceTypes_String(t *testing.T) {
testdata := []struct {
input AccountResourceTypes
expected string
}{
{input: AccountResourceTypes{Service: true}, expected: "s"},
{input: AccountResourceTypes{Container: true}, expected: "c"},
{input: AccountResourceTypes{Object: true}, expected: "o"},
{input: AccountResourceTypes{
Service: true,
Container: true,
Object: true,
}, expected: "sco"},
}
for _, c := range testdata {
require.Equal(t, c.expected, c.input.String())
}
}

func TestAccountResourceTypes_Parse(t *testing.T) {
testdata := []struct {
input string
expected AccountResourceTypes
}{
{expected: AccountResourceTypes{Service: true}, input: "s"},
{expected: AccountResourceTypes{Container: true}, input: "c"},
{expected: AccountResourceTypes{Object: true}, input: "o"},
{expected: AccountResourceTypes{
Service: true,
Container: true,
Object: true,
}, input: "sco"},
{expected: AccountResourceTypes{
Service: true,
Container: true,
Object: true,
}, input: "osc"},
}
for _, c := range testdata {
permissions, err := parseAccountResourceTypes(c.input)
require.Nil(t, err)
require.Equal(t, c.expected, permissions)
}
}

func TestAccountResourceTypes_ParseNegative(t *testing.T) {
_, err := parseAccountResourceTypes("scoz") // Here 'z' is invalid
require.NotNil(t, err)
require.Contains(t, err.Error(), "122")
}
Loading