diff --git a/internal/state/hooks.go b/internal/state/hooks.go index 096fb8cf..d8ecb1de 100644 --- a/internal/state/hooks.go +++ b/internal/state/hooks.go @@ -2,6 +2,8 @@ package state import ( "context" + "crypto/x509" + "net/http" "github.com/canonical/microcluster/v2/rest/types" ) @@ -45,4 +47,12 @@ type Hooks struct { // OnDaemonConfigUpdate is a post-action hook that is run on all cluster members when any cluster member receives a local configuration update. OnDaemonConfigUpdate func(ctx context.Context, s State, config types.DaemonConfig) error + + // OnAuthenticate is run when an incoming HTTP request needs to be authenticated. + // If defined it is used as a replacement for the regular mTLS check. + // trustedCerts contains the certs from the truststore. + // Returning true indicates that the request is trusted. + // Returning false indicates that the request is not trusted. + // Returning an error is optional but will always result in a forbidden request. + OnAuthenticate func(ctx context.Context, s State, r *http.Request, trustedCerts map[string]x509.Certificate) (bool, error) } diff --git a/microcluster/app.go b/microcluster/app.go index 6dea737d..3ee7d155 100644 --- a/microcluster/app.go +++ b/microcluster/app.go @@ -112,7 +112,7 @@ func (m *MicroCluster) Status(ctx context.Context) (*internalTypes.Server, error // Ready waits for the daemon to report it has finished initial setup and is ready to be bootstrapped or join an // existing cluster. func (m *MicroCluster) Ready(ctx context.Context) error { - finger := make(chan error, 1) + finger := make(chan struct{}, 1) var errLast error go func() { for i := 0; ; i++ { @@ -156,7 +156,7 @@ func (m *MicroCluster) Ready(ctx context.Context) error { continue } - finger <- nil + finger <- struct{}{} return } }() diff --git a/rest/access/handlers.go b/rest/access/handlers.go index 23893cc8..fe78a76b 100644 --- a/rest/access/handlers.go +++ b/rest/access/handlers.go @@ -79,6 +79,10 @@ func Authenticate(state state.State, r *http.Request, hostAddress string, truste switch r.Host { case hostAddrPort.WithZone("").String(): + if intState.Hooks != nil && intState.Hooks.OnAuthenticate != nil { + return intState.Hooks.OnAuthenticate(r.Context(), intState, r, trustedCerts) + } + if r.TLS != nil { for _, cert := range r.TLS.PeerCertificates { trusted, fingerprint := util.CheckMutualTLS(*cert, trustedCerts)