/
environment_credential.go
122 lines (112 loc) · 4.55 KB
/
environment_credential.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//go:build go1.18
// +build go1.18
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package azidentity
import (
"context"
"errors"
"fmt"
"os"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
)
const envVarSendCertChain = "AZURE_CLIENT_SEND_CERTIFICATE_CHAIN"
// EnvironmentCredentialOptions contains optional parameters for EnvironmentCredential
type EnvironmentCredentialOptions struct {
azcore.ClientOptions
}
// EnvironmentCredential authenticates a service principal with a secret or certificate, or a user with a password, depending
// on environment variable configuration. It reads configuration from these variables, in the following order:
//
// Service principal with client secret
//
// AZURE_TENANT_ID: ID of the service principal's tenant. Also called its "directory" ID.
//
// AZURE_CLIENT_ID: the service principal's client ID
//
// AZURE_CLIENT_SECRET: one of the service principal's client secrets
//
// Service principal with certificate
//
// AZURE_TENANT_ID: ID of the service principal's tenant. Also called its "directory" ID.
//
// AZURE_CLIENT_ID: the service principal's client ID
//
// AZURE_CLIENT_CERTIFICATE_PATH: path to a PEM or PKCS12 certificate file including the unencrypted private key.
//
// User with username and password
//
// AZURE_TENANT_ID: (optional) tenant to authenticate in. Defaults to "organizations".
//
// AZURE_CLIENT_ID: client ID of the application the user will authenticate to
//
// AZURE_USERNAME: a username (usually an email address)
//
// AZURE_PASSWORD: the user's password
type EnvironmentCredential struct {
cred azcore.TokenCredential
}
// NewEnvironmentCredential creates an EnvironmentCredential. Pass nil to accept default options.
func NewEnvironmentCredential(options *EnvironmentCredentialOptions) (*EnvironmentCredential, error) {
if options == nil {
options = &EnvironmentCredentialOptions{}
}
tenantID := os.Getenv("AZURE_TENANT_ID")
if tenantID == "" {
return nil, errors.New("missing environment variable AZURE_TENANT_ID")
}
clientID := os.Getenv(azureClientID)
if clientID == "" {
return nil, errors.New("missing environment variable " + azureClientID)
}
if clientSecret := os.Getenv("AZURE_CLIENT_SECRET"); clientSecret != "" {
log.Write(EventAuthentication, "EnvironmentCredential will authenticate with ClientSecretCredential")
o := &ClientSecretCredentialOptions{ClientOptions: options.ClientOptions}
cred, err := NewClientSecretCredential(tenantID, clientID, clientSecret, o)
if err != nil {
return nil, err
}
return &EnvironmentCredential{cred: cred}, nil
}
if certPath := os.Getenv("AZURE_CLIENT_CERTIFICATE_PATH"); certPath != "" {
log.Write(EventAuthentication, "EnvironmentCredential will authenticate with ClientCertificateCredential")
certData, err := os.ReadFile(certPath)
if err != nil {
return nil, fmt.Errorf(`failed to read certificate file "%s": %v`, certPath, err)
}
certs, key, err := ParseCertificates(certData, nil)
if err != nil {
return nil, fmt.Errorf(`failed to load certificate from "%s": %v`, certPath, err)
}
o := &ClientCertificateCredentialOptions{ClientOptions: options.ClientOptions}
if v, ok := os.LookupEnv(envVarSendCertChain); ok {
o.SendCertificateChain = v == "1" || strings.ToLower(v) == "true"
}
cred, err := NewClientCertificateCredential(tenantID, clientID, certs, key, o)
if err != nil {
return nil, err
}
return &EnvironmentCredential{cred: cred}, nil
}
if username := os.Getenv("AZURE_USERNAME"); username != "" {
if password := os.Getenv("AZURE_PASSWORD"); password != "" {
log.Write(EventAuthentication, "EnvironmentCredential will authenticate with UsernamePasswordCredential")
o := &UsernamePasswordCredentialOptions{ClientOptions: options.ClientOptions}
cred, err := NewUsernamePasswordCredential(tenantID, clientID, username, password, o)
if err != nil {
return nil, err
}
return &EnvironmentCredential{cred: cred}, nil
}
return nil, errors.New("no value for AZURE_PASSWORD")
}
return nil, errors.New("incomplete environment variable configuration. Only AZURE_TENANT_ID and AZURE_CLIENT_ID are set")
}
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
func (c *EnvironmentCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
return c.cred.GetToken(ctx, opts)
}
var _ azcore.TokenCredential = (*EnvironmentCredential)(nil)