-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #574 from terraform-providers/provider-block
Conditional loading of the Subscription ID / Tenant ID / Environment
- Loading branch information
Showing
15 changed files
with
1,189 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package authentication | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
"time" | ||
|
||
"github.com/Azure/go-autorest/autorest/adal" | ||
"github.com/Azure/go-autorest/autorest/azure/cli" | ||
) | ||
|
||
type AccessToken struct { | ||
ClientID string | ||
AccessToken *adal.Token | ||
IsCloudShell bool | ||
} | ||
|
||
func findValidAccessTokenForTenant(tokens []cli.Token, tenantId string) (*AccessToken, error) { | ||
for _, accessToken := range tokens { | ||
token, err := accessToken.ToADALToken() | ||
if err != nil { | ||
return nil, fmt.Errorf("[DEBUG] Error converting access token to token: %+v", err) | ||
} | ||
|
||
expirationDate, err := cli.ParseExpirationDate(accessToken.ExpiresOn) | ||
if err != nil { | ||
return nil, fmt.Errorf("Error parsing expiration date: %q", accessToken.ExpiresOn) | ||
} | ||
|
||
if expirationDate.UTC().Before(time.Now().UTC()) { | ||
log.Printf("[DEBUG] Token %q has expired", token.AccessToken) | ||
continue | ||
} | ||
|
||
if !strings.Contains(accessToken.Resource, "management") { | ||
log.Printf("[DEBUG] Resource %q isn't a management domain", accessToken.Resource) | ||
continue | ||
} | ||
|
||
if !strings.HasSuffix(accessToken.Authority, tenantId) { | ||
log.Printf("[DEBUG] Resource %q isn't for the correct Tenant", accessToken.Resource) | ||
continue | ||
} | ||
|
||
validAccessToken := AccessToken{ | ||
ClientID: accessToken.ClientID, | ||
AccessToken: &token, | ||
IsCloudShell: accessToken.RefreshToken == "", | ||
} | ||
return &validAccessToken, nil | ||
} | ||
|
||
return nil, fmt.Errorf("No Access Token was found for the Tenant ID %q", tenantId) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
package authentication | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/Azure/go-autorest/autorest/azure/cli" | ||
) | ||
|
||
func TestAzureFindValidAccessTokenForTenant_InvalidDate(t *testing.T) { | ||
tenantId := "c056adac-c6a6-4ddf-ab20-0f26d47f7eea" | ||
expectedToken := cli.Token{ | ||
ExpiresOn: "invalid date", | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
RefreshToken: "4ec3874d-ee2e-4980-ba47-b5bac11ddb94", | ||
Resource: "https://management.core.windows.net/", | ||
Authority: tenantId, | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, tenantId) | ||
|
||
if err == nil { | ||
t.Fatalf("Expected an error to be returned but got nil") | ||
} | ||
|
||
if token != nil { | ||
t.Fatalf("Expected Token to be nil but got: %+v", token) | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_Expired(t *testing.T) { | ||
expirationDate := time.Now().Add(time.Minute * -1) | ||
tenantId := "c056adac-c6a6-4ddf-ab20-0f26d47f7eea" | ||
expectedToken := cli.Token{ | ||
ExpiresOn: expirationDate.Format("2006-01-02 15:04:05.999999"), | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
RefreshToken: "4ec3874d-ee2e-4980-ba47-b5bac11ddb94", | ||
Resource: "https://management.core.windows.net/", | ||
Authority: tenantId, | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, tenantId) | ||
|
||
if err == nil { | ||
t.Fatalf("Expected an error to be returned but got nil") | ||
} | ||
|
||
if token != nil { | ||
t.Fatalf("Expected Token to be nil but got: %+v", token) | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_ExpiringIn(t *testing.T) { | ||
minutesToVerify := []int{1, 30, 60} | ||
|
||
for _, minute := range minutesToVerify { | ||
expirationDate := time.Now().Add(time.Minute * time.Duration(minute)) | ||
tenantId := "c056adac-c6a6-4ddf-ab20-0f26d47f7eea" | ||
expectedToken := cli.Token{ | ||
ExpiresOn: expirationDate.Format("2006-01-02 15:04:05.999999"), | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
RefreshToken: "4ec3874d-ee2e-4980-ba47-b5bac11ddb94", | ||
Resource: "https://management.core.windows.net/", | ||
Authority: tenantId, | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, tenantId) | ||
|
||
if err != nil { | ||
t.Fatalf("Expected no error to be returned for minute %d but got %+v", minute, err) | ||
} | ||
|
||
if token == nil { | ||
t.Fatalf("Expected Token to have a value for minute %d but it was nil", minute) | ||
} | ||
|
||
if token.AccessToken.AccessToken != expectedToken.AccessToken { | ||
t.Fatalf("Expected the Access Token to be %q for minute %d but got %q", expectedToken.AccessToken, minute, token.AccessToken.AccessToken) | ||
} | ||
|
||
if token.ClientID != expectedToken.ClientID { | ||
t.Fatalf("Expected the Client ID to be %q for minute %d but got %q", expectedToken.ClientID, minute, token.ClientID) | ||
} | ||
|
||
if token.IsCloudShell != false { | ||
t.Fatalf("Expected `IsCloudShell` to be false for minute %d but got true", minute) | ||
} | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_InvalidManagementDomain(t *testing.T) { | ||
expirationDate := time.Now().Add(1 * time.Hour) | ||
tenantId := "c056adac-c6a6-4ddf-ab20-0f26d47f7eea" | ||
expectedToken := cli.Token{ | ||
ExpiresOn: expirationDate.Format("2006-01-02 15:04:05.999999"), | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
Resource: "https://portal.azure.com/", | ||
Authority: tenantId, | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, tenantId) | ||
|
||
if err == nil { | ||
t.Fatalf("Expected an error but didn't get one") | ||
} | ||
|
||
if token != nil { | ||
t.Fatalf("Expected Token to be nil but got: %+v", token) | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_DifferentTenant(t *testing.T) { | ||
expirationDate := time.Now().Add(1 * time.Hour) | ||
expectedToken := cli.Token{ | ||
ExpiresOn: expirationDate.Format("2006-01-02 15:04:05.999999"), | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
Resource: "https://management.core.windows.net/", | ||
Authority: "9b5095de-5496-4b5e-9bc6-ef2c017b9d35", | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, "c056adac-c6a6-4ddf-ab20-0f26d47f7eea") | ||
|
||
if err == nil { | ||
t.Fatalf("Expected an error but didn't get one") | ||
} | ||
|
||
if token != nil { | ||
t.Fatalf("Expected Token to be nil but got: %+v", token) | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_ValidFromCloudShell(t *testing.T) { | ||
expirationDate := time.Now().Add(1 * time.Hour) | ||
tenantId := "c056adac-c6a6-4ddf-ab20-0f26d47f7eea" | ||
expectedToken := cli.Token{ | ||
ExpiresOn: expirationDate.Format(time.RFC3339), | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
Resource: "https://management.core.windows.net/", | ||
Authority: tenantId, | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, tenantId) | ||
|
||
if err != nil { | ||
t.Fatalf("Expected no error to be returned but got %+v", err) | ||
} | ||
|
||
if token == nil { | ||
t.Fatalf("Expected Token to have a value but it was nil") | ||
} | ||
|
||
if token.AccessToken.AccessToken != expectedToken.AccessToken { | ||
t.Fatalf("Expected the Access Token to be %q but got %q", expectedToken.AccessToken, token.AccessToken.AccessToken) | ||
} | ||
|
||
if token.ClientID != expectedToken.ClientID { | ||
t.Fatalf("Expected the Client ID to be %q but got %q", expectedToken.ClientID, token.ClientID) | ||
} | ||
|
||
if token.IsCloudShell != true { | ||
t.Fatalf("Expected `IsCloudShell` to be true but got false") | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_ValidFromAzureCLI(t *testing.T) { | ||
expirationDate := time.Now().Add(1 * time.Hour) | ||
tenantId := "c056adac-c6a6-4ddf-ab20-0f26d47f7eea" | ||
expectedToken := cli.Token{ | ||
ExpiresOn: expirationDate.Format("2006-01-02 15:04:05.999999"), | ||
AccessToken: "7cabcf30-8dca-43f9-91e6-fd56dfb8632f", | ||
TokenType: "9b10b986-7a61-4542-8d5a-9fcd96112585", | ||
RefreshToken: "4ec3874d-ee2e-4980-ba47-b5bac11ddb94", | ||
Resource: "https://management.core.windows.net/", | ||
Authority: tenantId, | ||
} | ||
tokens := []cli.Token{expectedToken} | ||
token, err := findValidAccessTokenForTenant(tokens, tenantId) | ||
|
||
if err != nil { | ||
t.Fatalf("Expected no error to be returned but got %+v", err) | ||
} | ||
|
||
if token == nil { | ||
t.Fatalf("Expected Token to have a value but it was nil") | ||
} | ||
|
||
if token.AccessToken.AccessToken != expectedToken.AccessToken { | ||
t.Fatalf("Expected the Access Token to be %q but got %q", expectedToken.AccessToken, token.AccessToken.AccessToken) | ||
} | ||
|
||
if token.ClientID != expectedToken.ClientID { | ||
t.Fatalf("Expected the Client ID to be %q but got %q", expectedToken.ClientID, token.ClientID) | ||
} | ||
|
||
if token.IsCloudShell != false { | ||
t.Fatalf("Expected `IsCloudShell` to be false but got true") | ||
} | ||
} | ||
|
||
func TestAzureFindValidAccessTokenForTenant_NoTokens(t *testing.T) { | ||
tokens := make([]cli.Token, 0) | ||
token, err := findValidAccessTokenForTenant(tokens, "abc123") | ||
|
||
if err == nil { | ||
t.Fatalf("Expected an error but didn't get one") | ||
} | ||
|
||
if token != nil { | ||
t.Fatalf("Expected a null token to be returned but got: %+v", token) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package authentication | ||
|
||
import ( | ||
"strings" | ||
|
||
"fmt" | ||
|
||
"github.com/Azure/go-autorest/autorest/azure/cli" | ||
) | ||
|
||
type AzureCLIProfile struct { | ||
cli.Profile | ||
} | ||
|
||
func (a AzureCLIProfile) FindDefaultSubscriptionId() (string, error) { | ||
for _, subscription := range a.Subscriptions { | ||
if subscription.IsDefault { | ||
return subscription.ID, nil | ||
} | ||
} | ||
|
||
return "", fmt.Errorf("No Subscription was Marked as Default in the Azure Profile.") | ||
} | ||
|
||
func (a AzureCLIProfile) FindSubscription(subscriptionId string) (*cli.Subscription, error) { | ||
for _, subscription := range a.Subscriptions { | ||
if strings.EqualFold(subscription.ID, subscriptionId) { | ||
return &subscription, nil | ||
} | ||
} | ||
|
||
return nil, fmt.Errorf("Subscription %q was not found in your Azure CLI credentials. Please verify it exists in `az account list`.", subscriptionId) | ||
} |
Oops, something went wrong.