provider/azurerm: Upgrading to AutoRest v8 (#15006)

* Upgrading to AutoRest 8

* Upgrading to AutoRest v8

* Updating the Remote State to v8
This commit is contained in:
Tom Harvey 2017-06-02 15:30:41 +01:00 committed by GitHub
parent 483b849448
commit 13583b4b8b
16 changed files with 822 additions and 271 deletions

View File

@ -24,6 +24,7 @@ import (
"github.com/Azure/azure-sdk-for-go/arm/trafficmanager"
mainStorage "github.com/Azure/azure-sdk-for-go/storage"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/hashicorp/terraform/terraform"
riviera "github.com/jen20/riviera/azure"
@ -173,7 +174,7 @@ func (c *Config) getArmClient() (*ArmClient, error) {
}
client.rivieraClient = rivieraClient
oauthConfig, err := env.OAuthConfigForTenant(c.TenantID)
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, c.TenantID)
if err != nil {
return nil, err
}
@ -183,294 +184,295 @@ func (c *Config) getArmClient() (*ArmClient, error) {
return nil, fmt.Errorf("Unable to configure OAuthConfig for tenant %s", c.TenantID)
}
spt, err := azure.NewServicePrincipalToken(*oauthConfig, c.ClientID, c.ClientSecret, env.ResourceManagerEndpoint)
spt, err := adal.NewServicePrincipalToken(*oauthConfig, c.ClientID, c.ClientSecret, env.ResourceManagerEndpoint)
if err != nil {
return nil, err
}
endpoint := env.ResourceManagerEndpoint
auth := autorest.NewBearerAuthorizer(spt)
// NOTE: these declarations should be left separate for clarity should the
// clients be wished to be configured with custom Responders/PollingModess etc...
asc := compute.NewAvailabilitySetsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&asc.Client)
asc.Authorizer = spt
asc.Authorizer = auth
asc.Sender = autorest.CreateSender(withRequestLogging())
client.availSetClient = asc
uoc := compute.NewUsageClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&uoc.Client)
uoc.Authorizer = spt
uoc.Authorizer = auth
uoc.Sender = autorest.CreateSender(withRequestLogging())
client.usageOpsClient = uoc
vmeic := compute.NewVirtualMachineExtensionImagesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vmeic.Client)
vmeic.Authorizer = spt
vmeic.Authorizer = auth
vmeic.Sender = autorest.CreateSender(withRequestLogging())
client.vmExtensionImageClient = vmeic
vmec := compute.NewVirtualMachineExtensionsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vmec.Client)
vmec.Authorizer = spt
vmec.Authorizer = auth
vmec.Sender = autorest.CreateSender(withRequestLogging())
client.vmExtensionClient = vmec
vmic := compute.NewVirtualMachineImagesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vmic.Client)
vmic.Authorizer = spt
vmic.Authorizer = auth
vmic.Sender = autorest.CreateSender(withRequestLogging())
client.vmImageClient = vmic
vmssc := compute.NewVirtualMachineScaleSetsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vmssc.Client)
vmssc.Authorizer = spt
vmssc.Authorizer = auth
vmssc.Sender = autorest.CreateSender(withRequestLogging())
client.vmScaleSetClient = vmssc
vmc := compute.NewVirtualMachinesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vmc.Client)
vmc.Authorizer = spt
vmc.Authorizer = auth
vmc.Sender = autorest.CreateSender(withRequestLogging())
client.vmClient = vmc
agc := network.NewApplicationGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&agc.Client)
agc.Authorizer = spt
agc.Authorizer = auth
agc.Sender = autorest.CreateSender(withRequestLogging())
client.appGatewayClient = agc
crc := containerregistry.NewRegistriesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&crc.Client)
crc.Authorizer = spt
crc.Authorizer = auth
crc.Sender = autorest.CreateSender(withRequestLogging())
client.containerRegistryClient = crc
csc := containerservice.NewContainerServicesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&csc.Client)
csc.Authorizer = spt
csc.Authorizer = auth
csc.Sender = autorest.CreateSender(withRequestLogging())
client.containerServicesClient = csc
dkc := disk.NewDisksClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&dkc.Client)
dkc.Authorizer = spt
dkc.Authorizer = auth
dkc.Sender = autorest.CreateSender(withRequestLogging())
client.diskClient = dkc
ehc := eventhub.NewEventHubsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&ehc.Client)
ehc.Authorizer = spt
ehc.Authorizer = auth
ehc.Sender = autorest.CreateSender(withRequestLogging())
client.eventHubClient = ehc
chcgc := eventhub.NewConsumerGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&chcgc.Client)
chcgc.Authorizer = spt
chcgc.Authorizer = auth
chcgc.Sender = autorest.CreateSender(withRequestLogging())
client.eventHubConsumerGroupClient = chcgc
ehnc := eventhub.NewNamespacesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&ehnc.Client)
ehnc.Authorizer = spt
ehnc.Authorizer = auth
ehnc.Sender = autorest.CreateSender(withRequestLogging())
client.eventHubNamespacesClient = ehnc
ifc := network.NewInterfacesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&ifc.Client)
ifc.Authorizer = spt
ifc.Authorizer = auth
ifc.Sender = autorest.CreateSender(withRequestLogging())
client.ifaceClient = ifc
erc := network.NewExpressRouteCircuitsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&erc.Client)
erc.Authorizer = spt
erc.Authorizer = auth
erc.Sender = autorest.CreateSender(withRequestLogging())
client.expressRouteCircuitClient = erc
lbc := network.NewLoadBalancersClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&lbc.Client)
lbc.Authorizer = spt
lbc.Authorizer = auth
lbc.Sender = autorest.CreateSender(withRequestLogging())
client.loadBalancerClient = lbc
lgc := network.NewLocalNetworkGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&lgc.Client)
lgc.Authorizer = spt
lgc.Authorizer = auth
lgc.Sender = autorest.CreateSender(withRequestLogging())
client.localNetConnClient = lgc
pipc := network.NewPublicIPAddressesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&pipc.Client)
pipc.Authorizer = spt
pipc.Authorizer = auth
pipc.Sender = autorest.CreateSender(withRequestLogging())
client.publicIPClient = pipc
sgc := network.NewSecurityGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&sgc.Client)
sgc.Authorizer = spt
sgc.Authorizer = auth
sgc.Sender = autorest.CreateSender(withRequestLogging())
client.secGroupClient = sgc
src := network.NewSecurityRulesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&src.Client)
src.Authorizer = spt
src.Authorizer = auth
src.Sender = autorest.CreateSender(withRequestLogging())
client.secRuleClient = src
snc := network.NewSubnetsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&snc.Client)
snc.Authorizer = spt
snc.Authorizer = auth
snc.Sender = autorest.CreateSender(withRequestLogging())
client.subnetClient = snc
vgcc := network.NewVirtualNetworkGatewayConnectionsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vgcc.Client)
vgcc.Authorizer = spt
vgcc.Authorizer = auth
vgcc.Sender = autorest.CreateSender(withRequestLogging())
client.vnetGatewayConnectionsClient = vgcc
vgc := network.NewVirtualNetworkGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vgc.Client)
vgc.Authorizer = spt
vgc.Authorizer = auth
vgc.Sender = autorest.CreateSender(withRequestLogging())
client.vnetGatewayClient = vgc
vnc := network.NewVirtualNetworksClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vnc.Client)
vnc.Authorizer = spt
vnc.Authorizer = auth
vnc.Sender = autorest.CreateSender(withRequestLogging())
client.vnetClient = vnc
vnpc := network.NewVirtualNetworkPeeringsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&vnpc.Client)
vnpc.Authorizer = spt
vnpc.Authorizer = auth
vnpc.Sender = autorest.CreateSender(withRequestLogging())
client.vnetPeeringsClient = vnpc
rtc := network.NewRouteTablesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&rtc.Client)
rtc.Authorizer = spt
rtc.Authorizer = auth
rtc.Sender = autorest.CreateSender(withRequestLogging())
client.routeTablesClient = rtc
rc := network.NewRoutesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&rc.Client)
rc.Authorizer = spt
rc.Authorizer = auth
rc.Sender = autorest.CreateSender(withRequestLogging())
client.routesClient = rc
rgc := resources.NewGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&rgc.Client)
rgc.Authorizer = spt
rgc.Authorizer = auth
rgc.Sender = autorest.CreateSender(withRequestLogging())
client.resourceGroupClient = rgc
pc := resources.NewProvidersClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&pc.Client)
pc.Authorizer = spt
pc.Authorizer = auth
pc.Sender = autorest.CreateSender(withRequestLogging())
client.providers = pc
tc := resources.NewTagsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&tc.Client)
tc.Authorizer = spt
tc.Authorizer = auth
tc.Sender = autorest.CreateSender(withRequestLogging())
client.tagsClient = tc
rf := resources.NewGroupClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&rf.Client)
rf.Authorizer = spt
rf.Authorizer = auth
rf.Sender = autorest.CreateSender(withRequestLogging())
client.resourceFindClient = rf
jc := scheduler.NewJobsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&jc.Client)
jc.Authorizer = spt
jc.Authorizer = auth
jc.Sender = autorest.CreateSender(withRequestLogging())
client.jobsClient = jc
jcc := scheduler.NewJobCollectionsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&jcc.Client)
jcc.Authorizer = spt
jcc.Authorizer = auth
jcc.Sender = autorest.CreateSender(withRequestLogging())
client.jobsCollectionsClient = jcc
ssc := storage.NewAccountsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&ssc.Client)
ssc.Authorizer = spt
ssc.Authorizer = auth
ssc.Sender = autorest.CreateSender(withRequestLogging())
client.storageServiceClient = ssc
suc := storage.NewUsageClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&suc.Client)
suc.Authorizer = spt
suc.Authorizer = auth
suc.Sender = autorest.CreateSender(withRequestLogging())
client.storageUsageClient = suc
cpc := cdn.NewProfilesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&cpc.Client)
cpc.Authorizer = spt
cpc.Authorizer = auth
cpc.Sender = autorest.CreateSender(withRequestLogging())
client.cdnProfilesClient = cpc
cec := cdn.NewEndpointsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&cec.Client)
cec.Authorizer = spt
cec.Authorizer = auth
cec.Sender = autorest.CreateSender(withRequestLogging())
client.cdnEndpointsClient = cec
dc := resources.NewDeploymentsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&dc.Client)
dc.Authorizer = spt
dc.Authorizer = auth
dc.Sender = autorest.CreateSender(withRequestLogging())
client.deploymentsClient = dc
tmpc := trafficmanager.NewProfilesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&tmpc.Client)
tmpc.Authorizer = spt
tmpc.Authorizer = auth
tmpc.Sender = autorest.CreateSender(withRequestLogging())
client.trafficManagerProfilesClient = tmpc
tmec := trafficmanager.NewEndpointsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&tmec.Client)
tmec.Authorizer = spt
tmec.Authorizer = auth
tmec.Sender = autorest.CreateSender(withRequestLogging())
client.trafficManagerEndpointsClient = tmec
rdc := redis.NewGroupClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&rdc.Client)
rdc.Authorizer = spt
rdc.Authorizer = auth
rdc.Sender = autorest.CreateSender(withRequestLogging())
client.redisClient = rdc
sbnc := servicebus.NewNamespacesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&sbnc.Client)
sbnc.Authorizer = spt
sbnc.Authorizer = auth
sbnc.Sender = autorest.CreateSender(withRequestLogging())
client.serviceBusNamespacesClient = sbnc
sbtc := servicebus.NewTopicsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&sbtc.Client)
sbtc.Authorizer = spt
sbtc.Authorizer = auth
sbtc.Sender = autorest.CreateSender(withRequestLogging())
client.serviceBusTopicsClient = sbtc
sbsc := servicebus.NewSubscriptionsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&sbsc.Client)
sbsc.Authorizer = spt
sbsc.Authorizer = auth
sbsc.Sender = autorest.CreateSender(withRequestLogging())
client.serviceBusSubscriptionsClient = sbsc
kvc := keyvault.NewVaultsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&kvc.Client)
kvc.Authorizer = spt
kvc.Authorizer = auth
kvc.Sender = autorest.CreateSender(withRequestLogging())
client.keyVaultClient = kvc
sqlepc := sql.NewElasticPoolsClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&sqlepc.Client)
sqlepc.Authorizer = spt
sqlepc.Authorizer = auth
sqlepc.Sender = autorest.CreateSender(withRequestLogging())
client.sqlElasticPoolsClient = sqlepc

