Added Azure SAS Token Authentication
This commit is contained in:
parent
920deb3df7
commit
01dd4c6290
|
@ -135,8 +135,10 @@ func CreateComposer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
accountKey := os.Getenv("AZURE_STORAGE_KEY")
|
accountKey := os.Getenv("AZURE_STORAGE_KEY")
|
||||||
if accountKey == "" {
|
sasUrl := os.Getenv("AZURE_STORAGE_SAS_URL")
|
||||||
stderr.Fatalf("No service account key for Azure BlockBlob Storage using the AZURE_STORAGE_KEY environment variable.\n")
|
|
||||||
|
if accountKey == "" && sasUrl == "" {
|
||||||
|
stderr.Fatalf("No service account key or SAS URL for Azure BlockBlob Storage using the AZURE_STORAGE_KEY or AZURE_STORAGE_SAS_URL environment variable.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
azureEndpoint := Flags.AzEndpoint
|
azureEndpoint := Flags.AzEndpoint
|
||||||
|
@ -152,6 +154,7 @@ func CreateComposer() {
|
||||||
|
|
||||||
azConfig := &azurestore.AzConfig{
|
azConfig := &azurestore.AzConfig{
|
||||||
AccountName: accountName,
|
AccountName: accountName,
|
||||||
|
SasUrl: sasUrl,
|
||||||
AccountKey: accountKey,
|
AccountKey: accountKey,
|
||||||
ContainerName: Flags.AzStorage,
|
ContainerName: Flags.AzStorage,
|
||||||
ContainerAccessType: Flags.AzContainerAccessType,
|
ContainerAccessType: Flags.AzContainerAccessType,
|
||||||
|
|
|
@ -20,9 +20,11 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/azure-storage-blob-go/azblob"
|
"github.com/Azure/azure-storage-blob-go/azblob"
|
||||||
"github.com/tus/tusd/pkg/handler"
|
"github.com/tus/tusd/pkg/handler"
|
||||||
|
@ -38,6 +40,8 @@ type azService struct {
|
||||||
BlobAccessTier azblob.AccessTierType
|
BlobAccessTier azblob.AccessTierType
|
||||||
ContainerURL *azblob.ContainerURL
|
ContainerURL *azblob.ContainerURL
|
||||||
ContainerName string
|
ContainerName string
|
||||||
|
SasUrl string
|
||||||
|
Endpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AzService interface {
|
type AzService interface {
|
||||||
|
@ -46,6 +50,7 @@ type AzService interface {
|
||||||
|
|
||||||
type AzConfig struct {
|
type AzConfig struct {
|
||||||
AccountName string
|
AccountName string
|
||||||
|
SasUrl string
|
||||||
AccountKey string
|
AccountKey string
|
||||||
BlobAccessTier string
|
BlobAccessTier string
|
||||||
ContainerName string
|
ContainerName string
|
||||||
|
@ -79,10 +84,25 @@ type InfoBlob struct {
|
||||||
// New Azure service for communication to Azure BlockBlob Storage API
|
// New Azure service for communication to Azure BlockBlob Storage API
|
||||||
func NewAzureService(config *AzConfig) (AzService, error) {
|
func NewAzureService(config *AzConfig) (AzService, error) {
|
||||||
// struct to store your credentials.
|
// struct to store your credentials.
|
||||||
credential, err := azblob.NewSharedKeyCredential(config.AccountName, config.AccountKey)
|
var credential azblob.Credential
|
||||||
|
var credError error
|
||||||
|
var cURL *url.URL
|
||||||
|
if config.AccountKey != "" {
|
||||||
|
// Use AccountKey for shared key credentials
|
||||||
|
credential, credError = azblob.NewSharedKeyCredential(config.AccountName, config.AccountKey)
|
||||||
|
if credError != nil {
|
||||||
|
return nil, credError
|
||||||
|
}
|
||||||
|
cURL, _ = url.Parse(fmt.Sprintf("%s/%s", config.Endpoint, config.ContainerName))
|
||||||
|
} else {
|
||||||
|
// Use anonymous credentials, request initial SAS and append it to URL
|
||||||
|
credential = azblob.NewAnonymousCredential()
|
||||||
|
sas, err := getSasToken(config.SasUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
cURL, _ = url.Parse(fmt.Sprintf("%s/%s?%s", config.Endpoint, config.ContainerName, sas))
|
||||||
|
}
|
||||||
|
|
||||||
// Might be limited by the storage account
|
// Might be limited by the storage account
|
||||||
// "" or default inherits the access type from the Storage Account
|
// "" or default inherits the access type from the Storage Account
|
||||||
|
@ -113,7 +133,6 @@ func NewAzureService(config *AzConfig) (AzService, error) {
|
||||||
|
|
||||||
// The pipeline specifies things like retry policies, logging, deserialization of HTTP response payloads, and more.
|
// The pipeline specifies things like retry policies, logging, deserialization of HTTP response payloads, and more.
|
||||||
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})
|
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})
|
||||||
cURL, _ := url.Parse(fmt.Sprintf("%s/%s", config.Endpoint, config.ContainerName))
|
|
||||||
|
|
||||||
// Get the ContainerURL URL
|
// Get the ContainerURL URL
|
||||||
containerURL := azblob.NewContainerURL(*cURL, p)
|
containerURL := azblob.NewContainerURL(*cURL, p)
|
||||||
|
@ -124,12 +143,31 @@ func NewAzureService(config *AzConfig) (AzService, error) {
|
||||||
BlobAccessTier: blobAccessTierType,
|
BlobAccessTier: blobAccessTierType,
|
||||||
ContainerURL: &containerURL,
|
ContainerURL: &containerURL,
|
||||||
ContainerName: config.ContainerName,
|
ContainerName: config.ContainerName,
|
||||||
|
SasUrl: config.SasUrl,
|
||||||
|
Endpoint: config.Endpoint,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if we return a InfoBlob or BlockBlob, based on the name
|
// Determine if we return a InfoBlob or BlockBlob, based on the name
|
||||||
func (service *azService) NewBlob(ctx context.Context, name string) (AzBlob, error) {
|
func (service *azService) NewBlob(ctx context.Context, name string) (AzBlob, error) {
|
||||||
var fileBlob AzBlob
|
var fileBlob AzBlob
|
||||||
|
url := service.ContainerURL.URL()
|
||||||
|
skeParam := url.Query().Get("ske")
|
||||||
|
if skeParam != "" {
|
||||||
|
sasEndDate, _ := time.Parse(time.RFC3339, skeParam)
|
||||||
|
if sasEndDate.Before(time.Now()) {
|
||||||
|
// Renew SAS and append it to URL
|
||||||
|
sas, err := getSasToken(service.SasUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cURL, _ := url.Parse(fmt.Sprintf("%s/%s?%s", service.Endpoint, service.ContainerName, sas))
|
||||||
|
p := azblob.NewPipeline(azblob.NewAnonymousCredential(), azblob.PipelineOptions{})
|
||||||
|
newContainerURL := azblob.NewContainerURL(*cURL, p)
|
||||||
|
service.ContainerURL = &newContainerURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bb := service.ContainerURL.NewBlockBlobURL(name)
|
bb := service.ContainerURL.NewBlockBlobURL(name)
|
||||||
if strings.HasSuffix(name, InfoBlobSuffix) {
|
if strings.HasSuffix(name, InfoBlobSuffix) {
|
||||||
fileBlob = &InfoBlob{
|
fileBlob = &InfoBlob{
|
||||||
|
@ -306,3 +344,16 @@ func isAzureError(err error, code string) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSasToken(sasUrl string) (sas string, err error) {
|
||||||
|
resp, err := http.Get(sasUrl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
sasResponse, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
return "", readErr
|
||||||
|
}
|
||||||
|
return string(sasResponse), nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue