-
Notifications
You must be signed in to change notification settings - Fork 46
/
client_secret_authorizer.go
130 lines (105 loc) · 3.68 KB
/
client_secret_authorizer.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
123
124
125
126
127
128
129
130
package auth
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/hashicorp/go-azure-sdk/sdk/environments"
"golang.org/x/oauth2"
)
type ClientSecretAuthorizerOptions struct {
// Environment is the Azure environment/cloud being targeted
Environment environments.Environment
// Api describes the Azure API being used
Api environments.Api
// TenantId is the tenant to authenticate against
TenantId string
// AuxTenantIds lists additional tenants to authenticate against, currently only
// used for Resource Manager when auxiliary tenants are needed.
// e.g. https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/authenticate-multi-tenant
AuxTenantIds []string
// ClientId is the client ID used when authenticating
ClientId string
// ClientSecret is the client secret used when authenticating
ClientSecret string
}
// NewClientSecretAuthorizer returns an authorizer which uses client secret authentication.
func NewClientSecretAuthorizer(ctx context.Context, options ClientSecretAuthorizerOptions) (Authorizer, error) {
scope, err := environments.Scope(options.Api)
if err != nil {
return nil, fmt.Errorf("determining scope for %q: %+v", options.Api.Name(), err)
}
conf := clientCredentialsConfig{
Environment: options.Environment,
TenantID: options.TenantId,
AuxiliaryTenantIDs: options.AuxTenantIds,
ClientID: options.ClientId,
ClientSecret: options.ClientSecret,
Scopes: []string{
*scope,
},
}
return conf.TokenSource(ctx, clientCredentialsSecretType)
}
var _ Authorizer = &clientSecretAuthorizer{}
type clientSecretAuthorizer struct {
conf *clientCredentialsConfig
}
func (a *clientSecretAuthorizer) Token(ctx context.Context, _ *http.Request) (*oauth2.Token, error) {
if a.conf == nil {
return nil, fmt.Errorf("could not request token: conf is nil")
}
v := url.Values{
"client_id": {a.conf.ClientID},
"client_secret": {a.conf.ClientSecret},
"grant_type": {"client_credentials"},
// NOTE: at this time we only support v2 (MSAL) Tokens since v1 (ADAL) is EOL.
"scope": []string{
strings.Join(a.conf.Scopes, " "),
},
}
tokenUrl := a.conf.TokenURL
if tokenUrl == "" {
if a.conf.Environment.Authorization == nil {
return nil, fmt.Errorf("no `authorization` configuration was found for this environment")
}
tokenUrl = tokenEndpoint(*a.conf.Environment.Authorization, a.conf.TenantID)
}
return clientCredentialsToken(ctx, tokenUrl, &v)
}
// AuxiliaryTokens returns additional tokens for auxiliary tenant IDs, for use in multi-tenant scenarios
func (a *clientSecretAuthorizer) AuxiliaryTokens(ctx context.Context, _ *http.Request) ([]*oauth2.Token, error) {
if a.conf == nil {
return nil, fmt.Errorf("could not request token: conf is nil")
}
tokens := make([]*oauth2.Token, 0)
if len(a.conf.AuxiliaryTenantIDs) == 0 {
return tokens, nil
}
for _, tenantId := range a.conf.AuxiliaryTenantIDs {
v := url.Values{
"client_id": {a.conf.ClientID},
"client_secret": {a.conf.ClientSecret},
"grant_type": {"client_credentials"},
// NOTE: at this time we only support v2 (MSAL) Tokens since v1 (ADAL) is EOL.
"scope": []string{
// TODO: given the Request, could we use a dynamic scope?
strings.Join(a.conf.Scopes, " "),
},
}
tokenUrl := a.conf.TokenURL
if tokenUrl == "" {
if a.conf.Environment.Authorization == nil {
return nil, fmt.Errorf("no `authorization` configuration was found for this environment")
}
tokenUrl = tokenEndpoint(*a.conf.Environment.Authorization, tenantId)
}
token, err := clientCredentialsToken(ctx, tokenUrl, &v)
if err != nil {
return tokens, err
}
tokens = append(tokens, token)
}
return tokens, nil
}