View File

@ -8,6 +8,8 @@ import (
"github.com/Azure/azure-sdk-for-go/arm/storage"
mainStorage "github.com/Azure/azure-sdk-for-go/storage"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
riviera "github.com/jen20/riviera/azure"
)
@ -68,7 +70,7 @@ func getStorageAccountAccessKey(conf map[string]string, resourceGroupName, stora
return "", err
}
oauthConfig, err := env.OAuthConfigForTenant(creds.TenantID)
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, creds.TenantID)
if err != nil {
return "", err
}
@ -76,13 +78,13 @@ func getStorageAccountAccessKey(conf map[string]string, resourceGroupName, stora
return "", fmt.Errorf("Unable to configure OAuthConfig for tenant %s", creds.TenantID)
}
spt, err := azure.NewServicePrincipalToken(*oauthConfig, creds.ClientID, creds.ClientSecret, env.ResourceManagerEndpoint)
spt, err := adal.NewServicePrincipalToken(*oauthConfig, creds.ClientID, creds.ClientSecret, env.ResourceManagerEndpoint)
if err != nil {
return "", err
}
accountsClient := storage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, creds.SubscriptionID)
accountsClient.Authorizer = spt
accountsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
keys, err := accountsClient.ListKeys(resourceGroupName, storageAccountName)
if err != nil {

View File

@ -0,0 +1,253 @@
# Azure Active Directory library for Go
This project provides a stand alone Azure Active Directory library for Go. The code was extracted
from [go-autorest](https://github.com/Azure/go-autorest/) project, which is used as a base for
[azure-sdk-for-go](https://github.com/Azure/azure-sdk-for-go).
## Installation
```
go get -u github.com/Azure/go-autorest/autorest/adal
```
## Usage
An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) follow these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli).
### Register an Azure AD Application with secret
1. Register a new application with a `secret` credential
```
az ad app create \
--display-name example-app \
--homepage https://example-app/home \
--identifier-uris https://example-app/app \
--password secret
```
2. Create a service principal using the `Application ID` from previous step
```
az ad sp create --id "Application ID"
```
* Replace `Application ID` with `appId` from step 1.
### Register an Azure AD Application with certificate
1. Create a private key
```
openssl genrsa -out "example-app.key" 2048
```
2. Create the certificate
```
openssl req -new -key "example-app.key" -subj "/CN=example-app" -out "example-app.csr"
openssl x509 -req -in "example-app.csr" -signkey "example-app.key" -out "example-app.crt" -days 10000
```
3. Create the PKCS12 version of the certificate containing also the private key
```
openssl pkcs12 -export -out "example-app.pfx" -inkey "example-app.key" -in "example-app.crt" -passout pass:
```
4. Register a new application with the certificate content form `example-app.crt`
```
certificateContents="$(tail -n+2 "example-app.crt" | head -n-1)"
az ad app create \
--display-name example-app \
--homepage https://example-app/home \
--identifier-uris https://example-app/app \
--key-usage Verify --end-date 2018-01-01 \
--key-value "${certificateContents}"
```
5. Create a service principal using the `Application ID` from previous step
```
az ad sp create --id "APPLICATION_ID"
```
* Replace `APPLICATION_ID` with `appId` from step 4.
### Grant the necessary permissions
Azure relies on a Role-Based Access Control (RBAC) model to manage the access to resources at a fine-grained
level. There is a set of [pre-defined roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-built-in-roles)
which can be assigned to a service principal of an Azure AD application depending of your needs.
```
az role assignment create --assigner "SERVICE_PRINCIPAL_ID" --role "ROLE_NAME"
```
* Replace the `SERVICE_PRINCIPAL_ID` with the `appId` from previous step.
* Replace the `ROLE_NAME` with a role name of your choice.
It is also possible to define custom role definitions.
```
az role definition create --role-definition role-definition.json
```
* Check [custom roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file.
### Acquire Access Token
The common configuration used by all flows:
```Go
const activeDirectoryEndpoint = "https://login.microsoftonline.com/"
tenantID := "TENANT_ID"
oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, tenantID)
applicationID := "APPLICATION_ID"
callback := func(token adal.Token) error {
// This is called after the token is acquired
}
// The resource for which the token is acquired
resource := "https://management.core.windows.net/"
```
* Replace the `TENANT_ID` with your tenant ID.
* Replace the `APPLICATION_ID` with the value from previous section.
#### Client Credentials
```Go
applicationSecret := "APPLICATION_SECRET"
spt, err := adal.NewServicePrincipalToken(
oauthConfig,
appliationID,
applicationSecret,
resource,
callbacks...)
if err != nil {
return nil, err
}
// Acquire a new access token
err = spt.Refresh()
if (err == nil) {
token := spt.Token
}
```
* Replace the `APPLICATION_SECRET` with the `password` value from previous section.
#### Client Certificate
```Go
certificatePath := "./example-app.pfx"
certData, err := ioutil.ReadFile(certificatePath)
if err != nil {
return nil, fmt.Errorf("failed to read the certificate file (%s): %v", certificatePath, err)
}
// Get the certificate and private key from pfx file
certificate, rsaPrivateKey, err := decodePkcs12(certData, "")
if err != nil {
return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
}
spt, err := adal.NewServicePrincipalTokenFromCertificate(
oauthConfig,
applicationID,
certificate,
rsaPrivateKey,
resource,
callbacks...)
// Acquire a new access token
err = spt.Refresh()
if (err == nil) {
token := spt.Token
}
```
* Update the certificate path to point to the example-app.pfx file which was created in previous section.
#### Device Code
```Go
oauthClient := &http.Client{}
// Acquire the device code
deviceCode, err := adal.InitiateDeviceAuth(
oauthClient,
oauthConfig,
applicationID,
resource)
if err != nil {
return nil, fmt.Errorf("Failed to start device auth flow: %s", err)
}
// Display the authentication message
fmt.Println(*deviceCode.Message)
// Wait here until the user is authenticated
token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
if err != nil {
return nil, fmt.Errorf("Failed to finish device auth flow: %s", err)
}
spt, err := adal.NewServicePrincipalTokenFromManualToken(
oauthConfig,
applicationID,
resource,
*token,
callbacks...)
if (err == nil) {
token := spt.Token
}
```
### Command Line Tool
A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above.
```
adal -h
Usage of ./adal:
-applicationId string
application id
-certificatePath string
path to pk12/PFC application certificate
-mode string
authentication mode (device, secret, cert, refresh) (default "device")
-resource string
resource for which the token is requested
-secret string
application secret
-tenantId string
tenant id
-tokenCachePath string
location of oath token cache (default "/home/cgc/.adal/accessToken.json")
```
Example acquire a token for `https://management.core.windows.net/` using device code flow:
```
adal -mode device \
-applicationId "APPLICATION_ID" \
-tenantId "TENANT_ID" \
-resource https://management.core.windows.net/
```

View File

@ -0,0 +1,51 @@
package adal
import (
"fmt"
"net/url"
)
const (
activeDirectoryAPIVersion = "1.0"
)
// OAuthConfig represents the endpoints needed
// in OAuth operations
type OAuthConfig struct {
AuthorityEndpoint url.URL
AuthorizeEndpoint url.URL
TokenEndpoint url.URL
DeviceCodeEndpoint url.URL
}
// NewOAuthConfig returns an OAuthConfig with tenant specific urls
func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s"
u, err := url.Parse(activeDirectoryEndpoint)
if err != nil {
return nil, err
}
authorityURL, err := u.Parse(tenantID)
if err != nil {
return nil, err
}
authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", activeDirectoryAPIVersion))
if err != nil {
return nil, err
}
tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", activeDirectoryAPIVersion))
if err != nil {
return nil, err
}
deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", activeDirectoryAPIVersion))
if err != nil {
return nil, err
}
return &OAuthConfig{
AuthorityEndpoint: *authorityURL,
AuthorizeEndpoint: *authorizeURL,
TokenEndpoint: *tokenURL,
DeviceCodeEndpoint: *deviceCodeURL,
}, nil
}

View File

@ -1,4 +1,4 @@
package azure
package adal
/*
This file is largely based on rjw57/oauth2device's code, with the follow differences:
@ -10,16 +10,17 @@ package azure
*/
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"github.com/Azure/go-autorest/autorest"
)
const (
logPrefix = "autorest/azure/devicetoken:"
logPrefix = "autorest/adal/devicetoken:"
)
var (
@ -38,10 +39,17 @@ var (
// ErrDeviceSlowDown represents the service telling us we're polling too often during device flow
ErrDeviceSlowDown = fmt.Errorf("%s Error while retrieving OAuth token: Slow Down", logPrefix)
// ErrDeviceCodeEmpty represents an empty device code from the device endpoint while using device flow
ErrDeviceCodeEmpty = fmt.Errorf("%s Error while retrieving device code: Device Code Empty", logPrefix)
// ErrOAuthTokenEmpty represents an empty OAuth token from the token endpoint when using device flow
ErrOAuthTokenEmpty = fmt.Errorf("%s Error while retrieving OAuth token: Token Empty", logPrefix)
errCodeSendingFails = "Error occurred while sending request for Device Authorization Code"
errCodeHandlingFails = "Error occurred while handling response from the Device Endpoint"
errTokenSendingFails = "Error occurred while sending request with device code for a token"
errTokenHandlingFails = "Error occurred while handling response from the Token Endpoint (during device flow)"
errStatusNotOK = "Error HTTP status != 200"
)
// DeviceCode is the object returned by the device auth endpoint
@ -79,31 +87,45 @@ type deviceToken struct {
// InitiateDeviceAuth initiates a device auth flow. It returns a DeviceCode
// that can be used with CheckForUserCompletion or WaitForUserCompletion.
func InitiateDeviceAuth(client *autorest.Client, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) {
req, _ := autorest.Prepare(
&http.Request{},
autorest.AsPost(),
autorest.AsFormURLEncoded(),
autorest.WithBaseURL(oauthConfig.DeviceCodeEndpoint.String()),
autorest.WithFormData(url.Values{
"client_id": []string{clientID},
"resource": []string{resource},
}),
)
func InitiateDeviceAuth(sender Sender, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) {
v := url.Values{
"client_id": []string{clientID},
"resource": []string{resource},
}
resp, err := autorest.SendWithSender(client, req)
s := v.Encode()
body := ioutil.NopCloser(strings.NewReader(s))
req, err := http.NewRequest(http.MethodPost, oauthConfig.DeviceCodeEndpoint.String(), body)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err)
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err.Error())
}
req.ContentLength = int64(len(s))
req.Header.Set(contentType, mimeTypeFormPost)
resp, err := sender.Do(req)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err.Error())
}
defer resp.Body.Close()
rb, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err.Error())
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, errStatusNotOK)
}
if len(strings.Trim(string(rb), " ")) == 0 {
return nil, ErrDeviceCodeEmpty
}
var code DeviceCode
err = autorest.Respond(
resp,
autorest.WithErrorUnlessStatusCode(http.StatusOK),
autorest.ByUnmarshallingJSON(&code),
autorest.ByClosing())
err = json.Unmarshal(rb, &code)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err)
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err.Error())
}
code.ClientID = clientID
@ -115,33 +137,46 @@ func InitiateDeviceAuth(client *autorest.Client, oauthConfig OAuthConfig, client
// CheckForUserCompletion takes a DeviceCode and checks with the Azure AD OAuth endpoint
// to see if the device flow has: been completed, timed out, or otherwise failed
func CheckForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) {
req, _ := autorest.Prepare(
&http.Request{},
autorest.AsPost(),
autorest.AsFormURLEncoded(),
autorest.WithBaseURL(code.OAuthConfig.TokenEndpoint.String()),
autorest.WithFormData(url.Values{
"client_id": []string{code.ClientID},
"code": []string{*code.DeviceCode},
"grant_type": []string{OAuthGrantTypeDeviceCode},
"resource": []string{code.Resource},
}),
)
func CheckForUserCompletion(sender Sender, code *DeviceCode) (*Token, error) {
v := url.Values{
"client_id": []string{code.ClientID},
"code": []string{*code.DeviceCode},
"grant_type": []string{OAuthGrantTypeDeviceCode},
"resource": []string{code.Resource},
}
resp, err := autorest.SendWithSender(client, req)
s := v.Encode()
body := ioutil.NopCloser(strings.NewReader(s))
req, err := http.NewRequest(http.MethodPost, code.OAuthConfig.TokenEndpoint.String(), body)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err)
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err.Error())
}
req.ContentLength = int64(len(s))
req.Header.Set(contentType, mimeTypeFormPost)
resp, err := sender.Do(req)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err.Error())
}
defer resp.Body.Close()
rb, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err.Error())
}
if resp.StatusCode != http.StatusOK && len(strings.Trim(string(rb), " ")) == 0 {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, errStatusNotOK)
}
if len(strings.Trim(string(rb), " ")) == 0 {
return nil, ErrOAuthTokenEmpty
}
var token deviceToken
err = autorest.Respond(
resp,
autorest.WithErrorUnlessStatusCode(http.StatusOK, http.StatusBadRequest),
autorest.ByUnmarshallingJSON(&token),
autorest.ByClosing())
err = json.Unmarshal(rb, &token)
if err != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err)
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err.Error())
}
if token.Error == nil {
@ -164,12 +199,12 @@ func CheckForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token,
// WaitForUserCompletion calls CheckForUserCompletion repeatedly until a token is granted or an error state occurs.
// This prevents the user from looping and checking against 'ErrDeviceAuthorizationPending'.
func WaitForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) {
func WaitForUserCompletion(sender Sender, code *DeviceCode) (*Token, error) {
intervalDuration := time.Duration(*code.Interval) * time.Second
waitDuration := intervalDuration
for {
token, err := CheckForUserCompletion(client, code)
token, err := CheckForUserCompletion(sender, code)
if err == nil {
return token, nil

View File

@ -1,4 +1,4 @@
package azure
package adal
import (
"encoding/json"

View File

@ -0,0 +1,46 @@
package adal
import (
"net/http"
)
const (
contentType = "Content-Type"
mimeTypeFormPost = "application/x-www-form-urlencoded"
)
// Sender is the interface that wraps the Do method to send HTTP requests.
//
// The standard http.Client conforms to this interface.
type Sender interface {
Do(*http.Request) (*http.Response, error)
}
// SenderFunc is a method that implements the Sender interface.
type SenderFunc func(*http.Request) (*http.Response, error)
// Do implements the Sender interface on SenderFunc.
func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
return sf(r)
}
// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the
// http.Request and pass it along or, first, pass the http.Request along then react to the
// http.Response result.
type SendDecorator func(Sender) Sender
// CreateSender creates, decorates, and returns, as a Sender, the default http.Client.
func CreateSender(decorators ...SendDecorator) Sender {
return DecorateSender(&http.Client{}, decorators...)
}
// DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to
// the Sender. Decorators are applied in the order received, but their affect upon the request
// depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a
// post-decorator (pass the http.Request along and react to the results in http.Response).
func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
for _, decorate := range decorators {
s = decorate(s)
}
return s
}

View File

@ -1,4 +1,4 @@
package azure
package adal
import (
"crypto/rand"
@ -6,13 +6,15 @@ import (
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/Azure/go-autorest/autorest"
"github.com/dgrijalva/jwt-go"
)
@ -28,6 +30,9 @@ const (
// OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows
OAuthGrantTypeRefreshToken = "refresh_token"
// managedIdentitySettingsPath is the path to the MSI Extension settings file (to discover the endpoint)
managedIdentitySettingsPath = "/var/lib/waagent/ManagedIdentity-Settings"
)
var expirationBase time.Time
@ -36,6 +41,18 @@ func init() {
expirationBase, _ = time.Parse(time.RFC3339, tokenBaseDate)
}
// OAuthTokenProvider is an interface which should be implemented by an access token retriever
type OAuthTokenProvider interface {
OAuthToken() string
}
// Refresher is an interface for token refresh functionality
type Refresher interface {
Refresh() error
RefreshExchange(resource string) error
EnsureFresh() error
}
// TokenRefreshCallback is the type representing callbacks that will be called after
// a successful token refresh
type TokenRefreshCallback func(Token) error
@ -73,14 +90,9 @@ func (t Token) WillExpireIn(d time.Duration) bool {
return !t.Expires().After(time.Now().Add(d))
}
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
// value is "Bearer " followed by the AccessToken of the Token.
func (t *Token) WithAuthorization() autorest.PrepareDecorator {
return func(p autorest.Preparer) autorest.Preparer {
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
return (autorest.WithBearerAuthorization(t.AccessToken)(p)).Prepare(r)
})
}
//OAuthToken return the current access token
func (t *Token) OAuthToken() string {
return t.AccessToken
}
// ServicePrincipalNoSecret represents a secret type that contains no secret
@ -118,6 +130,17 @@ type ServicePrincipalCertificateSecret struct {
PrivateKey *rsa.PrivateKey
}
// ServicePrincipalMSISecret implements ServicePrincipalSecret for machines running the MSI Extension.
type ServicePrincipalMSISecret struct {
}
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
// MSI extension requires the authority field to be set to the real tenant authority endpoint
func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
v.Set("authority", spt.oauthConfig.AuthorityEndpoint.String())
return nil
}
// SignJwt returns the JWT signed with the certificate's private key.
func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) {
hasher := sha1.New()
@ -173,7 +196,7 @@ type ServicePrincipalToken struct {
resource string
autoRefresh bool
refreshWithin time.Duration
sender autorest.Sender
sender Sender
refreshCallbacks []TokenRefreshCallback
}
@ -238,10 +261,56 @@ func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID s
)
}
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
func NewServicePrincipalTokenFromMSI(oauthConfig OAuthConfig, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(oauthConfig, resource, managedIdentitySettingsPath, callbacks...)
}
func newServicePrincipalTokenFromMSI(oauthConfig OAuthConfig, resource, settingsPath string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
// Read MSI settings
bytes, err := ioutil.ReadFile(settingsPath)
if err != nil {
return nil, err
}
msiSettings := struct {
URL string `json:"url"`
}{}
err = json.Unmarshal(bytes, &msiSettings)
if err != nil {
return nil, err
}
// We set the oauth config token endpoint to be MSI's endpoint
// We leave the authority as-is so MSI can POST it with the token request
msiEndpointURL, err := url.Parse(msiSettings.URL)
if err != nil {
return nil, err
}
msiTokenEndpointURL, err := msiEndpointURL.Parse("/oauth2/token")
if err != nil {
return nil, err
}
oauthConfig.TokenEndpoint = *msiTokenEndpointURL
spt := &ServicePrincipalToken{
oauthConfig: oauthConfig,
secret: &ServicePrincipalMSISecret{},
resource: resource,
autoRefresh: true,
refreshWithin: defaultRefresh,
sender: &http.Client{},
refreshCallbacks: callbacks,
}
return spt, nil
}
// EnsureFresh will refresh the token if it will expire within the refresh window (as set by
// RefreshWithin).
// RefreshWithin) and autoRefresh flag is on.
func (spt *ServicePrincipalToken) EnsureFresh() error {
if spt.WillExpireIn(spt.refreshWithin) {
if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) {
return spt.Refresh()
}
return nil
@ -253,8 +322,7 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
for _, callback := range spt.refreshCallbacks {
err := callback(spt.Token)
if err != nil {
return autorest.NewErrorWithError(err,
"azure.ServicePrincipalToken", "InvokeRefreshCallbacks", nil, "A TokenRefreshCallback handler returned an error")
return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err)
}
}
}
@ -287,39 +355,40 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
}
}
req, _ := autorest.Prepare(&http.Request{},
autorest.AsPost(),
autorest.AsFormURLEncoded(),
autorest.WithBaseURL(spt.oauthConfig.TokenEndpoint.String()),
autorest.WithFormData(v))
resp, err := autorest.SendWithSender(spt.sender, req)
s := v.Encode()
body := ioutil.NopCloser(strings.NewReader(s))
req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), body)
if err != nil {
return autorest.NewErrorWithError(err,
"azure.ServicePrincipalToken", "Refresh", resp, "Failure sending request for Service Principal %s",
spt.clientID)
return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err)
}
var newToken Token
err = autorest.Respond(resp,
autorest.WithErrorUnlessStatusCode(http.StatusOK),
autorest.ByUnmarshallingJSON(&newToken),
autorest.ByClosing())
req.ContentLength = int64(len(s))
req.Header.Set(contentType, mimeTypeFormPost)
resp, err := spt.sender.Do(req)
if err != nil {
return autorest.NewErrorWithError(err,
"azure.ServicePrincipalToken", "Refresh", resp, "Failure handling response to Service Principal %s request",
spt.clientID)
return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'", resp.StatusCode)
}
spt.Token = newToken
err = spt.InvokeRefreshCallbacks(newToken)
rb, err := ioutil.ReadAll(resp.Body)
if err != nil {
// its already wrapped inside InvokeRefreshCallbacks
return err
return fmt.Errorf("adal: Failed to read a new service principal token during refresh. Error = '%v'", err)
}
if len(strings.Trim(string(rb), " ")) == 0 {
return fmt.Errorf("adal: Empty service principal token received during refresh")
}
var token Token
err = json.Unmarshal(rb, &token)
if err != nil {
return fmt.Errorf("adal: Failed to unmarshal the service principal token during refresh. Error = '%v' JSON = '%s'", err, string(rb))
}
return nil
spt.Token = token
return spt.InvokeRefreshCallbacks(token)
}
// SetAutoRefresh enables or disables automatic refreshing of stale tokens.
@ -334,30 +403,6 @@ func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) {
return
}
// SetSender sets the autorest.Sender used when obtaining the Service Principal token. An
// SetSender sets the http.Client used when obtaining the Service Principal token. An
// undecorated http.Client is used by default.
func (spt *ServicePrincipalToken) SetSender(s autorest.Sender) {
spt.sender = s
}
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
// value is "Bearer " followed by the AccessToken of the ServicePrincipalToken.
//
// By default, the token will automatically refresh if nearly expired (as determined by the
// RefreshWithin interval). Use the AutoRefresh method to enable or disable automatically refreshing
// tokens.
func (spt *ServicePrincipalToken) WithAuthorization() autorest.PrepareDecorator {
return func(p autorest.Preparer) autorest.Preparer {
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
if spt.autoRefresh {
err := spt.EnsureFresh()
if err != nil {
return r, autorest.NewErrorWithError(err,
"azure.ServicePrincipalToken", "WithAuthorization", nil, "Failed to refresh Service Principal Token for request to %s",
r.URL)
}
}
return (autorest.WithBearerAuthorization(spt.AccessToken)(p)).Prepare(r)
})
}
}
func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s }

