-
Notifications
You must be signed in to change notification settings - Fork 8
/
token_flow.go
147 lines (130 loc) · 3.78 KB
/
token_flow.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package clients
import (
"context"
"errors"
"net/http"
"os"
"github.com/SchwarzIT/community-stackit-go-client/pkg/env"
"github.com/SchwarzIT/community-stackit-go-client/pkg/helpers/traceparent"
"golang.org/x/oauth2"
)
const (
// Service Account Token Flow
// Auth flow env variables
ServiceAccountEmail = "STACKIT_SERVICE_ACCOUNT_EMAIL"
ServiceAccountToken = "STACKIT_SERVICE_ACCOUNT_TOKEN"
)
// TokenFlow handles auth with SA static token
type TokenFlow struct {
client *http.Client
config *TokenFlowConfig
}
// TokenFlowConfig is the flow config
type TokenFlowConfig struct {
ServiceAccountEmail string
ServiceAccountToken string
Environment env.Environment
ClientRetry *RetryConfig
Traceparent *traceparent.Traceparent
}
// GetEnvironment returns the defined API environment
func (c *TokenFlow) GetEnvironment() env.Environment {
return c.GetConfig().Environment
}
// GetServiceAccountEmail returns the service account email
func (c *TokenFlow) GetServiceAccountEmail() string {
return c.GetConfig().ServiceAccountEmail
}
// GetConfig returns the flow configuration
func (c *TokenFlow) GetConfig() TokenFlowConfig {
if c.config == nil {
return TokenFlowConfig{}
}
return *c.config
}
func (c *TokenFlow) Init(ctx context.Context, cfg ...TokenFlowConfig) error {
c.processConfig(cfg...)
c.configureHTTPClient(ctx)
if c.config.ClientRetry == nil {
c.config.ClientRetry = NewRetryConfig()
}
return c.validate()
}
// Clone creates a clone of the client
func (c *TokenFlow) Clone() interface{} {
sc := *c
nc := &sc
cl := *nc.client
cf := *nc.config
nc.client = &cl
nc.config = &cf
return c
}
// processConfig processes the given configuration
func (c *TokenFlow) processConfig(cfg ...TokenFlowConfig) {
c.config = c.getConfigFromEnvironment()
for _, m := range cfg {
c.config = c.mergeConfigs(&m, c.config)
}
}
// getConfigFromEnvironment returns a TokenFlowConfig populated with environment variables.
func (c *TokenFlow) getConfigFromEnvironment() *TokenFlowConfig {
return &TokenFlowConfig{
ServiceAccountEmail: os.Getenv(ServiceAccountEmail),
ServiceAccountToken: os.Getenv(ServiceAccountToken),
Environment: env.Parse(os.Getenv(Environment)),
}
}
// mergeConfigs returns a new TokenFlowConfig that combines the values of cfg and currentCfg.
func (c *TokenFlow) mergeConfigs(cfg, currentCfg *TokenFlowConfig) *TokenFlowConfig {
merged := *currentCfg
if cfg.ServiceAccountEmail != "" {
merged.ServiceAccountEmail = cfg.ServiceAccountEmail
}
if cfg.ServiceAccountToken != "" {
merged.ServiceAccountToken = cfg.ServiceAccountToken
}
if cfg.Environment != "" {
merged.Environment = cfg.Environment
}
if cfg.Traceparent != nil {
merged.Traceparent = cfg.Traceparent
}
return &merged
}
// configureHTTPClient configures the HTTP client
func (c *TokenFlow) configureHTTPClient(ctx context.Context) {
sts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: c.config.ServiceAccountToken},
)
o2nc := oauth2.NewClient(ctx, sts)
o2nc.Timeout = DefaultClientTimeout
c.client = o2nc
}
// validate the client is configured well
func (c *TokenFlow) validate() error {
if c.config.ServiceAccountToken == "" {
return errors.New("Service Account Access Token cannot be empty")
}
if c.config.ServiceAccountEmail == "" {
return errors.New("Service Account Email cannot be empty")
}
return nil
}
// Do performs the request
func (c *TokenFlow) Do(req *http.Request) (*http.Response, error) {
if c.client == nil {
return nil, errors.New("please run Init()")
}
if t := c.GetTraceparent(); t != nil {
t.SetHeader(req)
}
return do(c.client, req, c.config.ClientRetry)
}
// GetTraceparent returns the defined Traceparent
func (c *TokenFlow) GetTraceparent() *traceparent.Traceparent {
if c.config == nil {
return nil
}
return c.config.Traceparent
}