117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
package authentication
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
var (
|
|
authenticatedObjectCache = ""
|
|
)
|
|
|
|
// Builder supports all of the possible Authentication values and feature toggles
|
|
// required to build a working Config for Authentication purposes.
|
|
type Builder struct {
|
|
// Core
|
|
ClientID string
|
|
SubscriptionID string
|
|
TenantID string
|
|
Environment string
|
|
MetadataURL string
|
|
|
|
// Auxiliary tenant IDs used for multi tenant auth
|
|
SupportsAuxiliaryTenants bool
|
|
AuxiliaryTenantIDs []string
|
|
|
|
// The custom Resource Manager Endpoint which should be used
|
|
// only applicable for Azure Stack at this time.
|
|
CustomResourceManagerEndpoint string
|
|
|
|
// Azure CLI Tokens Auth
|
|
SupportsAzureCliToken bool
|
|
|
|
// Managed Service Identity Auth
|
|
SupportsManagedServiceIdentity bool
|
|
MsiEndpoint string
|
|
|
|
// Service Principal (Client Cert) Auth
|
|
SupportsClientCertAuth bool
|
|
ClientCertPath string
|
|
ClientCertPassword string
|
|
|
|
// Service Principal (Client Secret) Auth
|
|
SupportsClientSecretAuth bool
|
|
ClientSecret string
|
|
ClientSecretDocsLink string
|
|
}
|
|
|
|
// Build takes the configuration from the Builder and builds up a validated Config
|
|
// for authenticating with Azure
|
|
func (b Builder) Build() (*Config, error) {
|
|
config := Config{
|
|
ClientID: b.ClientID,
|
|
SubscriptionID: b.SubscriptionID,
|
|
TenantID: b.TenantID,
|
|
AuxiliaryTenantIDs: b.AuxiliaryTenantIDs,
|
|
Environment: b.Environment,
|
|
MetadataURL: b.MetadataURL,
|
|
CustomResourceManagerEndpoint: b.CustomResourceManagerEndpoint,
|
|
}
|
|
|
|
// NOTE: the ordering here is important
|
|
// since the Azure CLI Parsing should always be the last thing checked
|
|
supportedAuthenticationMethods := []authMethod{
|
|
servicePrincipalClientCertificateAuth{},
|
|
servicePrincipalClientSecretMultiTenantAuth{},
|
|
servicePrincipalClientSecretAuth{},
|
|
managedServiceIdentityAuth{},
|
|
azureCliTokenAuth{},
|
|
}
|
|
|
|
for _, method := range supportedAuthenticationMethods {
|
|
name := method.name()
|
|
log.Printf("Testing if %s is applicable for Authentication..", name)
|
|
|
|
// does not support it via validate?
|
|
if !method.isApplicable(b) {
|
|
continue
|
|
}
|
|
|
|
log.Printf("Using %s for Authentication", name)
|
|
auth, err := method.build(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// populate authentication specific fields on the Config
|
|
// (e.g. is service principal, fields parsed from the azure cli)
|
|
err = auth.populateConfig(&config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.authMethod = auth
|
|
|
|
// Authenticated Object ID Cache
|
|
if config.GetAuthenticatedObjectID != nil {
|
|
uncachedFunction := config.GetAuthenticatedObjectID
|
|
config.GetAuthenticatedObjectID = func(ctx context.Context) (string, error) {
|
|
if authenticatedObjectCache == "" {
|
|
authenticatedObjectCache, err = uncachedFunction(ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
log.Printf("authenticated object ID cache miss, populting with: %q", authenticatedObjectCache)
|
|
}
|
|
|
|
return authenticatedObjectCache, nil
|
|
}
|
|
}
|
|
|
|
return &config, config.authMethod.validate()
|
|
}
|
|
|
|
return nil, fmt.Errorf("No supported authentication methods were found!")
|
|
}
|