View File

@ -0,0 +1,57 @@
package autorest
import (
"fmt"
"net/http"
"github.com/Azure/go-autorest/autorest/adal"
)
// Authorizer is the interface that provides a PrepareDecorator used to supply request
// authorization. Most often, the Authorizer decorator runs last so it has access to the full
// state of the formed HTTP request.
type Authorizer interface {
WithAuthorization() PrepareDecorator
}
// NullAuthorizer implements a default, "do nothing" Authorizer.
type NullAuthorizer struct{}
// WithAuthorization returns a PrepareDecorator that does nothing.
func (na NullAuthorizer) WithAuthorization() PrepareDecorator {
return WithNothing()
}
// BearerAuthorizer implements the bearer authorization
type BearerAuthorizer struct {
tokenProvider adal.OAuthTokenProvider
}
// NewBearerAuthorizer crates a BearerAuthorizer using the given token provider
func NewBearerAuthorizer(tp adal.OAuthTokenProvider) *BearerAuthorizer {
return &BearerAuthorizer{tokenProvider: tp}
}
func (ba *BearerAuthorizer) withBearerAuthorization() PrepareDecorator {
return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken()))
}
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
// value is "Bearer " followed by the token.
//
// By default, the token will be automatically refreshed through the Refresher interface.
func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator {
return func(p Preparer) Preparer {
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
refresher, ok := ba.tokenProvider.(adal.Refresher)
if ok {
err := refresher.EnsureFresh()
if err != nil {
return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", nil,
"Failed to refresh the Token for request to %s", r.URL)
}
}
return (ba.withBearerAuthorization()(p)).Prepare(r)
})
}
}

