package main import ( "context" "encoding/json" "flag" "os" "os/signal" "time" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/config" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/connector" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/server" dex_server "github.com/dexidp/dex/server" "github.com/dexidp/dex/storage" "github.com/dexidp/dex/storage/memory" "github.com/prometheus/client_golang/prometheus" ) const stopTimeout = 10 * time.Second type cliArgs struct { configPath string } func parseArgs() *cliArgs { configPath := flag.String("config", "", "Path to the JSON configuration file") flag.Parse() return &cliArgs{ configPath: *configPath, } } func main() { args := parseArgs() mainCtx, cancel := context.WithCancel(context.Background()) conf, err := config.New(args.configPath) if err != nil { panic(err) } logger.Init(conf.LogLevel) logger.L.Infof("Initialized logger with level %v", conf.LogLevel) var storageType storage.Storage switch conf.StorageType { case "memory": storageType = memory.New(logger.L) default: logger.L.Fatalf("Unsupported backend type: %s", conf.StorageType) } logger.L.Infof("Initialized storage backend \"%s\"", conf.StorageType) dexConf := dex_server.Config{ Web: dex_server.WebConfig{ Dir: "./", Theme: "default", }, Storage: storageType, Issuer: conf.OpenConnectConfig.Issuer, SupportedResponseTypes: []string{"code"}, SkipApprovalScreen: false, AllowedOrigins: []string{"*"}, Logger: logger.L, PrometheusRegistry: prometheus.NewRegistry(), } logger.L.Info("Initializing authentication backends") dex_server.ConnectorsConfig["refuseAll"] = func() dex_server.ConnectorConfig { return new(connector.RefuseAllConfig) } if err := dexConf.Storage.CreateConnector(storage.Connector{ ID: "null", Name: "RefuseAll", Type: "refuseAll", Config: nil, }); err != nil { logger.L.Errorf("Failed to add connector for backend RefuseAll to stage: %s", err.Error()) } for _, backend := range conf.OpenConnectConfig.BackendConfigs { backendConfJson, err := json.Marshal(backend.Config) if err != nil { logger.L.Errorf("Failed to serialize oidc config for backend %q: %s", backend.Name, err.Error()) continue } if err := dexConf.Storage.CreateConnector(storage.Connector{ ID: backend.ID, Name: backend.Name, Type: backend.Type, Config: backendConfJson, }); err != nil { logger.L.Errorf("Failed to add connector for backend %q to stage: %s", backend.Name, err.Error()) continue } } logger.L.Info("Initializing clients") for _, client := range conf.OpenConnectConfig.ClientConfigs { if err := dexConf.Storage.CreateClient(*client); err != nil { logger.L.Errorf("Failed to add client to storage: %s", err.Error()) } } dexSrv, err := dex_server.NewServer(mainCtx, dexConf) if err != nil { logger.L.Fatalf("Failed to init dex server: %s", err.Error()) } logger.L.Info("Initializing server") s, err := server.New(conf, dexSrv, logger.L) if err != nil { logger.L.Fatalf("Failed to initialize server: %s", err.Error()) } go s.Run(mainCtx) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) logger.L.Info("Application successfully started") logger.L.Debug("Waiting for stop signal") select { case <-s.Done(): logger.L.Fatal("Unexpected exit from server") case <-c: logger.L.Info("Stopping main application") cancel() } logger.L.Debugf("Waiting %v for all daemons to stop", stopTimeout) select { case <-time.After(stopTimeout): logger.L.Fatalf("Failed to stop all daemons in the expected time") case <-s.Done(): logger.L.Info("web server successfully stopped") } logger.L.Info("Application successfully stopped") os.Exit(0) }