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:
parent
483b849448
commit
13583b4b8b
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/Azure/azure-sdk-for-go/arm/trafficmanager"
|
"github.com/Azure/azure-sdk-for-go/arm/trafficmanager"
|
||||||
mainStorage "github.com/Azure/azure-sdk-for-go/storage"
|
mainStorage "github.com/Azure/azure-sdk-for-go/storage"
|
||||||
"github.com/Azure/go-autorest/autorest"
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
"github.com/Azure/go-autorest/autorest/adal"
|
||||||
"github.com/Azure/go-autorest/autorest/azure"
|
"github.com/Azure/go-autorest/autorest/azure"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
riviera "github.com/jen20/riviera/azure"
|
riviera "github.com/jen20/riviera/azure"
|
||||||
|
@ -173,7 +174,7 @@ func (c *Config) getArmClient() (*ArmClient, error) {
|
||||||
}
|
}
|
||||||
client.rivieraClient = rivieraClient
|
client.rivieraClient = rivieraClient
|
||||||
|
|
||||||
oauthConfig, err := env.OAuthConfigForTenant(c.TenantID)
|
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, c.TenantID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := env.ResourceManagerEndpoint
|
endpoint := env.ResourceManagerEndpoint
|
||||||
|
auth := autorest.NewBearerAuthorizer(spt)
|
||||||
|
|
||||||
// NOTE: these declarations should be left separate for clarity should the
|
// NOTE: these declarations should be left separate for clarity should the
|
||||||
// clients be wished to be configured with custom Responders/PollingModess etc...
|
// clients be wished to be configured with custom Responders/PollingModess etc...
|
||||||
asc := compute.NewAvailabilitySetsClientWithBaseURI(endpoint, c.SubscriptionID)
|
asc := compute.NewAvailabilitySetsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&asc.Client)
|
setUserAgent(&asc.Client)
|
||||||
asc.Authorizer = spt
|
asc.Authorizer = auth
|
||||||
asc.Sender = autorest.CreateSender(withRequestLogging())
|
asc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.availSetClient = asc
|
client.availSetClient = asc
|
||||||
|
|
||||||
uoc := compute.NewUsageClientWithBaseURI(endpoint, c.SubscriptionID)
|
uoc := compute.NewUsageClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&uoc.Client)
|
setUserAgent(&uoc.Client)
|
||||||
uoc.Authorizer = spt
|
uoc.Authorizer = auth
|
||||||
uoc.Sender = autorest.CreateSender(withRequestLogging())
|
uoc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.usageOpsClient = uoc
|
client.usageOpsClient = uoc
|
||||||
|
|
||||||
vmeic := compute.NewVirtualMachineExtensionImagesClientWithBaseURI(endpoint, c.SubscriptionID)
|
vmeic := compute.NewVirtualMachineExtensionImagesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vmeic.Client)
|
setUserAgent(&vmeic.Client)
|
||||||
vmeic.Authorizer = spt
|
vmeic.Authorizer = auth
|
||||||
vmeic.Sender = autorest.CreateSender(withRequestLogging())
|
vmeic.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vmExtensionImageClient = vmeic
|
client.vmExtensionImageClient = vmeic
|
||||||
|
|
||||||
vmec := compute.NewVirtualMachineExtensionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
vmec := compute.NewVirtualMachineExtensionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vmec.Client)
|
setUserAgent(&vmec.Client)
|
||||||
vmec.Authorizer = spt
|
vmec.Authorizer = auth
|
||||||
vmec.Sender = autorest.CreateSender(withRequestLogging())
|
vmec.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vmExtensionClient = vmec
|
client.vmExtensionClient = vmec
|
||||||
|
|
||||||
vmic := compute.NewVirtualMachineImagesClientWithBaseURI(endpoint, c.SubscriptionID)
|
vmic := compute.NewVirtualMachineImagesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vmic.Client)
|
setUserAgent(&vmic.Client)
|
||||||
vmic.Authorizer = spt
|
vmic.Authorizer = auth
|
||||||
vmic.Sender = autorest.CreateSender(withRequestLogging())
|
vmic.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vmImageClient = vmic
|
client.vmImageClient = vmic
|
||||||
|
|
||||||
vmssc := compute.NewVirtualMachineScaleSetsClientWithBaseURI(endpoint, c.SubscriptionID)
|
vmssc := compute.NewVirtualMachineScaleSetsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vmssc.Client)
|
setUserAgent(&vmssc.Client)
|
||||||
vmssc.Authorizer = spt
|
vmssc.Authorizer = auth
|
||||||
vmssc.Sender = autorest.CreateSender(withRequestLogging())
|
vmssc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vmScaleSetClient = vmssc
|
client.vmScaleSetClient = vmssc
|
||||||
|
|
||||||
vmc := compute.NewVirtualMachinesClientWithBaseURI(endpoint, c.SubscriptionID)
|
vmc := compute.NewVirtualMachinesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vmc.Client)
|
setUserAgent(&vmc.Client)
|
||||||
vmc.Authorizer = spt
|
vmc.Authorizer = auth
|
||||||
vmc.Sender = autorest.CreateSender(withRequestLogging())
|
vmc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vmClient = vmc
|
client.vmClient = vmc
|
||||||
|
|
||||||
agc := network.NewApplicationGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
|
agc := network.NewApplicationGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&agc.Client)
|
setUserAgent(&agc.Client)
|
||||||
agc.Authorizer = spt
|
agc.Authorizer = auth
|
||||||
agc.Sender = autorest.CreateSender(withRequestLogging())
|
agc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.appGatewayClient = agc
|
client.appGatewayClient = agc
|
||||||
|
|
||||||
crc := containerregistry.NewRegistriesClientWithBaseURI(endpoint, c.SubscriptionID)
|
crc := containerregistry.NewRegistriesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&crc.Client)
|
setUserAgent(&crc.Client)
|
||||||
crc.Authorizer = spt
|
crc.Authorizer = auth
|
||||||
crc.Sender = autorest.CreateSender(withRequestLogging())
|
crc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.containerRegistryClient = crc
|
client.containerRegistryClient = crc
|
||||||
|
|
||||||
csc := containerservice.NewContainerServicesClientWithBaseURI(endpoint, c.SubscriptionID)
|
csc := containerservice.NewContainerServicesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&csc.Client)
|
setUserAgent(&csc.Client)
|
||||||
csc.Authorizer = spt
|
csc.Authorizer = auth
|
||||||
csc.Sender = autorest.CreateSender(withRequestLogging())
|
csc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.containerServicesClient = csc
|
client.containerServicesClient = csc
|
||||||
|
|
||||||
dkc := disk.NewDisksClientWithBaseURI(endpoint, c.SubscriptionID)
|
dkc := disk.NewDisksClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&dkc.Client)
|
setUserAgent(&dkc.Client)
|
||||||
dkc.Authorizer = spt
|
dkc.Authorizer = auth
|
||||||
dkc.Sender = autorest.CreateSender(withRequestLogging())
|
dkc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.diskClient = dkc
|
client.diskClient = dkc
|
||||||
|
|
||||||
ehc := eventhub.NewEventHubsClientWithBaseURI(endpoint, c.SubscriptionID)
|
ehc := eventhub.NewEventHubsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&ehc.Client)
|
setUserAgent(&ehc.Client)
|
||||||
ehc.Authorizer = spt
|
ehc.Authorizer = auth
|
||||||
ehc.Sender = autorest.CreateSender(withRequestLogging())
|
ehc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.eventHubClient = ehc
|
client.eventHubClient = ehc
|
||||||
|
|
||||||
chcgc := eventhub.NewConsumerGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
|
chcgc := eventhub.NewConsumerGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&chcgc.Client)
|
setUserAgent(&chcgc.Client)
|
||||||
chcgc.Authorizer = spt
|
chcgc.Authorizer = auth
|
||||||
chcgc.Sender = autorest.CreateSender(withRequestLogging())
|
chcgc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.eventHubConsumerGroupClient = chcgc
|
client.eventHubConsumerGroupClient = chcgc
|
||||||
|
|
||||||
ehnc := eventhub.NewNamespacesClientWithBaseURI(endpoint, c.SubscriptionID)
|
ehnc := eventhub.NewNamespacesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&ehnc.Client)
|
setUserAgent(&ehnc.Client)
|
||||||
ehnc.Authorizer = spt
|
ehnc.Authorizer = auth
|
||||||
ehnc.Sender = autorest.CreateSender(withRequestLogging())
|
ehnc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.eventHubNamespacesClient = ehnc
|
client.eventHubNamespacesClient = ehnc
|
||||||
|
|
||||||
ifc := network.NewInterfacesClientWithBaseURI(endpoint, c.SubscriptionID)
|
ifc := network.NewInterfacesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&ifc.Client)
|
setUserAgent(&ifc.Client)
|
||||||
ifc.Authorizer = spt
|
ifc.Authorizer = auth
|
||||||
ifc.Sender = autorest.CreateSender(withRequestLogging())
|
ifc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.ifaceClient = ifc
|
client.ifaceClient = ifc
|
||||||
|
|
||||||
erc := network.NewExpressRouteCircuitsClientWithBaseURI(endpoint, c.SubscriptionID)
|
erc := network.NewExpressRouteCircuitsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&erc.Client)
|
setUserAgent(&erc.Client)
|
||||||
erc.Authorizer = spt
|
erc.Authorizer = auth
|
||||||
erc.Sender = autorest.CreateSender(withRequestLogging())
|
erc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.expressRouteCircuitClient = erc
|
client.expressRouteCircuitClient = erc
|
||||||
|
|
||||||
lbc := network.NewLoadBalancersClientWithBaseURI(endpoint, c.SubscriptionID)
|
lbc := network.NewLoadBalancersClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&lbc.Client)
|
setUserAgent(&lbc.Client)
|
||||||
lbc.Authorizer = spt
|
lbc.Authorizer = auth
|
||||||
lbc.Sender = autorest.CreateSender(withRequestLogging())
|
lbc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.loadBalancerClient = lbc
|
client.loadBalancerClient = lbc
|
||||||
|
|
||||||
lgc := network.NewLocalNetworkGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
|
lgc := network.NewLocalNetworkGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&lgc.Client)
|
setUserAgent(&lgc.Client)
|
||||||
lgc.Authorizer = spt
|
lgc.Authorizer = auth
|
||||||
lgc.Sender = autorest.CreateSender(withRequestLogging())
|
lgc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.localNetConnClient = lgc
|
client.localNetConnClient = lgc
|
||||||
|
|
||||||
pipc := network.NewPublicIPAddressesClientWithBaseURI(endpoint, c.SubscriptionID)
|
pipc := network.NewPublicIPAddressesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&pipc.Client)
|
setUserAgent(&pipc.Client)
|
||||||
pipc.Authorizer = spt
|
pipc.Authorizer = auth
|
||||||
pipc.Sender = autorest.CreateSender(withRequestLogging())
|
pipc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.publicIPClient = pipc
|
client.publicIPClient = pipc
|
||||||
|
|
||||||
sgc := network.NewSecurityGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
|
sgc := network.NewSecurityGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&sgc.Client)
|
setUserAgent(&sgc.Client)
|
||||||
sgc.Authorizer = spt
|
sgc.Authorizer = auth
|
||||||
sgc.Sender = autorest.CreateSender(withRequestLogging())
|
sgc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.secGroupClient = sgc
|
client.secGroupClient = sgc
|
||||||
|
|
||||||
src := network.NewSecurityRulesClientWithBaseURI(endpoint, c.SubscriptionID)
|
src := network.NewSecurityRulesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&src.Client)
|
setUserAgent(&src.Client)
|
||||||
src.Authorizer = spt
|
src.Authorizer = auth
|
||||||
src.Sender = autorest.CreateSender(withRequestLogging())
|
src.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.secRuleClient = src
|
client.secRuleClient = src
|
||||||
|
|
||||||
snc := network.NewSubnetsClientWithBaseURI(endpoint, c.SubscriptionID)
|
snc := network.NewSubnetsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&snc.Client)
|
setUserAgent(&snc.Client)
|
||||||
snc.Authorizer = spt
|
snc.Authorizer = auth
|
||||||
snc.Sender = autorest.CreateSender(withRequestLogging())
|
snc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.subnetClient = snc
|
client.subnetClient = snc
|
||||||
|
|
||||||
vgcc := network.NewVirtualNetworkGatewayConnectionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
vgcc := network.NewVirtualNetworkGatewayConnectionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vgcc.Client)
|
setUserAgent(&vgcc.Client)
|
||||||
vgcc.Authorizer = spt
|
vgcc.Authorizer = auth
|
||||||
vgcc.Sender = autorest.CreateSender(withRequestLogging())
|
vgcc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vnetGatewayConnectionsClient = vgcc
|
client.vnetGatewayConnectionsClient = vgcc
|
||||||
|
|
||||||
vgc := network.NewVirtualNetworkGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
|
vgc := network.NewVirtualNetworkGatewaysClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vgc.Client)
|
setUserAgent(&vgc.Client)
|
||||||
vgc.Authorizer = spt
|
vgc.Authorizer = auth
|
||||||
vgc.Sender = autorest.CreateSender(withRequestLogging())
|
vgc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vnetGatewayClient = vgc
|
client.vnetGatewayClient = vgc
|
||||||
|
|
||||||
vnc := network.NewVirtualNetworksClientWithBaseURI(endpoint, c.SubscriptionID)
|
vnc := network.NewVirtualNetworksClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vnc.Client)
|
setUserAgent(&vnc.Client)
|
||||||
vnc.Authorizer = spt
|
vnc.Authorizer = auth
|
||||||
vnc.Sender = autorest.CreateSender(withRequestLogging())
|
vnc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vnetClient = vnc
|
client.vnetClient = vnc
|
||||||
|
|
||||||
vnpc := network.NewVirtualNetworkPeeringsClientWithBaseURI(endpoint, c.SubscriptionID)
|
vnpc := network.NewVirtualNetworkPeeringsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&vnpc.Client)
|
setUserAgent(&vnpc.Client)
|
||||||
vnpc.Authorizer = spt
|
vnpc.Authorizer = auth
|
||||||
vnpc.Sender = autorest.CreateSender(withRequestLogging())
|
vnpc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.vnetPeeringsClient = vnpc
|
client.vnetPeeringsClient = vnpc
|
||||||
|
|
||||||
rtc := network.NewRouteTablesClientWithBaseURI(endpoint, c.SubscriptionID)
|
rtc := network.NewRouteTablesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&rtc.Client)
|
setUserAgent(&rtc.Client)
|
||||||
rtc.Authorizer = spt
|
rtc.Authorizer = auth
|
||||||
rtc.Sender = autorest.CreateSender(withRequestLogging())
|
rtc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.routeTablesClient = rtc
|
client.routeTablesClient = rtc
|
||||||
|
|
||||||
rc := network.NewRoutesClientWithBaseURI(endpoint, c.SubscriptionID)
|
rc := network.NewRoutesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&rc.Client)
|
setUserAgent(&rc.Client)
|
||||||
rc.Authorizer = spt
|
rc.Authorizer = auth
|
||||||
rc.Sender = autorest.CreateSender(withRequestLogging())
|
rc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.routesClient = rc
|
client.routesClient = rc
|
||||||
|
|
||||||
rgc := resources.NewGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
|
rgc := resources.NewGroupsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&rgc.Client)
|
setUserAgent(&rgc.Client)
|
||||||
rgc.Authorizer = spt
|
rgc.Authorizer = auth
|
||||||
rgc.Sender = autorest.CreateSender(withRequestLogging())
|
rgc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.resourceGroupClient = rgc
|
client.resourceGroupClient = rgc
|
||||||
|
|
||||||
pc := resources.NewProvidersClientWithBaseURI(endpoint, c.SubscriptionID)
|
pc := resources.NewProvidersClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&pc.Client)
|
setUserAgent(&pc.Client)
|
||||||
pc.Authorizer = spt
|
pc.Authorizer = auth
|
||||||
pc.Sender = autorest.CreateSender(withRequestLogging())
|
pc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.providers = pc
|
client.providers = pc
|
||||||
|
|
||||||
tc := resources.NewTagsClientWithBaseURI(endpoint, c.SubscriptionID)
|
tc := resources.NewTagsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&tc.Client)
|
setUserAgent(&tc.Client)
|
||||||
tc.Authorizer = spt
|
tc.Authorizer = auth
|
||||||
tc.Sender = autorest.CreateSender(withRequestLogging())
|
tc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.tagsClient = tc
|
client.tagsClient = tc
|
||||||
|
|
||||||
rf := resources.NewGroupClientWithBaseURI(endpoint, c.SubscriptionID)
|
rf := resources.NewGroupClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&rf.Client)
|
setUserAgent(&rf.Client)
|
||||||
rf.Authorizer = spt
|
rf.Authorizer = auth
|
||||||
rf.Sender = autorest.CreateSender(withRequestLogging())
|
rf.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.resourceFindClient = rf
|
client.resourceFindClient = rf
|
||||||
|
|
||||||
jc := scheduler.NewJobsClientWithBaseURI(endpoint, c.SubscriptionID)
|
jc := scheduler.NewJobsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&jc.Client)
|
setUserAgent(&jc.Client)
|
||||||
jc.Authorizer = spt
|
jc.Authorizer = auth
|
||||||
jc.Sender = autorest.CreateSender(withRequestLogging())
|
jc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.jobsClient = jc
|
client.jobsClient = jc
|
||||||
|
|
||||||
jcc := scheduler.NewJobCollectionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
jcc := scheduler.NewJobCollectionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&jcc.Client)
|
setUserAgent(&jcc.Client)
|
||||||
jcc.Authorizer = spt
|
jcc.Authorizer = auth
|
||||||
jcc.Sender = autorest.CreateSender(withRequestLogging())
|
jcc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.jobsCollectionsClient = jcc
|
client.jobsCollectionsClient = jcc
|
||||||
|
|
||||||
ssc := storage.NewAccountsClientWithBaseURI(endpoint, c.SubscriptionID)
|
ssc := storage.NewAccountsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&ssc.Client)
|
setUserAgent(&ssc.Client)
|
||||||
ssc.Authorizer = spt
|
ssc.Authorizer = auth
|
||||||
ssc.Sender = autorest.CreateSender(withRequestLogging())
|
ssc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.storageServiceClient = ssc
|
client.storageServiceClient = ssc
|
||||||
|
|
||||||
suc := storage.NewUsageClientWithBaseURI(endpoint, c.SubscriptionID)
|
suc := storage.NewUsageClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&suc.Client)
|
setUserAgent(&suc.Client)
|
||||||
suc.Authorizer = spt
|
suc.Authorizer = auth
|
||||||
suc.Sender = autorest.CreateSender(withRequestLogging())
|
suc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.storageUsageClient = suc
|
client.storageUsageClient = suc
|
||||||
|
|
||||||
cpc := cdn.NewProfilesClientWithBaseURI(endpoint, c.SubscriptionID)
|
cpc := cdn.NewProfilesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&cpc.Client)
|
setUserAgent(&cpc.Client)
|
||||||
cpc.Authorizer = spt
|
cpc.Authorizer = auth
|
||||||
cpc.Sender = autorest.CreateSender(withRequestLogging())
|
cpc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.cdnProfilesClient = cpc
|
client.cdnProfilesClient = cpc
|
||||||
|
|
||||||
cec := cdn.NewEndpointsClientWithBaseURI(endpoint, c.SubscriptionID)
|
cec := cdn.NewEndpointsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&cec.Client)
|
setUserAgent(&cec.Client)
|
||||||
cec.Authorizer = spt
|
cec.Authorizer = auth
|
||||||
cec.Sender = autorest.CreateSender(withRequestLogging())
|
cec.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.cdnEndpointsClient = cec
|
client.cdnEndpointsClient = cec
|
||||||
|
|
||||||
dc := resources.NewDeploymentsClientWithBaseURI(endpoint, c.SubscriptionID)
|
dc := resources.NewDeploymentsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&dc.Client)
|
setUserAgent(&dc.Client)
|
||||||
dc.Authorizer = spt
|
dc.Authorizer = auth
|
||||||
dc.Sender = autorest.CreateSender(withRequestLogging())
|
dc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.deploymentsClient = dc
|
client.deploymentsClient = dc
|
||||||
|
|
||||||
tmpc := trafficmanager.NewProfilesClientWithBaseURI(endpoint, c.SubscriptionID)
|
tmpc := trafficmanager.NewProfilesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&tmpc.Client)
|
setUserAgent(&tmpc.Client)
|
||||||
tmpc.Authorizer = spt
|
tmpc.Authorizer = auth
|
||||||
tmpc.Sender = autorest.CreateSender(withRequestLogging())
|
tmpc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.trafficManagerProfilesClient = tmpc
|
client.trafficManagerProfilesClient = tmpc
|
||||||
|
|
||||||
tmec := trafficmanager.NewEndpointsClientWithBaseURI(endpoint, c.SubscriptionID)
|
tmec := trafficmanager.NewEndpointsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&tmec.Client)
|
setUserAgent(&tmec.Client)
|
||||||
tmec.Authorizer = spt
|
tmec.Authorizer = auth
|
||||||
tmec.Sender = autorest.CreateSender(withRequestLogging())
|
tmec.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.trafficManagerEndpointsClient = tmec
|
client.trafficManagerEndpointsClient = tmec
|
||||||
|
|
||||||
rdc := redis.NewGroupClientWithBaseURI(endpoint, c.SubscriptionID)
|
rdc := redis.NewGroupClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&rdc.Client)
|
setUserAgent(&rdc.Client)
|
||||||
rdc.Authorizer = spt
|
rdc.Authorizer = auth
|
||||||
rdc.Sender = autorest.CreateSender(withRequestLogging())
|
rdc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.redisClient = rdc
|
client.redisClient = rdc
|
||||||
|
|
||||||
sbnc := servicebus.NewNamespacesClientWithBaseURI(endpoint, c.SubscriptionID)
|
sbnc := servicebus.NewNamespacesClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&sbnc.Client)
|
setUserAgent(&sbnc.Client)
|
||||||
sbnc.Authorizer = spt
|
sbnc.Authorizer = auth
|
||||||
sbnc.Sender = autorest.CreateSender(withRequestLogging())
|
sbnc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.serviceBusNamespacesClient = sbnc
|
client.serviceBusNamespacesClient = sbnc
|
||||||
|
|
||||||
sbtc := servicebus.NewTopicsClientWithBaseURI(endpoint, c.SubscriptionID)
|
sbtc := servicebus.NewTopicsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&sbtc.Client)
|
setUserAgent(&sbtc.Client)
|
||||||
sbtc.Authorizer = spt
|
sbtc.Authorizer = auth
|
||||||
sbtc.Sender = autorest.CreateSender(withRequestLogging())
|
sbtc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.serviceBusTopicsClient = sbtc
|
client.serviceBusTopicsClient = sbtc
|
||||||
|
|
||||||
sbsc := servicebus.NewSubscriptionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
sbsc := servicebus.NewSubscriptionsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&sbsc.Client)
|
setUserAgent(&sbsc.Client)
|
||||||
sbsc.Authorizer = spt
|
sbsc.Authorizer = auth
|
||||||
sbsc.Sender = autorest.CreateSender(withRequestLogging())
|
sbsc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.serviceBusSubscriptionsClient = sbsc
|
client.serviceBusSubscriptionsClient = sbsc
|
||||||
|
|
||||||
kvc := keyvault.NewVaultsClientWithBaseURI(endpoint, c.SubscriptionID)
|
kvc := keyvault.NewVaultsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&kvc.Client)
|
setUserAgent(&kvc.Client)
|
||||||
kvc.Authorizer = spt
|
kvc.Authorizer = auth
|
||||||
kvc.Sender = autorest.CreateSender(withRequestLogging())
|
kvc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.keyVaultClient = kvc
|
client.keyVaultClient = kvc
|
||||||
|
|
||||||
sqlepc := sql.NewElasticPoolsClientWithBaseURI(endpoint, c.SubscriptionID)
|
sqlepc := sql.NewElasticPoolsClientWithBaseURI(endpoint, c.SubscriptionID)
|
||||||
setUserAgent(&sqlepc.Client)
|
setUserAgent(&sqlepc.Client)
|
||||||
sqlepc.Authorizer = spt
|
sqlepc.Authorizer = auth
|
||||||
sqlepc.Sender = autorest.CreateSender(withRequestLogging())
|
sqlepc.Sender = autorest.CreateSender(withRequestLogging())
|
||||||
client.sqlElasticPoolsClient = sqlepc
|
client.sqlElasticPoolsClient = sqlepc
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/arm/storage"
|
"github.com/Azure/azure-sdk-for-go/arm/storage"
|
||||||
mainStorage "github.com/Azure/azure-sdk-for-go/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"
|
"github.com/Azure/go-autorest/autorest/azure"
|
||||||
riviera "github.com/jen20/riviera/azure"
|
riviera "github.com/jen20/riviera/azure"
|
||||||
)
|
)
|
||||||
|
@ -68,7 +70,7 @@ func getStorageAccountAccessKey(conf map[string]string, resourceGroupName, stora
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
oauthConfig, err := env.OAuthConfigForTenant(creds.TenantID)
|
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, creds.TenantID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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)
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
accountsClient := storage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, creds.SubscriptionID)
|
accountsClient := storage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, creds.SubscriptionID)
|
||||||
accountsClient.Authorizer = spt
|
accountsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
|
||||||
|
|
||||||
keys, err := accountsClient.ListKeys(resourceGroupName, storageAccountName)
|
keys, err := accountsClient.ListKeys(resourceGroupName, storageAccountName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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/
|
||||||
|
|
||||||
|
```
|
|
@ -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
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package azure
|
package adal
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is largely based on rjw57/oauth2device's code, with the follow differences:
|
This file is largely based on rjw57/oauth2device's code, with the follow differences:
|
||||||
|
@ -10,16 +10,17 @@ package azure
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/go-autorest/autorest"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
logPrefix = "autorest/azure/devicetoken:"
|
logPrefix = "autorest/adal/devicetoken:"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -38,10 +39,17 @@ var (
|
||||||
// ErrDeviceSlowDown represents the service telling us we're polling too often during device flow
|
// 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)
|
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"
|
errCodeSendingFails = "Error occurred while sending request for Device Authorization Code"
|
||||||
errCodeHandlingFails = "Error occurred while handling response from the Device Endpoint"
|
errCodeHandlingFails = "Error occurred while handling response from the Device Endpoint"
|
||||||
errTokenSendingFails = "Error occurred while sending request with device code for a token"
|
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)"
|
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
|
// 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
|
// InitiateDeviceAuth initiates a device auth flow. It returns a DeviceCode
|
||||||
// that can be used with CheckForUserCompletion or WaitForUserCompletion.
|
// that can be used with CheckForUserCompletion or WaitForUserCompletion.
|
||||||
func InitiateDeviceAuth(client *autorest.Client, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) {
|
func InitiateDeviceAuth(sender Sender, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) {
|
||||||
req, _ := autorest.Prepare(
|
v := url.Values{
|
||||||
&http.Request{},
|
"client_id": []string{clientID},
|
||||||
autorest.AsPost(),
|
"resource": []string{resource},
|
||||||
autorest.AsFormURLEncoded(),
|
}
|
||||||
autorest.WithBaseURL(oauthConfig.DeviceCodeEndpoint.String()),
|
|
||||||
autorest.WithFormData(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 {
|
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
|
var code DeviceCode
|
||||||
err = autorest.Respond(
|
err = json.Unmarshal(rb, &code)
|
||||||
resp,
|
|
||||||
autorest.WithErrorUnlessStatusCode(http.StatusOK),
|
|
||||||
autorest.ByUnmarshallingJSON(&code),
|
|
||||||
autorest.ByClosing())
|
|
||||||
if err != nil {
|
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
|
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
|
// 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
|
// to see if the device flow has: been completed, timed out, or otherwise failed
|
||||||
func CheckForUserCompletion(client *autorest.Client, code *DeviceCode) (*Token, error) {
|
func CheckForUserCompletion(sender Sender, code *DeviceCode) (*Token, error) {
|
||||||
req, _ := autorest.Prepare(
|
v := url.Values{
|
||||||
&http.Request{},
|
"client_id": []string{code.ClientID},
|
||||||
autorest.AsPost(),
|
"code": []string{*code.DeviceCode},
|
||||||
autorest.AsFormURLEncoded(),
|
"grant_type": []string{OAuthGrantTypeDeviceCode},
|
||||||
autorest.WithBaseURL(code.OAuthConfig.TokenEndpoint.String()),
|
"resource": []string{code.Resource},
|
||||||
autorest.WithFormData(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 {
|
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
|
var token deviceToken
|
||||||
err = autorest.Respond(
|
err = json.Unmarshal(rb, &token)
|
||||||
resp,
|
|
||||||
autorest.WithErrorUnlessStatusCode(http.StatusOK, http.StatusBadRequest),
|
|
||||||
autorest.ByUnmarshallingJSON(&token),
|
|
||||||
autorest.ByClosing())
|
|
||||||
if err != nil {
|
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 {
|
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.
|
// WaitForUserCompletion calls CheckForUserCompletion repeatedly until a token is granted or an error state occurs.
|
||||||
// This prevents the user from looping and checking against 'ErrDeviceAuthorizationPending'.
|
// 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
|
intervalDuration := time.Duration(*code.Interval) * time.Second
|
||||||
waitDuration := intervalDuration
|
waitDuration := intervalDuration
|
||||||
|
|
||||||
for {
|
for {
|
||||||
token, err := CheckForUserCompletion(client, code)
|
token, err := CheckForUserCompletion(sender, code)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return token, nil
|
return token, nil
|
|
@ -1,4 +1,4 @@
|
||||||
package azure
|
package adal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
|
@ -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
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package azure
|
package adal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
@ -6,13 +6,15 @@ import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/go-autorest/autorest"
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +30,9 @@ const (
|
||||||
|
|
||||||
// OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows
|
// OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows
|
||||||
OAuthGrantTypeRefreshToken = "refresh_token"
|
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
|
var expirationBase time.Time
|
||||||
|
@ -36,6 +41,18 @@ func init() {
|
||||||
expirationBase, _ = time.Parse(time.RFC3339, tokenBaseDate)
|
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
|
// TokenRefreshCallback is the type representing callbacks that will be called after
|
||||||
// a successful token refresh
|
// a successful token refresh
|
||||||
type TokenRefreshCallback func(Token) error
|
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))
|
return !t.Expires().After(time.Now().Add(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
//OAuthToken return the current access token
|
||||||
// value is "Bearer " followed by the AccessToken of the Token.
|
func (t *Token) OAuthToken() string {
|
||||||
func (t *Token) WithAuthorization() autorest.PrepareDecorator {
|
return t.AccessToken
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServicePrincipalNoSecret represents a secret type that contains no secret
|
// ServicePrincipalNoSecret represents a secret type that contains no secret
|
||||||
|
@ -118,6 +130,17 @@ type ServicePrincipalCertificateSecret struct {
|
||||||
PrivateKey *rsa.PrivateKey
|
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.
|
// SignJwt returns the JWT signed with the certificate's private key.
|
||||||
func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) {
|
func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) {
|
||||||
hasher := sha1.New()
|
hasher := sha1.New()
|
||||||
|
@ -173,7 +196,7 @@ type ServicePrincipalToken struct {
|
||||||
resource string
|
resource string
|
||||||
autoRefresh bool
|
autoRefresh bool
|
||||||
refreshWithin time.Duration
|
refreshWithin time.Duration
|
||||||
sender autorest.Sender
|
sender Sender
|
||||||
|
|
||||||
refreshCallbacks []TokenRefreshCallback
|
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
|
// 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 {
|
func (spt *ServicePrincipalToken) EnsureFresh() error {
|
||||||
if spt.WillExpireIn(spt.refreshWithin) {
|
if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) {
|
||||||
return spt.Refresh()
|
return spt.Refresh()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -253,8 +322,7 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
|
||||||
for _, callback := range spt.refreshCallbacks {
|
for _, callback := range spt.refreshCallbacks {
|
||||||
err := callback(spt.Token)
|
err := callback(spt.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return autorest.NewErrorWithError(err,
|
return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err)
|
||||||
"azure.ServicePrincipalToken", "InvokeRefreshCallbacks", nil, "A TokenRefreshCallback handler returned an error")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,39 +355,40 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req, _ := autorest.Prepare(&http.Request{},
|
s := v.Encode()
|
||||||
autorest.AsPost(),
|
body := ioutil.NopCloser(strings.NewReader(s))
|
||||||
autorest.AsFormURLEncoded(),
|
req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), body)
|
||||||
autorest.WithBaseURL(spt.oauthConfig.TokenEndpoint.String()),
|
|
||||||
autorest.WithFormData(v))
|
|
||||||
|
|
||||||
resp, err := autorest.SendWithSender(spt.sender, req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return autorest.NewErrorWithError(err,
|
return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err)
|
||||||
"azure.ServicePrincipalToken", "Refresh", resp, "Failure sending request for Service Principal %s",
|
|
||||||
spt.clientID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var newToken Token
|
req.ContentLength = int64(len(s))
|
||||||
err = autorest.Respond(resp,
|
req.Header.Set(contentType, mimeTypeFormPost)
|
||||||
autorest.WithErrorUnlessStatusCode(http.StatusOK),
|
resp, err := spt.sender.Do(req)
|
||||||
autorest.ByUnmarshallingJSON(&newToken),
|
|
||||||
autorest.ByClosing())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return autorest.NewErrorWithError(err,
|
return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err)
|
||||||
"azure.ServicePrincipalToken", "Refresh", resp, "Failure handling response to Service Principal %s request",
|
}
|
||||||
spt.clientID)
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
spt.Token = newToken
|
rb, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
err = spt.InvokeRefreshCallbacks(newToken)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// its already wrapped inside InvokeRefreshCallbacks
|
return fmt.Errorf("adal: Failed to read a new service principal token during refresh. Error = '%v'", err)
|
||||||
return 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.
|
// SetAutoRefresh enables or disables automatic refreshing of stale tokens.
|
||||||
|
@ -334,30 +403,6 @@ func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) {
|
||||||
return
|
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.
|
// undecorated http.Client is used by default.
|
||||||
func (spt *ServicePrincipalToken) SetSender(s autorest.Sender) {
|
func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s }
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,12 +17,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
methodDelete = "DELETE"
|
|
||||||
methodPatch = "PATCH"
|
|
||||||
methodPost = "POST"
|
|
||||||
methodPut = "PUT"
|
|
||||||
methodGet = "GET"
|
|
||||||
|
|
||||||
operationInProgress string = "InProgress"
|
operationInProgress string = "InProgress"
|
||||||
operationCanceled string = "Canceled"
|
operationCanceled string = "Canceled"
|
||||||
operationFailed string = "Failed"
|
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
|
// Lastly, requests against an existing resource, use the last request URI
|
||||||
if ps.uri == "" {
|
if ps.uri == "" {
|
||||||
m := strings.ToUpper(req.Method)
|
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()
|
ps.uri = req.URL.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -2,14 +2,9 @@ package azure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
activeDirectoryAPIVersion = "1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
var environments = map[string]Environment{
|
var environments = map[string]Environment{
|
||||||
"AZURECHINACLOUD": ChinaCloud,
|
"AZURECHINACLOUD": ChinaCloud,
|
||||||
"AZUREGERMANCLOUD": GermanCloud,
|
"AZUREGERMANCLOUD": GermanCloud,
|
||||||
|
@ -133,35 +128,3 @@ func EnvironmentFromName(name string) (Environment, error) {
|
||||||
}
|
}
|
||||||
return env, nil
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
package autorest
|
package autorest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
major = "7"
|
major = 8
|
||||||
minor = "3"
|
minor = 0
|
||||||
patch = "0"
|
patch = 0
|
||||||
tag = ""
|
tag = ""
|
||||||
semVerFormat = "%s.%s.%s%s"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var once sync.Once
|
||||||
var version string
|
var version string
|
||||||
|
|
||||||
// Version returns the semantic version (see http://semver.org).
|
// Version returns the semantic version (see http://semver.org).
|
||||||
func Version() string {
|
func Version() string {
|
||||||
if version == "" {
|
once.Do(func() {
|
||||||
version = fmt.Sprintf(semVerFormat, major, minor, patch, tag)
|
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
|
return version
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,48 +265,58 @@
|
||||||
"revisionTime": "2016-06-22T17:32:16Z"
|
"revisionTime": "2016-06-22T17:32:16Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "+sxS3YEvxf1VxlRskIdXFRWq9rY=",
|
"checksumSHA1": "NwbvjCz9Xo4spo0C96Tq6WCLX7U=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v8.0.0",
|
||||||
"path": "github.com/Azure/go-autorest/autorest",
|
"path": "github.com/Azure/go-autorest/autorest",
|
||||||
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
|
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
|
||||||
"revisionTime": "2017-02-15T19:58:14Z",
|
"revisionTime": "2017-04-28T17:52:31Z",
|
||||||
"version": "v7.3.1",
|
"version": "v8.0.0",
|
||||||
"versionExact": "v7.3.1"
|
"versionExact": "v8.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "ghrnc4vZv6q8zzeakZnrS8CGFhE=",
|
"checksumSHA1": "KOETWLsF6QW+lrPVPsMNHDZP+xA=",
|
||||||
"comment": "v7.0.5",
|
"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",
|
"path": "github.com/Azure/go-autorest/autorest/azure",
|
||||||
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
|
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
|
||||||
"revisionTime": "2017-02-15T19:58:14Z",
|
"revisionTime": "2017-04-28T17:52:31Z",
|
||||||
"version": "v7.3.1",
|
"version": "v8.0.0",
|
||||||
"versionExact": "v7.3.1"
|
"versionExact": "v8.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=",
|
"checksumSHA1": "LSF/pNrjhIxl6jiS6bKooBFCOxI=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v8.0.0",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/date",
|
"path": "github.com/Azure/go-autorest/autorest/date",
|
||||||
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
|
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
|
||||||
"revisionTime": "2017-02-15T19:58:14Z",
|
"revisionTime": "2017-04-28T17:52:31Z",
|
||||||
"version": "v7.3.1",
|
"version": "v8.0.0",
|
||||||
"versionExact": "v7.3.1"
|
"versionExact": "v8.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
|
"checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v8.0.0",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/to",
|
"path": "github.com/Azure/go-autorest/autorest/to",
|
||||||
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
|
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
|
||||||
"revisionTime": "2017-02-15T19:58:14Z",
|
"revisionTime": "2017-04-28T17:52:31Z",
|
||||||
"version": "v7.3.1",
|
"version": "v8.0.0",
|
||||||
"versionExact": "v7.3.1"
|
"versionExact": "v8.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
|
"checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
|
||||||
|
"comment": "v8.0.0",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/validation",
|
"path": "github.com/Azure/go-autorest/autorest/validation",
|
||||||
"revision": "ec5f4903f77ed9927ac95b19ab8e44ada64c1356",
|
"revision": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d",
|
||||||
"revisionTime": "2017-02-15T19:58:14Z",
|
"revisionTime": "2017-04-28T17:52:31Z",
|
||||||
"version": "v7.3.1",
|
"version": "v8.0.0",
|
||||||
"versionExact": "v7.3.1"
|
"versionExact": "v8.0.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "ICScouhAqYHoJEpJlJMYg7EzgyY=",
|
"checksumSHA1": "ICScouhAqYHoJEpJlJMYg7EzgyY=",
|
||||||
|
|
Loading…
Reference in New Issue