View File

@ -17,12 +17,6 @@ const (
)
const (
methodDelete = "DELETE"
methodPatch = "PATCH"
methodPost = "POST"
methodPut = "PUT"
methodGet = "GET"
operationInProgress string = "InProgress"
operationCanceled string = "Canceled"
operationFailed string = "Failed"
@ -226,7 +220,7 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
// Lastly, requests against an existing resource, use the last request URI
if ps.uri == "" {
m := strings.ToUpper(req.Method)
if m == methodPatch || m == methodPut || m == methodGet {
if m == http.MethodPatch || m == http.MethodPut || m == http.MethodGet {
ps.uri = req.URL.String()
}
}

View File

@ -1,13 +0,0 @@
package azure
import (
"net/url"
)
// OAuthConfig represents the endpoints needed
// in OAuth operations
type OAuthConfig struct {
AuthorizeEndpoint url.URL
TokenEndpoint url.URL
DeviceCodeEndpoint url.URL
}

View File

@ -2,14 +2,9 @@ package azure
import (
"fmt"
"net/url"
"strings"
)
const (
activeDirectoryAPIVersion = "1.0"
)
var environments = map[string]Environment{
"AZURECHINACLOUD": ChinaCloud,
"AZUREGERMANCLOUD": GermanCloud,
@ -133,35 +128,3 @@ func EnvironmentFromName(name string) (Environment, error) {
}
return env, nil
}
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls
func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) {
return OAuthConfigForTenant(env.ActiveDirectoryEndpoint, tenantID)
}
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls for target cloud auth endpoint
func OAuthConfigForTenant(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
template := "%s/oauth2/%s?api-version=%s"
u, err := url.Parse(activeDirectoryEndpoint)
if err != nil {
return nil, err
}
authorizeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "authorize", activeDirectoryAPIVersion))
if err != nil {
return nil, err
}
tokenURL, err := u.Parse(fmt.Sprintf(template, tenantID, "token", activeDirectoryAPIVersion))
if err != nil {
return nil, err
}
deviceCodeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "devicecode", activeDirectoryAPIVersion))
if err != nil {
return nil, err
}
return &OAuthConfig{
AuthorizeEndpoint: *authorizeURL,
TokenEndpoint: *tokenURL,
DeviceCodeEndpoint: *deviceCodeURL,
}, nil
}

