-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathcredentials.go
356 lines (288 loc) · 11.1 KB
/
credentials.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
package edge_apis
import (
"crypto"
"crypto/tls"
"crypto/x509"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"github.com/openziti/edge-api/rest_model"
"github.com/openziti/identity"
"github.com/openziti/sdk-golang/ziti/edge/network"
"github.com/openziti/sdk-golang/ziti/sdkinfo"
"net/http"
)
// Credentials represents the minimal information needed across all authentication mechanisms to authenticate an identity
// to an OpenZiti network.
type Credentials interface {
// Payload constructs the objects that represent the JSON authentication payload for this set of credentials.
Payload() *rest_model.Authenticate
// TlsCerts returns zero or more tls.Certificates used for client authentication.
TlsCerts() []tls.Certificate
// GetCaPool returns the CA pool that this credential was configured to trust.
GetCaPool() *x509.CertPool
// Method returns the authentication necessary to complete an authentication request.
Method() string
// AddAuthHeader adds a header for all authentication requests.
AddAuthHeader(key, value string)
// AddRequestHeader adds a header for all requests after authentication
AddRequestHeader(key, value string)
// AddJWT adds additional JWTs to the credentials. Used to satisfy secondary authentication/MFA requirements. The
// provided token should be the base64 encoded version of the token.
AddJWT(string)
// ClientAuthInfoWriter is used to pass a Credentials instance to the openapi runtime to authenticate outgoing
//requests.
runtime.ClientAuthInfoWriter
// GetRequestHeaders returns a set of headers to use after authentication during normal HTTP operations
GetRequestHeaders() http.Header
}
// IdentityProvider is a sentinel interface used to determine whether the backing Credentials instance can provide
// an Identity that can provide a certificate and private key used to initiate mTLS connections.
type IdentityProvider interface {
GetIdentity() identity.Identity
}
// toTlsCerts converts an array of certificates into a single tls.Certificate. Index zero is assumed to be the leaf
// certificate and all subsequent certificates to be the support certificate chain that should be sent to servers.
// At least one certificate must be provided.
func toTlsCerts(certs []*x509.Certificate, key crypto.PrivateKey) tls.Certificate {
tlsCert := tls.Certificate{
PrivateKey: key,
Leaf: certs[0],
}
for _, cert := range certs {
tlsCert.Certificate = append(tlsCert.Certificate, cert.Raw)
}
return tlsCert
}
// getClientAuthInfoOp returns a one-off runtime.ClientOperation used to authenticate single requests without altering
// the authentication operation of the entire client runtime.
func getClientAuthInfoOp(credentials Credentials, client *http.Client) func(*runtime.ClientOperation) {
return func(operation *runtime.ClientOperation) {
operation.AuthInfo = credentials
certs := credentials.TlsCerts()
if len(certs) != 0 {
operation.Client = client
if transport, ok := operation.Client.Transport.(*http.Transport); ok {
transport.TLSClientConfig.Certificates = certs
}
}
}
}
// BaseCredentials is a shared struct of information all Credentials implementations require.
type BaseCredentials struct {
// ConfigTypes is used to set the configuration types for services during authentication
ConfigTypes []string
// AuthHeaders is a map of strings to string arrays of headers to send with auth requests.
AuthHeaders http.Header
// RequestHeaders is a map of string to string arrays of headers to send on non-authentication requests.
RequestHeaders http.Header
// EnvInfo is provided during authentication to set environmental information about the client.
EnvInfo *rest_model.EnvInfo
// SdkInfo is provided during authentication to set SDK information about the client.
SdkInfo *rest_model.SdkInfo
// CaPool will override the client's default certificate pool if set to a non-nil value.
CaPool *x509.CertPool
}
// Payload will produce the object used to construct the body of an authentication requests. The base version
// sets shared information available in BaseCredentials.
func (c *BaseCredentials) Payload() *rest_model.Authenticate {
envInfo, sdkInfo := sdkinfo.GetSdkInfo()
if c.EnvInfo != nil {
envInfo = c.EnvInfo
}
if c.SdkInfo != nil {
sdkInfo = c.SdkInfo
}
return &rest_model.Authenticate{
ConfigTypes: c.ConfigTypes,
EnvInfo: envInfo,
SdkInfo: sdkInfo,
}
}
// GetCaPool provides a base implementation to return the certificate pool of a Credentials instance.
func (c *BaseCredentials) GetCaPool() *x509.CertPool {
return c.CaPool
}
// AddAuthHeader provides a base implementation to add a header to authentication requests.
func (c *BaseCredentials) AddAuthHeader(key, value string) {
if c.AuthHeaders == nil {
c.AuthHeaders = http.Header{}
}
c.AuthHeaders.Add(key, value)
}
// AddRequestHeader provides a base implementation to add a header to all requests after authentication.
func (c *BaseCredentials) AddRequestHeader(key, value string) {
if c.RequestHeaders == nil {
c.RequestHeaders = http.Header{}
}
c.RequestHeaders.Add(key, value)
}
// AddJWT adds additional JWTs to the credentials. Used to satisfy secondary authentication/MFA requirements. The
// provided token should be the base64 encoded version of the token. Convenience function for AddHeader.
func (c *BaseCredentials) AddJWT(token string) {
c.AddAuthHeader("Authorization", "Bearer "+token)
c.AddRequestHeader("Authorization", "Bearer "+token)
}
// AuthenticateRequest provides a base implementation to authenticate an outgoing request. This is provided here
// for authentication methods such as `cert` which do not have to provide any more request level information.
func (c *BaseCredentials) AuthenticateRequest(request runtime.ClientRequest, _ strfmt.Registry) error {
var errors []error
for hName, hVals := range c.AuthHeaders {
for _, hVal := range hVals {
err := request.SetHeaderParam(hName, hVal)
if err != nil {
errors = append(errors, err)
}
}
}
if len(errors) > 0 {
return network.MultipleErrors(errors)
}
return nil
}
// ProcessRequest proves a base implemmentation mutate runtime.ClientRequests as they are sent out after
// authentication. Useful for adding headers.
func (c *BaseCredentials) ProcessRequest(request runtime.ClientRequest, _ strfmt.Registry) error {
var errors []error
for hName, hVals := range c.RequestHeaders {
for _, hVal := range hVals {
err := request.SetHeaderParam(hName, hVal)
if err != nil {
errors = append(errors, err)
}
}
}
if len(errors) > 0 {
return network.MultipleErrors(errors)
}
return nil
}
// GetRequestHeaders returns headers that should be sent on requests post authentication.
func (c *BaseCredentials) GetRequestHeaders() http.Header {
return c.RequestHeaders
}
// TlsCerts provides a base implementation of returning the tls.Certificate array that will be used to setup
// mTLS connections. This is provided here for authentication methods that do not initially require mTLS (e.g. JWTs).
func (c *BaseCredentials) TlsCerts() []tls.Certificate {
return nil
}
var _ Credentials = &CertCredentials{}
// CertCredentials represents authentication using certificates that are not from an Identity configuration file.
type CertCredentials struct {
BaseCredentials
Certs []*x509.Certificate
Key crypto.PrivateKey
}
// NewCertCredentials creates Credentials instance based upon an array of certificates. At least one certificate must
// be provided and the certificate at index zero is assumed to be the leaf client certificate that pairs with the
// provided private key. All other certificates are assumed to support the leaf client certificate as a chain.
func NewCertCredentials(certs []*x509.Certificate, key crypto.PrivateKey) *CertCredentials {
return &CertCredentials{
BaseCredentials: BaseCredentials{},
Certs: certs,
Key: key,
}
}
func (c *CertCredentials) Method() string {
return "cert"
}
func (c *CertCredentials) TlsCerts() []tls.Certificate {
return []tls.Certificate{toTlsCerts(c.Certs, c.Key)}
}
func (c *CertCredentials) GetIdentity() identity.Identity {
return identity.NewClientTokenIdentityWithPool(c.Certs, c.Key, c.GetCaPool())
}
var _ Credentials = &IdentityCredentials{}
type IdentityCredentials struct {
BaseCredentials
Identity identity.Identity
}
// NewIdentityCredentials creates a Credentials instance based upon and Identity.
func NewIdentityCredentials(identity identity.Identity) *IdentityCredentials {
return &IdentityCredentials{
BaseCredentials: BaseCredentials{},
Identity: identity,
}
}
// NewIdentityCredentialsFromConfig creates a Credentials instance based upon and Identity configuration.
func NewIdentityCredentialsFromConfig(config identity.Config) *IdentityCredentials {
return &IdentityCredentials{
BaseCredentials: BaseCredentials{},
Identity: &identity.LazyIdentity{Config: &config},
}
}
func (c *IdentityCredentials) GetIdentity() identity.Identity {
return c.Identity
}
func (c *IdentityCredentials) Method() string {
return "cert"
}
func (c *IdentityCredentials) GetCaPool() *x509.CertPool {
return c.Identity.CA()
}
func (c *IdentityCredentials) TlsCerts() []tls.Certificate {
tlsCert := c.Identity.Cert()
if tlsCert != nil {
return []tls.Certificate{*tlsCert}
}
return nil
}
func (c *IdentityCredentials) AuthenticateRequest(request runtime.ClientRequest, reg strfmt.Registry) error {
return c.BaseCredentials.AuthenticateRequest(request, reg)
}
var _ Credentials = &JwtCredentials{}
type JwtCredentials struct {
BaseCredentials
JWT string
SendOnEveryRequest bool
}
// NewJwtCredentials creates a Credentials instance based on a JWT obtained from an outside system.
func NewJwtCredentials(jwt string) *JwtCredentials {
return &JwtCredentials{
BaseCredentials: BaseCredentials{},
JWT: jwt,
}
}
func (c *JwtCredentials) Method() string {
return "ext-jwt"
}
func (c *JwtCredentials) AuthenticateRequest(request runtime.ClientRequest, reg strfmt.Registry) error {
var errors []error
err := c.BaseCredentials.AuthenticateRequest(request, reg)
if err != nil {
errors = append(errors, err)
}
err = request.SetHeaderParam("Authorization", "Bearer "+c.JWT)
if err != nil {
errors = append(errors, err)
}
if len(errors) > 0 {
return network.MultipleErrors(errors)
}
return nil
}
var _ Credentials = &UpdbCredentials{}
type UpdbCredentials struct {
BaseCredentials
Username string
Password string
}
func (c *UpdbCredentials) Method() string {
return "password"
}
// NewUpdbCredentials creates a Credentials instance based on a username/passwords combination.
func NewUpdbCredentials(username string, password string) *UpdbCredentials {
return &UpdbCredentials{
BaseCredentials: BaseCredentials{},
Username: username,
Password: password,
}
}
func (c *UpdbCredentials) Payload() *rest_model.Authenticate {
payload := c.BaseCredentials.Payload()
payload.Username = rest_model.Username(c.Username)
payload.Password = rest_model.Password(c.Password)
return payload
}
func (c *UpdbCredentials) AuthenticateRequest(request runtime.ClientRequest, reg strfmt.Registry) error {
return c.BaseCredentials.AuthenticateRequest(request, reg)
}