package ak import ( "math/rand" "net/url" "os" "time" "github.com/go-openapi/runtime" "github.com/google/uuid" "github.com/pkg/errors" "github.com/recws-org/recws" "goauthentik.io/outpost/pkg" "goauthentik.io/outpost/pkg/client" "goauthentik.io/outpost/pkg/client/outposts" httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" log "github.com/sirupsen/logrus" ) const ConfigLogLevel = "log_level" const ConfigErrorReportingEnabled = "error_reporting_enabled" const ConfigErrorReportingEnvironment = "error_reporting_environment" // APIController main controller which connects to the authentik api via http and ws type APIController struct { Client *client.Authentik Auth runtime.ClientAuthInfoWriter token string Server Outpost logger *log.Entry reloadOffset time.Duration wsConn *recws.RecConn instanceUUID uuid.UUID } // NewAPIController initialise new API Controller instance from URL and API token func NewAPIController(akURL url.URL, token string) *APIController { transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme}) transport.Transport = SetUserAgent(getTLSTransport(), pkg.UserAgent()) // create the transport auth := httptransport.BearerToken(token) // create the API client, with the transport apiClient := client.New(transport, strfmt.Default) log := log.WithField("logger", "authentik.outpost.ak-api-controller") // Because we don't know the outpost UUID, we simply do a list and pick the first // The service account this token belongs to should only have access to a single outpost outposts, err := apiClient.Outposts.OutpostsInstancesList(outposts.NewOutpostsInstancesListParams(), auth) if err != nil { log.WithError(err).Error("Failed to fetch configuration") os.Exit(1) } outpost := outposts.Payload.Results[0] doGlobalSetup(outpost.Config.(map[string]interface{})) ac := &APIController{ Client: apiClient, Auth: auth, token: token, logger: log, reloadOffset: time.Duration(rand.Intn(10)) * time.Second, instanceUUID: uuid.New(), } ac.logger.Debugf("HA Reload offset: %s", ac.reloadOffset) ac.initWS(akURL, outpost.Pk) return ac } // Start Starts all handlers, non-blocking func (a *APIController) Start() error { err := a.Server.Refresh() if err != nil { return errors.Wrap(err, "failed to run initial refresh") } go func() { a.logger.Debug("Starting WS Handler...") a.startWSHandler() }() go func() { a.logger.Debug("Starting WS Health notifier...") a.startWSHealth() }() go func() { a.logger.Debug("Starting Interval updater...") a.startIntervalUpdater() }() go func() { err := a.Server.Start() if err != nil { panic(err) } }() return nil }