View File

@ -0,0 +1,109 @@
package date
import (
"bytes"
"encoding/binary"
"encoding/json"
"time"
)
// unixEpoch is the moment in time that should be treated as timestamp 0.
var unixEpoch = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
// UnixTime marshals and unmarshals a time that is represented as the number
// of seconds (ignoring skip-seconds) since the Unix Epoch.
type UnixTime time.Time
// Duration returns the time as a Duration since the UnixEpoch.
func (t UnixTime) Duration() time.Duration {
return time.Time(t).Sub(unixEpoch)
}
// NewUnixTimeFromSeconds creates a UnixTime as a number of seconds from the UnixEpoch.
func NewUnixTimeFromSeconds(seconds float64) UnixTime {
return NewUnixTimeFromDuration(time.Duration(seconds * float64(time.Second)))
}
// NewUnixTimeFromNanoseconds creates a UnixTime as a number of nanoseconds from the UnixEpoch.
func NewUnixTimeFromNanoseconds(nanoseconds int64) UnixTime {
return NewUnixTimeFromDuration(time.Duration(nanoseconds))
}
// NewUnixTimeFromDuration creates a UnixTime as a duration of time since the UnixEpoch.
func NewUnixTimeFromDuration(dur time.Duration) UnixTime {
return UnixTime(unixEpoch.Add(dur))
}
// UnixEpoch retreives the moment considered the Unix Epoch. I.e. The time represented by '0'
func UnixEpoch() time.Time {
return unixEpoch
}
// MarshalJSON preserves the UnixTime as a JSON number conforming to Unix Timestamp requirements.
// (i.e. the number of seconds since midnight January 1st, 1970 not considering leap seconds.)
func (t UnixTime) MarshalJSON() ([]byte, error) {
buffer := &bytes.Buffer{}
enc := json.NewEncoder(buffer)
err := enc.Encode(float64(time.Time(t).UnixNano()) / 1e9)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// UnmarshalJSON reconstitures a UnixTime saved as a JSON number of the number of seconds since
// midnight January 1st, 1970.
func (t *UnixTime) UnmarshalJSON(text []byte) error {
dec := json.NewDecoder(bytes.NewReader(text))
var secondsSinceEpoch float64
if err := dec.Decode(&secondsSinceEpoch); err != nil {
return err
}
*t = NewUnixTimeFromSeconds(secondsSinceEpoch)
return nil
}
// MarshalText stores the number of seconds since the Unix Epoch as a textual floating point number.
func (t UnixTime) MarshalText() ([]byte, error) {
cast := time.Time(t)
return cast.MarshalText()
}
// UnmarshalText populates a UnixTime with a value stored textually as a floating point number of seconds since the Unix Epoch.
func (t *UnixTime) UnmarshalText(raw []byte) error {
var unmarshaled time.Time
if err := unmarshaled.UnmarshalText(raw); err != nil {
return err
}
*t = UnixTime(unmarshaled)
return nil
}
// MarshalBinary converts a UnixTime into a binary.LittleEndian float64 of nanoseconds since the epoch.
func (t UnixTime) MarshalBinary() ([]byte, error) {
buf := &bytes.Buffer{}
payload := int64(t.Duration())
if err := binary.Write(buf, binary.LittleEndian, &payload); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// UnmarshalBinary converts a from a binary.LittleEndian float64 of nanoseconds since the epoch into a UnixTime.
func (t *UnixTime) UnmarshalBinary(raw []byte) error {
var nanosecondsSinceEpoch int64
if err := binary.Read(bytes.NewReader(raw), binary.LittleEndian, &nanosecondsSinceEpoch); err != nil {
return err
}
*t = NewUnixTimeFromNanoseconds(nanosecondsSinceEpoch)
return nil
}

View File

@ -426,18 +426,3 @@ func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorato
})
}
}
// Authorizer is the interface that provides a PrepareDecorator used to supply request
// authorization. Most often, the Authorizer decorator runs last so it has access to the full
// state of the formed HTTP request.
type Authorizer interface {
WithAuthorization() PrepareDecorator
}
// NullAuthorizer implements a default, "do nothing" Authorizer.
type NullAuthorizer struct{}
// WithAuthorization returns a PrepareDecorator that does nothing.
func (na NullAuthorizer) WithAuthorization() PrepareDecorator {
return WithNothing()
}

