Skip to content

Commit 38d051b

Browse files
adds router posture responses (ha support) (#816)
* adds router posture responses (ha support) - adds ability to submit posture to controller or router based on router capabilities - adds new ToTP MFA JWT token type for MFA posture checks post-login - simply and remove caches - streamline posture processing - adds doc to new funcs, types, etc.
1 parent 1bdbcd3 commit 38d051b

35 files changed

+2514
-583
lines changed

edge-apis/authwrapper.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import (
66
"context"
77
"encoding/json"
88
"fmt"
9+
"net/http"
10+
"net/url"
11+
"sync"
12+
"time"
13+
914
"github.com/go-openapi/runtime"
1015
"github.com/go-openapi/strfmt"
1116
"github.com/go-resty/resty/v2"
@@ -28,10 +33,6 @@ import (
2833
"github.com/zitadel/oidc/v3/pkg/client/tokenexchange"
2934
"github.com/zitadel/oidc/v3/pkg/oidc"
3035
"golang.org/x/oauth2"
31-
"net/http"
32-
"net/url"
33-
"sync"
34-
"time"
3536
)
3637

3738
const (
@@ -81,8 +82,25 @@ type ApiSession interface {
8182
RequiresRouterTokenUpdate() bool
8283

8384
GetRequestHeaders() http.Header
85+
86+
// GetType returns the authentication method used to establish this session, enabling
87+
// callers to determine whether legacy or OIDC-based authentication is in use.
88+
GetType() ApiSessionType
8489
}
8590

91+
// ApiSessionType identifies the authentication mechanism used to establish an API session.
92+
type ApiSessionType string
93+
94+
const (
95+
// ApiSessionTypeLegacy indicates a session created using the original Ziti authentication
96+
// with session tokens passed in the zt-session header.
97+
ApiSessionTypeLegacy ApiSessionType = "legacy"
98+
99+
// ApiSessionTypeOidc indicates a session created using OpenID Connect authentication
100+
// with JWT bearer tokens.
101+
ApiSessionTypeOidc ApiSessionType = "oidc"
102+
)
103+
86104
var _ ApiSession = (*ApiSessionLegacy)(nil)
87105
var _ ApiSession = (*ApiSessionOidc)(nil)
88106

@@ -93,6 +111,10 @@ type ApiSessionLegacy struct {
93111
RequestHeaders http.Header
94112
}
95113

114+
func (a *ApiSessionLegacy) GetType() ApiSessionType {
115+
return ApiSessionTypeLegacy
116+
}
117+
96118
func (a *ApiSessionLegacy) GetRequestHeaders() http.Header {
97119
return a.RequestHeaders
98120
}
@@ -170,6 +192,10 @@ type ApiSessionOidc struct {
170192
RequestHeaders http.Header
171193
}
172194

195+
func (a *ApiSessionOidc) GetType() ApiSessionType {
196+
return ApiSessionTypeOidc
197+
}
198+
173199
func (a *ApiSessionOidc) GetRequestHeaders() http.Header {
174200
return a.RequestHeaders
175201
}

edge-apis/clients.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,13 @@ type BaseClient[A ApiType] struct {
6464
onControllerListeners []func([]*url.URL)
6565
}
6666

67+
// Url returns the URL of the currently active controller endpoint.
6768
func (self *BaseClient[A]) Url() url.URL {
6869
return *self.AuthEnabledApi.GetClientTransportPool().GetActiveTransport().ApiUrl
6970
}
7071

72+
// AddOnControllerUpdateListeners registers a callback that is invoked when the list of
73+
// available controller endpoints changes.
7174
func (self *BaseClient[A]) AddOnControllerUpdateListeners(listener func([]*url.URL)) {
7275
self.onControllerListeners = append(self.onControllerListeners, listener)
7376
}
@@ -82,12 +85,15 @@ func (self *BaseClient[A]) GetCurrentApiSession() ApiSession {
8285
return *ptr
8386
}
8487

88+
// SetUseOidc forces the API client to operate in OIDC mode when true, or legacy mode when false.
8589
func (self *BaseClient[A]) SetUseOidc(use bool) {
8690
v := any(self.API)
8791
apiType := v.(OidcEnabledApi)
8892
apiType.SetUseOidc(use)
8993
}
9094

95+
// SetAllowOidcDynamicallyEnabled configures whether the client checks the controller for
96+
// OIDC support and switches modes accordingly.
9197
func (self *BaseClient[A]) SetAllowOidcDynamicallyEnabled(allow bool) {
9298
v := any(self.API)
9399
apiType := v.(OidcEnabledApi)
@@ -134,6 +140,7 @@ func (self *BaseClient[A]) initializeComponents(config *ApiClientConfig) {
134140
self.Components = *components
135141
}
136142

143+
// NewRuntime creates an OpenAPI runtime configured for the specified API endpoint.
137144
func NewRuntime(apiUrl *url.URL, schemes []string, httpClient *http.Client) *openapiclient.Runtime {
138145
return openapiclient.NewWithClient(apiUrl.Host, apiUrl.Path, schemes, httpClient)
139146
}
@@ -170,6 +177,8 @@ func (self *BaseClient[A]) AuthenticateRequest(request runtime.ClientRequest, re
170177
return nil
171178
}
172179

180+
// ProcessControllers queries the authenticated controller for its list of peer controllers
181+
// and registers them for high-availability failover.
173182
func (self *BaseClient[A]) ProcessControllers(authEnabledApi AuthEnabledApi) {
174183
list, err := authEnabledApi.ListControllers()
175184

@@ -208,6 +217,7 @@ type ManagementApiClient struct {
208217
BaseClient[ZitiEdgeManagement]
209218
}
210219

220+
// ApiClientConfig contains configuration options for creating API clients.
211221
type ApiClientConfig struct {
212222
ApiUrls []*url.URL
213223
CaPool *x509.CertPool
@@ -235,6 +245,7 @@ func NewManagementApiClient(apiUrls []*url.URL, caPool *x509.CertPool, totpCallb
235245
})
236246
}
237247

248+
// NewManagementApiClientWithConfig creates a Management API client using the provided configuration.
238249
func NewManagementApiClientWithConfig(config *ApiClientConfig) *ManagementApiClient {
239250
ret := &ManagementApiClient{}
240251
ret.Schemes = rest_management_api_client.DefaultSchemes
@@ -264,6 +275,7 @@ func NewManagementApiClientWithConfig(config *ApiClientConfig) *ManagementApiCli
264275
return ret
265276
}
266277

278+
// ClientApiClient provides access to the Ziti Edge Client API for identity operations.
267279
type ClientApiClient struct {
268280
BaseClient[ZitiEdgeClient]
269281
}
@@ -288,6 +300,7 @@ func NewClientApiClient(apiUrls []*url.URL, caPool *x509.CertPool, totpCallback
288300
})
289301
}
290302

303+
// NewClientApiClientWithConfig creates a Client API client using the provided configuration.
291304
func NewClientApiClientWithConfig(config *ApiClientConfig) *ClientApiClient {
292305
ret := &ClientApiClient{}
293306
ret.ApiBinding = "edge-client"

edge-apis/component.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import (
99
"time"
1010
)
1111

12-
// Components provides the basic shared lower level pieces used to assemble go-swagger/openapi clients. These
13-
// components are interconnected and have references to each other. This struct is used to set, move, and manage
14-
// them as a set.
12+
// Components provides the foundational HTTP client infrastructure for OpenAPI clients,
13+
// bundling the HTTP client, transport, and certificate pool as a cohesive unit.
1514
type Components struct {
1615
HttpClient *http.Client
1716
HttpTransport *http.Transport
1817
CaPool *x509.CertPool
1918
}
2019

20+
// ComponentsConfig contains configuration options for creating Components.
2121
type ComponentsConfig struct {
2222
Proxy func(*http.Request) (*url.URL, error)
2323
}
@@ -29,7 +29,7 @@ func NewComponents() *Components {
2929
})
3030
}
3131

32-
// NewComponentsWithConfig assembles a new set of components with reasonable production defaults.
32+
// NewComponentsWithConfig assembles a new set of components using the provided configuration.
3333
func NewComponentsWithConfig(cfg *ComponentsConfig) *Components {
3434
tlsClientConfig, _ := rest_util.NewTlsConfig()
3535

edge-apis/oidc.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@ import (
1717
"time"
1818
)
1919

20+
// JwtTokenPrefix is the standard prefix for JWT tokens, representing the first two characters
21+
// of a Base64URL-encoded JWT header. This prefix is used to identify JWT-format tokens.
2022
const JwtTokenPrefix = "ey"
2123

24+
// ServiceAccessClaims represents the JWT claims for service-level access tokens, including
25+
// identity and session binding information specific to a service connection.
2226
type ServiceAccessClaims struct {
2327
jwt.RegisteredClaims
2428
ApiSessionId string `json:"z_asid"`
@@ -27,6 +31,8 @@ type ServiceAccessClaims struct {
2731
Type string `json:"z_st"`
2832
}
2933

34+
// ApiAccessClaims represents the JWT claims for API session access tokens, including
35+
// identity attributes, administrative status, and configuration bindings.
3036
type ApiAccessClaims struct {
3137
jwt.RegisteredClaims
3238
ApiSessionId string `json:"z_asid,omitempty"`
@@ -71,6 +77,8 @@ func (r *IdClaims) GetAudience() (jwt.ClaimStrings, error) {
7177
return jwt.ClaimStrings(r.Audience), nil
7278
}
7379

80+
// localRpServer manages a local HTTP server for OpenID Connect relying party operations,
81+
// handling OAuth callbacks and token exchanges during authentication flows.
7482
type localRpServer struct {
7583
Server *http.Server
7684
Port string
@@ -81,11 +89,13 @@ type localRpServer struct {
8189
LoginUri string
8290
}
8391

92+
// Stop shuts down the local server and closes the token channel.
8493
func (t *localRpServer) Stop() {
8594
_ = t.Server.Shutdown(context.Background())
8695
close(t.TokenChan)
8796
}
8897

98+
// Start launches the local server and waits for it to become available.
8999
func (t *localRpServer) Start() {
90100
go func() {
91101
_ = t.Server.Serve(t.Listener)
@@ -118,6 +128,8 @@ func (t *localRpServer) Start() {
118128
}
119129
}
120130

131+
// newLocalRpServer creates and configures a local HTTP server for handling OpenID Connect
132+
// authentication flows, including callback processing and token exchange.
121133
func newLocalRpServer(apiHost string, authMethod string) (*localRpServer, error) {
122134
tokenOutChan := make(chan *oidc.Tokens[*oidc.IDTokenClaims], 1)
123135
result := &localRpServer{

edge-apis/pool.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,53 @@ import (
3030
errors "github.com/pkg/errors"
3131
)
3232

33+
// ApiClientTransport wraps a runtime.ClientTransport with its associated API URL,
34+
// enabling tracking of which controller endpoint a transport communicates with.
3335
type ApiClientTransport struct {
3436
runtime.ClientTransport
3537
ApiUrl *url.URL
3638
}
3739

38-
// ClientTransportPool abstracts the concept of multiple `runtime.ClientTransport` (openapi interface) representing one
39-
// target OpenZiti network. In situations where controllers are running in HA mode (multiple controllers) this
40-
// interface can attempt to try a different controller during outages or partitioning.
40+
// ClientTransportPool manages multiple runtime.ClientTransport instances representing
41+
// different controller endpoints in a high-availability OpenZiti network. It provides
42+
// automatic failover capabilities when individual controllers become unavailable.
4143
type ClientTransportPool interface {
4244
runtime.ClientTransport
4345

46+
// Add registers a new transport for the specified API URL.
4447
Add(apiUrl *url.URL, transport runtime.ClientTransport)
48+
49+
// Remove unregisters the transport for the specified API URL.
4550
Remove(apiUrl *url.URL)
4651

52+
// GetActiveTransport returns the currently selected transport.
4753
GetActiveTransport() *ApiClientTransport
54+
55+
// SetActiveTransport designates which transport to use for subsequent operations.
4856
SetActiveTransport(*ApiClientTransport)
57+
58+
// GetApiUrls returns all registered API URLs.
4959
GetApiUrls() []*url.URL
60+
61+
// IterateTransportsRandomly provides a channel for iterating through available transports
62+
// in random order.
5063
IterateTransportsRandomly() chan<- *ApiClientTransport
5164

65+
// TryTransportsForOp attempts to execute an operation, trying different transports
66+
// on connection failures.
5267
TryTransportsForOp(operation *runtime.ClientOperation) (any, error)
68+
69+
// TryTransportForF executes a callback function, trying different transports
70+
// on connection failures.
5371
TryTransportForF(cb func(*ApiClientTransport) (any, error)) (any, error)
5472
}
5573

5674
var _ runtime.ClientTransport = (ClientTransportPool)(nil)
5775
var _ ClientTransportPool = (*ClientTransportPoolRandom)(nil)
5876

59-
// ClientTransportPoolRandom selects a client transport (controller) at random until it is unreachable. Controllers
60-
// are tried at random until a controller is reached. The newly connected controller is set for use on future requests
61-
// until is too becomes unreachable.
77+
// ClientTransportPoolRandom implements a randomized failover strategy for controller selection.
78+
// It maintains an active transport and switches to randomly selected alternatives when the active
79+
// transport becomes unreachable.
6280
type ClientTransportPoolRandom struct {
6381
pool cmap.ConcurrentMap[string, *ApiClientTransport]
6482
current atomic.Pointer[ApiClientTransport]
@@ -107,6 +125,7 @@ func (c *ClientTransportPoolRandom) GetActiveTransport() *ApiClientTransport {
107125
return active
108126
}
109127

128+
// GetApiClientTransports returns a snapshot of all registered transports.
110129
func (c *ClientTransportPoolRandom) GetApiClientTransports() []*ApiClientTransport {
111130
var result []*ApiClientTransport
112131

@@ -117,6 +136,7 @@ func (c *ClientTransportPoolRandom) GetApiClientTransports() []*ApiClientTranspo
117136
return result
118137
}
119138

139+
// NewClientTransportPoolRandom creates a new transport pool with randomized failover.
120140
func NewClientTransportPoolRandom() *ClientTransportPoolRandom {
121141
return &ClientTransportPoolRandom{
122142
pool: cmap.New[*ApiClientTransport](),
@@ -215,6 +235,7 @@ func (c *ClientTransportPoolRandom) TryTransportForF(cb func(*ApiClientTransport
215235
return lastResult, lastErr
216236
}
217237

238+
// AnyTransport returns a randomly selected transport from the pool, or nil if empty.
218239
func (c *ClientTransportPoolRandom) AnyTransport() *ApiClientTransport {
219240
transportBuffer := c.pool.Items()
220241
var keys []string
@@ -237,6 +258,8 @@ var _ ClientTransportPool = (*ClientTransportPoolRandom)(nil)
237258

238259
var opError = &net.OpError{}
239260

261+
// errorIndicatesControllerSwap determines whether an error suggests the need to
262+
// switch to a different controller endpoint.
240263
func errorIndicatesControllerSwap(err error) bool {
241264
pfxlog.Logger().WithError(err).Debugf("checking for network errror on type (%T) and its wrapped errors", err)
242265

example/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/google/uuid v1.6.0
1111
github.com/gorilla/mux v1.8.1
1212
github.com/michaelquigley/pfxlog v0.6.10
13-
github.com/openziti/edge-api v0.26.48
13+
github.com/openziti/edge-api v0.26.50
1414
github.com/openziti/foundation/v2 v2.0.77
1515
github.com/openziti/runzmd v1.0.83
1616
github.com/openziti/sdk-golang v1.2.6

example/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
368368
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
369369
github.com/openziti/channel/v4 v4.2.37 h1:oFlYB7PPRzNS/CcwkM80/l2Rkw7z3FDaNbCjiDhdWeg=
370370
github.com/openziti/channel/v4 v4.2.37/go.mod h1:G6UDW+FsTj1NR1vzrOIQEfuShitU9ElHTNlNzkd2dMg=
371-
github.com/openziti/edge-api v0.26.48 h1:u31EKgNOxnepHjcLDqjeNJvLYXYQVvARQPacSlJ1nOE=
372-
github.com/openziti/edge-api v0.26.48/go.mod h1:Sj8HEql6ol2Oqp0yd3ZbGayCg8t/XTlH7q608UDHrwE=
371+
github.com/openziti/edge-api v0.26.50 h1:GNqVfAK4yhIInDl+B58lv1mEFslU0x3yjkDrwePQFys=
372+
github.com/openziti/edge-api v0.26.50/go.mod h1:Sj8HEql6ol2Oqp0yd3ZbGayCg8t/XTlH7q608UDHrwE=
373373
github.com/openziti/foundation/v2 v2.0.77 h1:aHB+qJuXFE9FZ+9GOF53laemoBxXmUZ2XnBbDy3fxmE=
374374
github.com/openziti/foundation/v2 v2.0.77/go.mod h1:rwLV3heBM+S7CtCKCauiozLWGPPejy2p80M1R65d6Lk=
375375
github.com/openziti/go-term-markdown v1.0.1 h1:9uzMpK4tav6OtvRxRt99WwPTzAzCh+Pj9zWU2FBp3Qg=

example/influxdb-client-go/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ require (
104104
github.com/muhlemmer/gu v0.3.1 // indirect
105105
github.com/oklog/ulid v1.3.1 // indirect
106106
github.com/openziti/channel/v4 v4.2.37 // indirect
107-
github.com/openziti/edge-api v0.26.48 // indirect
107+
github.com/openziti/edge-api v0.26.50 // indirect
108108
github.com/openziti/foundation/v2 v2.0.77 // indirect
109109
github.com/openziti/identity v1.0.116 // indirect
110110
github.com/openziti/metrics v1.4.2 // indirect

example/influxdb-client-go/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,8 @@ github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
444444
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
445445
github.com/openziti/channel/v4 v4.2.37 h1:oFlYB7PPRzNS/CcwkM80/l2Rkw7z3FDaNbCjiDhdWeg=
446446
github.com/openziti/channel/v4 v4.2.37/go.mod h1:G6UDW+FsTj1NR1vzrOIQEfuShitU9ElHTNlNzkd2dMg=
447-
github.com/openziti/edge-api v0.26.48 h1:u31EKgNOxnepHjcLDqjeNJvLYXYQVvARQPacSlJ1nOE=
448-
github.com/openziti/edge-api v0.26.48/go.mod h1:Sj8HEql6ol2Oqp0yd3ZbGayCg8t/XTlH7q608UDHrwE=
447+
github.com/openziti/edge-api v0.26.50 h1:GNqVfAK4yhIInDl+B58lv1mEFslU0x3yjkDrwePQFys=
448+
github.com/openziti/edge-api v0.26.50/go.mod h1:Sj8HEql6ol2Oqp0yd3ZbGayCg8t/XTlH7q608UDHrwE=
449449
github.com/openziti/foundation/v2 v2.0.77 h1:aHB+qJuXFE9FZ+9GOF53laemoBxXmUZ2XnBbDy3fxmE=
450450
github.com/openziti/foundation/v2 v2.0.77/go.mod h1:rwLV3heBM+S7CtCKCauiozLWGPPejy2p80M1R65d6Lk=
451451
github.com/openziti/identity v1.0.116 h1:o+vvH1zw0vaG+sn5sVHPWWnxTelZR59QFr9D+4os19g=

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
github.com/mitchellh/go-ps v1.0.0
1818
github.com/mitchellh/mapstructure v1.5.0
1919
github.com/openziti/channel/v4 v4.2.37
20-
github.com/openziti/edge-api v0.26.48
20+
github.com/openziti/edge-api v0.26.50
2121
github.com/openziti/foundation/v2 v2.0.77
2222
github.com/openziti/identity v1.0.116
2323
github.com/openziti/metrics v1.4.2

0 commit comments

Comments
 (0)