View File

@ -1,23 +1,35 @@
package autorest
import (
"bytes"
"fmt"
"strings"
"sync"
)
const (
major = "7"
minor = "3"
patch = "0"
tag = ""
semVerFormat = "%s.%s.%s%s"
major = 8
minor = 0
patch = 0
tag = ""
)
var once sync.Once
var version string
// Version returns the semantic version (see http://semver.org).
func Version() string {
if version == "" {
version = fmt.Sprintf(semVerFormat, major, minor, patch, tag)
}
once.Do(func() {
semver := fmt.Sprintf("%d.%d.%d", major, minor, patch)
verBuilder := bytes.NewBufferString(semver)
if tag != "" && tag != "-" {
updated := strings.TrimPrefix(tag, "-")
_, err := verBuilder.WriteString("-" + updated)
if err == nil {
verBuilder = bytes.NewBufferString(semver)
}
}
version = verBuilder.String()
})
return version
}

64
vendor/vendor.json vendored
View File

@ -265,48 +265,58 @@
"revisionTime": "2016-06-22T17:32:16Z"
},
{
"checksumSHA1": "+sxS3YEvxf1VxlRskIdXFRWq9rY=",
"comment": "v7.0.5",
"checksumSHA1": "NwbvjCz9Xo4spo0C96Tq6WCLX7U=",
"comment": "v8.0.0",
"path": "github.com/Azure/go-autorest/autorest",
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
"revisionTime": "2017-02-15T19:58:14Z",
"version": "v7.3.1",
"versionExact": "v7.3.1"
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
"revisionTime": "2017-04-28T17:52:31Z",
"version": "v8.0.0",
"versionExact": "v8.0.0"
},
{
"checksumSHA1": "ghrnc4vZv6q8zzeakZnrS8CGFhE=",
"comment": "v7.0.5",
"checksumSHA1": "KOETWLsF6QW+lrPVPsMNHDZP+xA=",
"comment": "v8.0.0",
"path": "github.com/Azure/go-autorest/autorest/adal",
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
"revisionTime": "2017-04-28T17:52:31Z",
"version": "v8.0.0",
"versionExact": "v8.0.0"
},
{
"checksumSHA1": "2KdBFgT4qY+fMOkBTa5vA9V0AiM=",
"comment": "v8.0.0",
"path": "github.com/Azure/go-autorest/autorest/azure",
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
"revisionTime": "2017-02-15T19:58:14Z",
"version": "v7.3.1",
"versionExact": "v7.3.1"
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
"revisionTime": "2017-04-28T17:52:31Z",
"version": "v8.0.0",
"versionExact": "v8.0.0"
},
{
"checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=",
"comment": "v7.0.5",
"checksumSHA1": "LSF/pNrjhIxl6jiS6bKooBFCOxI=",
"comment": "v8.0.0",
"path": "github.com/Azure/go-autorest/autorest/date",
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
"revisionTime": "2017-02-15T19:58:14Z",
"version": "v7.3.1",
"versionExact": "v7.3.1"
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
"revisionTime": "2017-04-28T17:52:31Z",
"version": "v8.0.0",
"versionExact": "v8.0.0"
},
{
"checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
"comment": "v7.0.5",
"comment": "v8.0.0",
"path": "github.com/Azure/go-autorest/autorest/to",
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
"revisionTime": "2017-02-15T19:58:14Z",
"version": "v7.3.1",
"versionExact": "v7.3.1"
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
"revisionTime": "2017-04-28T17:52:31Z",
"version": "v8.0.0",
"versionExact": "v8.0.0"
},
{
"checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
"comment": "v8.0.0",
"path": "github.com/Azure/go-autorest/autorest/validation",
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
"revisionTime": "2017-02-15T19:58:14Z",
"version": "v7.3.1",
"versionExact": "v7.3.1"
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
"revisionTime": "2017-04-28T17:52:31Z",
"version": "v8.0.0",
"versionExact": "v8.0.0"
},
{
"checksumSHA1": "ICScouhAqYHoJEpJlJMYg7EzgyY=",