diff --git a/polyculeconnect.db b/polyculeconnect.db new file mode 100644 index 0000000..5b1a7bd Binary files /dev/null and b/polyculeconnect.db differ diff --git a/polyculeconnect/cmd/backend/add.go b/polyculeconnect/cmd/backend/add.go index ba70a18..7d21a34 100644 --- a/polyculeconnect/cmd/backend/add.go +++ b/polyculeconnect/cmd/backend/add.go @@ -1,11 +1,14 @@ package cmd import ( + "context" "fmt" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/cmd/utils" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger" - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/services/backend" + "github.com/google/uuid" "github.com/spf13/cobra" ) @@ -38,7 +41,11 @@ Parameters to provide: func addNewBackend() { c := utils.InitConfig("") logger.Init(c.LogLevel) - s := utils.InitStorage(c) + + s, err := db.New(*c) + if err != nil { + utils.Failf("failed to init storage: %s", err.Error()) + } if backendClientID == "" { utils.Fail("Empty client ID") @@ -47,15 +54,19 @@ func addNewBackend() { utils.Fail("Empty client secret") } - backendConf := backend.BackendConfig{ - Issuer: backendIssuer, - ClientID: backendClientID, - ClientSecret: backendClientSecret, - RedirectURI: c.RedirectURI(), - ID: backendID, - Name: backendName, + backendIDUUID := uuid.New() + + backendConf := model.Backend{ + ID: backendIDUUID, + Name: backendName, + OIDCConfig: model.BackendOIDCConfig{ + ClientID: backendClientID, + ClientSecret: backendClientSecret, + Issuer: backendIssuer, + RedirectURI: c.RedirectURI(), + }, } - if err := backend.New(s).AddBackend(backendConf); err != nil { + if err := s.BackendStorage().AddBackend(context.Background(), &backendConf); err != nil { utils.Failf("Failed to add new backend to storage: %s", err.Error()) } diff --git a/polyculeconnect/cmd/backend/backend.go b/polyculeconnect/cmd/backend/backend.go index b971f35..b5b01c5 100644 --- a/polyculeconnect/cmd/backend/backend.go +++ b/polyculeconnect/cmd/backend/backend.go @@ -11,9 +11,6 @@ var backendCmd = &cobra.Command{ Use: "backend", Short: "Handle authentication backends", Long: `Add, Remove or Show currently installed authentication backends`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("backend called") - }, } func printProperty(key, value string) { diff --git a/polyculeconnect/cmd/backend/remove.go b/polyculeconnect/cmd/backend/remove.go index de52874..a74de87 100644 --- a/polyculeconnect/cmd/backend/remove.go +++ b/polyculeconnect/cmd/backend/remove.go @@ -1,12 +1,14 @@ package cmd import ( + "context" "errors" "fmt" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/cmd/utils" - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/services/backend" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" "github.com/dexidp/dex/storage" + "github.com/google/uuid" "github.com/spf13/cobra" ) @@ -20,10 +22,18 @@ var backendRemoveCmd = &cobra.Command{ }, } -func removeBackend(backendID string) { - s := utils.InitStorage(utils.InitConfig("")) +func removeBackend(backendIDStr string) { + backendID, err := uuid.Parse(backendIDStr) + if err != nil { + utils.Failf("Invalid UUID format: %s", err.Error()) + } - if err := backend.New(s).RemoveBackend(backendID); err != nil { + s, err := db.New(*utils.InitConfig("")) + if err != nil { + utils.Failf("Failed to init storage: %s", err.Error()) + } + + if err := s.BackendStorage().DeleteBackend(context.Background(), backendID); err != nil { if !errors.Is(err, storage.ErrNotFound) { utils.Failf("Failed to remove backend: %s", err.Error()) } diff --git a/polyculeconnect/cmd/backend/show.go b/polyculeconnect/cmd/backend/show.go index 1fc8253..6999e5c 100644 --- a/polyculeconnect/cmd/backend/show.go +++ b/polyculeconnect/cmd/backend/show.go @@ -1,11 +1,13 @@ package cmd import ( + "context" "errors" "fmt" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/cmd/utils" - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/services/backend" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/backend" "github.com/dexidp/dex/storage" "github.com/spf13/cobra" ) @@ -19,36 +21,39 @@ Optional parameters: - app-id: id of the backend to display. If empty, display the list of available backends instead`, Args: cobra.MaximumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - s := utils.InitStorage(utils.InitConfig("")) + s, err := db.New(*utils.InitConfig("")) + if err != nil { + utils.Failf("Failed to init storage: %s", err.Error()) + } if len(args) > 0 { - showBackend(args[0], backend.New(s)) + showBackend(args[0], s.BackendStorage()) } else { - listBackends(backend.New(s)) + listBackends(s.BackendStorage()) } }, } -func showBackend(backendId string, backendService backend.Service) { - backendConfig, err := backendService.GetBackend(backendId) +func showBackend(backendName string, backendService backend.BackendDB) { + backendConfig, err := backendService.GetBackendByName(context.Background(), backendName) if err != nil { if errors.Is(err, storage.ErrNotFound) { - utils.Failf("Backend with ID %s does not exist\n", backendId) + utils.Failf("Backend with name %s does not exist\n", backendName) } - utils.Failf("Failed to get config for backend %s: %q\n", backendId, err.Error()) + utils.Failf("Failed to get config for backend %s: %q\n", backendName, err.Error()) } fmt.Println("Backend config:") - printProperty("ID", backendConfig.ID) + printProperty("ID", backendConfig.ID.String()) printProperty("Name", backendConfig.Name) - printProperty("Issuer", backendConfig.Issuer) - printProperty("Client ID", backendConfig.ClientID) - printProperty("Client secret", backendConfig.ClientSecret) - printProperty("Redirect URI", backendConfig.RedirectURI) + printProperty("Issuer", backendConfig.OIDCConfig.Issuer) + printProperty("Client ID", backendConfig.OIDCConfig.ClientID) + printProperty("Client secret", backendConfig.OIDCConfig.ClientSecret) + printProperty("Redirect URI", backendConfig.OIDCConfig.RedirectURI) } -func listBackends(backendService backend.Service) { - backends, err := backendService.ListBackends() +func listBackends(backendStorage backend.BackendDB) { + backends, err := backendStorage.GetAllBackends(context.Background()) if err != nil { utils.Failf("Failed to list backends: %q\n", err.Error()) } @@ -58,7 +63,7 @@ func listBackends(backendService backend.Service) { return } for _, b := range backends { - fmt.Printf("\t - %s: (%s) - %s\n", b.ID, b.Name, b.Issuer) + fmt.Printf("\t - %s: (%s) - %s\n", b.ID, b.Name, b.OIDCConfig.Issuer) } } diff --git a/polyculeconnect/cmd/db/migrate.go b/polyculeconnect/cmd/db/migrate.go new file mode 100644 index 0000000..bf5749f --- /dev/null +++ b/polyculeconnect/cmd/db/migrate.go @@ -0,0 +1,96 @@ +package db + +import ( + "fmt" + "strconv" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/cmd/utils" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/config" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" + "github.com/golang-migrate/migrate/v4" + "github.com/golang-migrate/migrate/v4/database/sqlite3" + _ "github.com/golang-migrate/migrate/v4/source/file" + "github.com/spf13/cobra" +) + +// migrateCmd represents the db migrate command +var migrateCmd = &cobra.Command{ + Use: "migrate", + Short: "Run the database migrations", + Long: `Run the database migrations.`, + Run: func(cmd *cobra.Command, args []string) { + conf := utils.InitConfig("") + up, nbSteps := parseArgs(args) + if err := runMigrations(conf, up, nbSteps); err != nil { + utils.Failf("Failed to run migrations: %s", err.Error()) + } + }, +} + +func parseArgs(args []string) (bool, int) { + if len(args) == 0 { + return true, 0 + } + var actionUp bool + switch args[0] { + case "up": + actionUp = true + case "down": + actionUp = false + default: + actionUp = true + } + + nbSteps := 0 + if len(args) > 1 { + var err error + nbSteps, err = strconv.Atoi(args[1]) + if err != nil { + return actionUp, 0 + } + } + + return actionUp, nbSteps +} + +func runMigrations(conf *config.AppConfig, up bool, nbSteps int) error { + storage, err := db.New(*conf) + if err != nil { + return fmt.Errorf("failed to connect to db: %w", err) + } + driver, err := sqlite3.WithInstance(storage.DB(), &sqlite3.Config{}) + if err != nil { + return fmt.Errorf("failed to open sqlite3 driver: %w", err) + } + + m, err := migrate.NewWithDatabaseInstance("file://migrations", "", driver) + if err != nil { + return fmt.Errorf("failed to init migrator: %w", err) + } + + if nbSteps > 0 { + multiplier := 1 + if !up { + multiplier = -1 + } + return m.Steps(multiplier * nbSteps) + } + if up { + return m.Up() + } + return m.Down() +} + +func init() { + dbCmd.AddCommand(migrateCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // dbCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // dbCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/polyculeconnect/cmd/serve/serve.go b/polyculeconnect/cmd/serve/serve.go index 1c4a98f..32a48dd 100644 --- a/polyculeconnect/cmd/serve/serve.go +++ b/polyculeconnect/cmd/serve/serve.go @@ -2,19 +2,23 @@ package serve import ( "context" + "log/slog" "os" "os/signal" "time" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/cmd" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/cmd/utils" - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/connector" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/client" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/middlewares" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/storage" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/server" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/services" - dex_server "github.com/dexidp/dex/server" - "github.com/prometheus/client_golang/prometheus" "github.com/spf13/cobra" + "github.com/zitadel/oidc/v3/pkg/op" + "go.uber.org/zap/exp/zapslog" ) var configPath string @@ -41,43 +45,57 @@ func serve() { storageType := utils.InitStorage(conf) logger.L.Infof("Initialized storage backend %q", conf.StorageType) - dexConf := dex_server.Config{ - Web: dex_server.WebConfig{ - Dir: conf.StaticDir, - Theme: "default", - }, - Storage: storageType, - Issuer: conf.Issuer, - SupportedResponseTypes: []string{"code"}, - SkipApprovalScreen: false, - AllowedOrigins: []string{"*"}, - Logger: logger.L, - PrometheusRegistry: prometheus.NewRegistry(), + + userDB, err := db.New(*conf) + if err != nil { + utils.Failf("failed to init user DB: %s", err.Error()) + } + + st := storage.Storage{LocalStorage: userDB} + opConf := op.Config{} + slogger := slog.New(zapslog.NewHandler(logger.L.Desugar().Core(), nil)) + // slogger := + options := []op.Option{ + op.WithAllowInsecure(), + op.WithLogger(slogger), + op.WithHttpInterceptors(middlewares.WithBackendFromRequestMiddleware), } logger.L.Info("Initializing authentication backends") - - dex_server.ConnectorsConfig[connector.TypeRefuseAll] = func() dex_server.ConnectorConfig { return new(connector.RefuseAllConfig) } - connectors, err := dexConf.Storage.ListConnectors() + backends := []*client.OIDCClient{} + backendConfs, err := userDB.BackendStorage().GetAllBackends(context.Background()) if err != nil { - logger.L.Fatalf("Failed to get existing connectors: %s", err.Error()) + utils.Failf("failed to get backend configs from the DB: %s", err.Error()) } - var connectorIDs []string - for _, conn := range connectors { - connectorIDs = append(connectorIDs, conn.ID) + + // TODO: check if we need to do it this way or + // - do a try-loop? + // - only init when using them in a request? + for _, c := range backendConfs { + logger.L.Debugf("Initializing backend %s", c.Name) + b, err := client.New(context.Background(), c) + if err != nil { + utils.Failf("failed to init backend client: %s", err.Error()) + } + backends = append(backends, b) + } + if len(backends) == 0 { + logger.L.Warn("No auth backend loaded") + } else { + logger.L.Infof("Initialized %d auth backends", len(backends)) + } + + provider, err := op.NewProvider(&opConf, &st, op.StaticIssuer(conf.Issuer), options...) + if err != nil { + utils.Failf("failed to init OIDC provider: %s", err.Error()) } if err := services.AddDefaultBackend(storageType); err != nil { logger.L.Errorf("Failed to add connector for backend RefuseAll to stage: %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) + s, err := server.New(conf, provider, logger.L) if err != nil { logger.L.Fatalf("Failed to initialize server: %s", err.Error()) } diff --git a/polyculeconnect/config/config.go b/polyculeconnect/config/config.go index 2db5424..4ba8be6 100644 --- a/polyculeconnect/config/config.go +++ b/polyculeconnect/config/config.go @@ -9,7 +9,7 @@ import ( "github.com/dexidp/dex/connector/oidc" "github.com/kelseyhightower/envconfig" - "github.com/sirupsen/logrus" + "go.uber.org/zap" ) const ( @@ -32,7 +32,7 @@ const ( ) const ( - defaultLogLevel = logrus.InfoLevel + defaultLogLevel = zap.InfoLevel defaultServerMode = ModeNet defaultServerHost = "0.0.0.0" @@ -126,12 +126,12 @@ func (c *jsonConf) initValues(ac *AppConfig) { } type AppConfig struct { - LogLevel logrus.Level `envconfig:"LOG_LEVEL"` - ServerMode ListeningMode `envconfig:"SERVER_MODE"` - Host string `envconfig:"SERVER_HOST"` - Port int `envconfig:"SERVER_PORT"` - SockPath string `envconfig:"SERVER_SOCK"` - StorageType string `envconfig:"STORAGE_TYPE"` + LogLevel zap.AtomicLevel `envconfig:"LOG_LEVEL"` + ServerMode ListeningMode `envconfig:"SERVER_MODE"` + Host string `envconfig:"SERVER_HOST"` + Port int `envconfig:"SERVER_PORT"` + SockPath string `envconfig:"SERVER_SOCK"` + StorageType string `envconfig:"STORAGE_TYPE"` StorageConfig *StorageConfig Issuer string StaticDir string @@ -139,7 +139,7 @@ type AppConfig struct { func defaultConfig() AppConfig { return AppConfig{ - LogLevel: defaultLogLevel, + LogLevel: zap.NewAtomicLevelAt(defaultLogLevel), ServerMode: defaultServerMode, Host: defaultServerHost, Port: defaultServerPort, @@ -162,13 +162,12 @@ func defaultConfig() AppConfig { } } -func parseLevel(lvlStr string) logrus.Level { - for _, lvl := range logrus.AllLevels { - if lvl.String() == lvlStr { - return lvl - } +func parseLevel(lvlStr string) zap.AtomicLevel { + var res zap.AtomicLevel + if err := res.UnmarshalText([]byte(lvlStr)); err != nil { + return zap.NewAtomicLevelAt(zap.InfoLevel) } - return logrus.InfoLevel + return res } func (ac *AppConfig) UnmarshalJSON(data []byte) error { diff --git a/polyculeconnect/controller/ui/static.go b/polyculeconnect/controller/ui/static.go index 1145194..e98224a 100644 --- a/polyculeconnect/controller/ui/static.go +++ b/polyculeconnect/controller/ui/static.go @@ -9,7 +9,7 @@ import ( "path/filepath" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/helpers" - "github.com/sirupsen/logrus" + "go.uber.org/zap" ) const StaticRoute = "/static/" @@ -30,12 +30,12 @@ func (sc *StaticController) ServeHTTP(w http.ResponseWriter, r *http.Request) { } type IndexController struct { - l *logrus.Logger + l *zap.SugaredLogger downstreamConstroller http.Handler baseDir string } -func NewIndexController(l *logrus.Logger, downstream http.Handler, baseDir string) *IndexController { +func NewIndexController(l *zap.SugaredLogger, downstream http.Handler, baseDir string) *IndexController { return &IndexController{ l: l, downstreamConstroller: downstream, diff --git a/polyculeconnect/go.mod b/polyculeconnect/go.mod index 4214398..2730293 100644 --- a/polyculeconnect/go.mod +++ b/polyculeconnect/go.mod @@ -1,19 +1,26 @@ module git.faercol.me/faercol/polyculeconnect/polyculeconnect -go 1.20 +go 1.21 + +toolchain go1.22.6 require ( github.com/dexidp/dex v0.0.0-20231014000322-089f374d4f3e + github.com/go-jose/go-jose/v4 v4.0.4 + github.com/golang-migrate/migrate/v4 v4.17.1 + github.com/google/uuid v1.6.0 github.com/kelseyhightower/envconfig v1.4.0 - github.com/prometheus/client_golang v1.17.0 + github.com/mattn/go-sqlite3 v1.14.17 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 + github.com/zitadel/oidc/v3 v3.27.0 + go.uber.org/zap v1.24.0 + go.uber.org/zap/exp v0.2.0 ) require ( - cloud.google.com/go/compute v1.23.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/AppsFlyer/go-sundheit v0.5.0 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -21,54 +28,69 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/beevik/etree v1.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-oidc/v3 v3.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dexidp/dex/api/v2 v2.1.1-0.20231014000322-089f374d4f3e // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-chi/chi/v5 v5.1.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect - github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect + github.com/muhlemmer/gu v0.3.1 // indirect + github.com/muhlemmer/httpforwarded v0.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect + github.com/rs/cors v1.11.0 // indirect github.com/russellhaering/goxmldsig v1.4.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/zitadel/logging v0.6.0 // indirect + github.com/zitadel/schema v1.3.0 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/api v0.147.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect - google.golang.org/grpc v1.58.3 // indirect - google.golang.org/protobuf v1.31.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/api v0.150.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/polyculeconnect/go.sum b/polyculeconnect/go.sum index c60f175..99d4fb1 100644 --- a/polyculeconnect/go.sum +++ b/polyculeconnect/go.sum @@ -1,8 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/AppsFlyer/go-sundheit v0.5.0 h1:/VxpyigCfJrq1r97mn9HPiAB2qrhcTFHwNIIDr15CZM= github.com/AppsFlyer/go-sundheit v0.5.0/go.mod h1:2ZM0BnfqT/mljBQO224VbL5XH06TgWuQ6Cn+cTtCpTY= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= @@ -19,8 +17,12 @@ github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1L github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.2.0 h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw= github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -48,19 +50,31 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= +github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -79,27 +93,40 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= +github.com/jeremija/gosubmit v0.2.7/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= @@ -108,11 +135,13 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= @@ -125,6 +154,10 @@ github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMK github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= +github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= +github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= +github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -143,6 +176,9 @@ github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -160,8 +196,9 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -170,22 +207,44 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank= +github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= +github.com/zitadel/oidc/v3 v3.27.0 h1:zeYpyRH0UcgdCjVHUYzSsqf1jbSwVMPVxYKOnRXstgU= +github.com/zitadel/oidc/v3 v3.27.0/go.mod h1:ZwBEqSviCpJVZiYashzo53bEGRGXi7amE5Q8PpQg9IM= +github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= +github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap/exp v0.2.0 h1:FtGenNNeCATRB3CmB/yEUnjEFeJWpB/pMcy7e2bKPYs= +go.uber.org/zap/exp v0.2.0/go.mod h1:t0gqAIdh1MfKv9EwN/dLwfZnJxe9ITAZN78HEWPFWDQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741 h1:fGZugkZk2UgYBxtpKmvub51Yno1LJDeEsRp2xGD+0gY= -golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -196,7 +255,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -204,18 +262,19 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -229,8 +288,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -238,14 +297,14 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -256,26 +315,26 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= +google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -287,8 +346,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -299,6 +358,7 @@ gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/polyculeconnect/helpers/helpers.go b/polyculeconnect/helpers/helpers.go index 5a6e659..fce58ab 100644 --- a/polyculeconnect/helpers/helpers.go +++ b/polyculeconnect/helpers/helpers.go @@ -4,7 +4,7 @@ import ( "context" "net/http" - "github.com/sirupsen/logrus" + "go.uber.org/zap" ) type ContextKey string @@ -16,7 +16,7 @@ type ResponseInfo struct { ContentLength int } -func HandleResponse(w http.ResponseWriter, r *http.Request, returncode int, content []byte, l *logrus.Logger) { +func HandleResponse(w http.ResponseWriter, r *http.Request, returncode int, content []byte, l *zap.SugaredLogger) { w.WriteHeader(returncode) n, err := w.Write(content) if err != nil { diff --git a/polyculeconnect/internal/client/client.go b/polyculeconnect/internal/client/client.go new file mode 100644 index 0000000..6a933ba --- /dev/null +++ b/polyculeconnect/internal/client/client.go @@ -0,0 +1,39 @@ +package client + +import ( + "context" + "fmt" + "log/slog" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger" + "github.com/zitadel/oidc/v3/pkg/client/rp" + "go.uber.org/zap" + "go.uber.org/zap/exp/zapslog" +) + +type OIDCClient struct { + conf *model.Backend + + provider rp.RelyingParty + ctx context.Context + st db.Storage + l *zap.SugaredLogger +} + +func New(ctx context.Context, conf *model.Backend, l *zap.SugaredLogger) (*OIDCClient, error) { + options := []rp.Option{ + rp.WithLogger(slog.New(zapslog.NewHandler(logger.L.Desugar().Core(), nil))), + } + pr, err := rp.NewRelyingPartyOIDC(ctx, conf.OIDCConfig.Issuer, conf.OIDCConfig.ClientID, conf.OIDCConfig.ClientSecret, conf.OIDCConfig.RedirectURI, []string{}, options...) + if err != nil { + return nil, fmt.Errorf("failed to init relying party provider: %w", err) + } + + return &OIDCClient{ctx: ctx, conf: conf, provider: pr, l: l}, nil +} + +func (c *OIDCClient) toto() { + c.provider.GetDeviceAuthorizationEndpoint() +} diff --git a/polyculeconnect/internal/db/authrequest/authrequest.go b/polyculeconnect/internal/db/authrequest/authrequest.go new file mode 100644 index 0000000..3506dee --- /dev/null +++ b/polyculeconnect/internal/db/authrequest/authrequest.go @@ -0,0 +1,77 @@ +package authrequest + +import ( + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" + "github.com/google/uuid" +) + +var ErrNotFound = errors.New("backend not found") + +const authRequestRows = `"id", "client_id", "backend_id", "scopes", "redirect_uri", "state", "nonce", "response_type", "creation_time"` + +type AuthRequestDB interface { + GetAuthRequestByID(ctx context.Context, id uuid.UUID) (*model.AuthRequest, error) + CreateAuthRequest(ctx context.Context, req model.AuthRequest) error +} + +type sqlAuthRequestDB struct { + db *sql.DB +} + +func (db *sqlAuthRequestDB) GetAuthRequestByID(ctx context.Context, id uuid.UUID) (*model.AuthRequest, error) { + query := fmt.Sprintf(`SELECT %s FROM "auth_request_2" WHERE "id" = ?`, authRequestRows) + row := db.db.QueryRowContext(ctx, query, id) + + var res model.AuthRequest + var scopesStr []byte + + if err := row.Scan(&res.ID, &res.ClientID, &res.BackendID, &scopesStr, &res.RedirectURI, &res.State, &res.Nonce, &res.ResponseType, &res.CreationDate); err != nil { + return nil, fmt.Errorf("failed to get auth request from DB: %w", err) + } + if err := json.Unmarshal(scopesStr, &res.Scopes); err != nil { + return nil, fmt.Errorf("invalid format for scopes: %w", err) + } + + fmt.Println(res) + + return &res, nil +} + +func (db *sqlAuthRequestDB) CreateAuthRequest(ctx context.Context, req model.AuthRequest) error { + tx, err := db.db.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("failed to start transaction: %w", err) + } + defer func() { _ = tx.Rollback() }() + + scopesStr, err := json.Marshal(req.Scopes) + if err != nil { + return fmt.Errorf("failed to serialize scopes: %w", err) + } + + query := fmt.Sprintf(`INSERT INTO "auth_request_2" (%s) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, authRequestRows) + _, err = tx.ExecContext(ctx, query, + req.ID, req.ClientID, req.BackendID, + scopesStr, req.RedirectURI, req.State, + req.Nonce, req.ResponseType, req.CreationDate, req.AuthTime, + ) + if err != nil { + return fmt.Errorf("failed to insert in DB: %w", err) + } + + if err := tx.Commit(); err != nil { + return fmt.Errorf("failed to commit transaction: %w", err) + } + + return nil +} + +func New(db *sql.DB) *sqlAuthRequestDB { + return &sqlAuthRequestDB{db: db} +} diff --git a/polyculeconnect/internal/db/backend/backend.go b/polyculeconnect/internal/db/backend/backend.go new file mode 100644 index 0000000..b68f3ef --- /dev/null +++ b/polyculeconnect/internal/db/backend/backend.go @@ -0,0 +1,120 @@ +package backend + +import ( + "context" + "database/sql" + "errors" + "fmt" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" + "github.com/google/uuid" +) + +var ErrNotFound = errors.New("backend not found") + +const backendRows = `"id", "name", "oidc_issuer", "oidc_client_id", "oidc_client_secret", "oidc_redirect_uri"` + +type scannable interface { + Scan(dest ...any) error +} + +type BackendDB interface { + GetAllBackends(ctx context.Context) ([]*model.Backend, error) + + GetBackendByID(ctx context.Context, id uuid.UUID) (*model.Backend, error) + GetBackendByName(ctx context.Context, name string) (*model.Backend, error) + + AddBackend(ctx context.Context, newBackend *model.Backend) error + + DeleteBackend(ctx context.Context, id uuid.UUID) error +} + +type sqlBackendDB struct { + db *sql.DB +} + +func backendFromRow(row scannable) (*model.Backend, error) { + var res model.Backend + + if err := row.Scan(&res.ID, &res.Name, &res.OIDCConfig.Issuer, &res.OIDCConfig.ClientID, &res.OIDCConfig.ClientSecret, &res.OIDCConfig.RedirectURI); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("invalid format for backend: %w", err) + } + return &res, nil +} + +func (db *sqlBackendDB) GetBackendByName(ctx context.Context, name string) (*model.Backend, error) { + query := fmt.Sprintf(`SELECT %s FROM "backend" WHERE "name" = ?`, backendRows) + row := db.db.QueryRowContext(ctx, query, name) + return backendFromRow(row) +} + +func (db *sqlBackendDB) GetBackendByID(ctx context.Context, id uuid.UUID) (*model.Backend, error) { + query := fmt.Sprintf(`SELECT %s FROM "backend" WHERE "id" = ?`, backendRows) + row := db.db.QueryRowContext(ctx, query, id) + return backendFromRow(row) +} + +func (db *sqlBackendDB) GetAllBackends(ctx context.Context) ([]*model.Backend, error) { + rows, err := db.db.QueryContext(ctx, fmt.Sprintf(`SELECT %s FROM "backend"`, backendRows)) + if err != nil { + return nil, err + } + + var res []*model.Backend + for rows.Next() { + b, err := backendFromRow(rows) + if err != nil { + return nil, err + } + res = append(res, b) + } + return res, nil +} + +func (db *sqlBackendDB) AddBackend(ctx context.Context, newBackend *model.Backend) error { + tx, err := db.db.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("failed to start transaction: %w", err) + } + defer func() { _ = tx.Rollback() }() + + query := fmt.Sprintf(`INSERT INTO "backend" (%s) VALUES ($1, $2, $3, $4, $5, $6)`, backendRows) + _, err = tx.ExecContext( + ctx, query, + newBackend.ID, newBackend.Name, + newBackend.OIDCConfig.Issuer, newBackend.OIDCConfig.ClientID, + newBackend.OIDCConfig.ClientSecret, newBackend.OIDCConfig.RedirectURI, + ) + if err != nil { + return fmt.Errorf("failed to insert in DB: %w", err) + } + + if err := tx.Commit(); err != nil { + return fmt.Errorf("failed to commit transaction: %w", err) + } + return nil +} + +func (db *sqlBackendDB) DeleteBackend(ctx context.Context, id uuid.UUID) error { + tx, err := db.db.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("failed to start transaction: %w", err) + } + defer func() { _ = tx.Rollback() }() + + if _, err := tx.ExecContext(ctx, `DELETE FROM "backend" WHERE id = $1`, id.String()); err != nil { + return fmt.Errorf("failed to run query: %w", err) + } + + if err := tx.Commit(); err != nil { + return fmt.Errorf("failed to commit transaction: %w", err) + } + return nil +} + +func New(db *sql.DB) *sqlBackendDB { + return &sqlBackendDB{db: db} +} diff --git a/polyculeconnect/internal/db/base.go b/polyculeconnect/internal/db/base.go new file mode 100644 index 0000000..207a520 --- /dev/null +++ b/polyculeconnect/internal/db/base.go @@ -0,0 +1,46 @@ +package db + +import ( + "database/sql" + "fmt" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/config" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/authrequest" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/backend" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/client" +) + +type Storage interface { + DB() *sql.DB + ClientStorage() client.ClientDB + BackendStorage() backend.BackendDB + AuthRequestStorage() authrequest.AuthRequestDB +} + +type sqlStorage struct { + db *sql.DB +} + +func (s *sqlStorage) DB() *sql.DB { + return s.db +} + +func (s *sqlStorage) ClientStorage() client.ClientDB { + return client.New(s.db) +} + +func (s *sqlStorage) BackendStorage() backend.BackendDB { + return backend.New(s.db) +} + +func (s *sqlStorage) AuthRequestStorage() authrequest.AuthRequestDB { + return authrequest.New(s.db) +} + +func New(conf config.AppConfig) (Storage, error) { + db, err := sql.Open("sqlite3", conf.StorageConfig.File) + if err != nil { + return nil, fmt.Errorf("failed to open DB: %w", err) + } + return &sqlStorage{db: db}, nil +} diff --git a/polyculeconnect/internal/db/client/client.go b/polyculeconnect/internal/db/client/client.go new file mode 100644 index 0000000..0b90045 --- /dev/null +++ b/polyculeconnect/internal/db/client/client.go @@ -0,0 +1,60 @@ +package client + +import ( + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" + _ "github.com/mattn/go-sqlite3" +) + +var ErrNotFound = errors.New("not found") + +const clientRows = `"client"."id", "client"."secret", "client"."redirect_uris", "client"."trusted_peers", "client"."name"` + +type ClientDB interface { + GetClientByID(ctx context.Context, id string) (*model.Client, error) +} + +type sqlClientDB struct { + db *sql.DB +} + +func strArrayToSlice(rawVal string) []string { + var res []string + if err := json.Unmarshal([]byte(rawVal), &res); err != nil { + return nil + } + return res +} + +func clientFromRow(row *sql.Row) (*model.Client, error) { + var res model.Client + redirectURIsStr := "" + trustedPeersStr := "" + + if err := row.Scan(&res.ID, &res.Secret, &redirectURIsStr, &trustedPeersStr, &res.Name); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("invalid format for client: %w", err) + } + + res.ClientConfig.RedirectURIs = strArrayToSlice(redirectURIsStr) + res.ClientConfig.TrustedPeers = strArrayToSlice(trustedPeersStr) + + return &res, nil +} + +func (db *sqlClientDB) GetClientByID(ctx context.Context, id string) (*model.Client, error) { + query := fmt.Sprintf(`SELECT %s FROM "client" WHERE "id" = ?`, clientRows) + row := db.db.QueryRowContext(ctx, query, id) + return clientFromRow(row) +} + +func New(db *sql.DB) *sqlClientDB { + return &sqlClientDB{db: db} +} diff --git a/polyculeconnect/middlewares/logger.go b/polyculeconnect/internal/middlewares/logger.go similarity index 96% rename from polyculeconnect/middlewares/logger.go rename to polyculeconnect/internal/middlewares/logger.go index 0808010..43c1d10 100644 --- a/polyculeconnect/middlewares/logger.go +++ b/polyculeconnect/internal/middlewares/logger.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/sirupsen/logrus" + "go.uber.org/zap" ) type loggedResponseWriter struct { @@ -33,7 +33,7 @@ func (lr *loggedResponseWriter) WriteHeader(statusCode int) { } type LoggerMiddleware struct { - l *logrus.Logger + l *zap.SugaredLogger h http.Handler } diff --git a/polyculeconnect/internal/middlewares/middlewarechain.go b/polyculeconnect/internal/middlewares/middlewarechain.go new file mode 100644 index 0000000..ba89469 --- /dev/null +++ b/polyculeconnect/internal/middlewares/middlewarechain.go @@ -0,0 +1,14 @@ +package middlewares + +import ( + "net/http" + + "go.uber.org/zap" +) + +func WithLogger(handler http.Handler, l *zap.SugaredLogger) http.Handler { + return &LoggerMiddleware{ + l: l, + h: handler, + } +} diff --git a/polyculeconnect/internal/middlewares/test.go b/polyculeconnect/internal/middlewares/test.go new file mode 100644 index 0000000..1f83086 --- /dev/null +++ b/polyculeconnect/internal/middlewares/test.go @@ -0,0 +1,46 @@ +package middlewares + +import ( + "context" + "net/http" + "strings" +) + +const ( + backendNameQueryParam = "connector_id" + backendCtxKeyName = "backendName" +) + +type BackendFromRequestMiddleware struct { + h http.Handler +} + +func (m *BackendFromRequestMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if !strings.HasPrefix(r.RequestURI, "/authorize") { + m.h.ServeHTTP(w, r) + return + } + + if err := r.ParseForm(); err != nil { + // TODO: handle this better + w.WriteHeader(http.StatusBadRequest) + return + } + + backendName := r.Form.Get(backendNameQueryParam) + // TODO this should be explicitly handled + if backendName == "" { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("no backend id provided")) + return + } + + // TODO we should test that this backend actually exists here + + ctx := context.WithValue(r.Context(), backendCtxKeyName, backendName) + m.h.ServeHTTP(w, r.WithContext(ctx)) +} + +func WithBackendFromRequestMiddleware(input http.Handler) http.Handler { + return &BackendFromRequestMiddleware{h: input} +} diff --git a/polyculeconnect/internal/model/authrequest.go b/polyculeconnect/internal/model/authrequest.go new file mode 100644 index 0000000..07324a8 --- /dev/null +++ b/polyculeconnect/internal/model/authrequest.go @@ -0,0 +1,112 @@ +package model + +import ( + "strings" + "time" + + "github.com/google/uuid" + "github.com/zitadel/oidc/v3/pkg/oidc" +) + +// AuthRequest also implements the op.AuthRequest interface +type AuthRequest struct { + ID uuid.UUID + ClientID string + Scopes []string + RedirectURI string + State string + Nonce string + + ResponseType string + + CreationDate time.Time + AuthTime time.Time + + // TODO mapping to claims to be added I guess + + CodeChallenge string + CodeChallengeMethod string + + BackendID uuid.UUID + Backend *Backend + + UserID uuid.UUID + done bool +} + +func (a AuthRequest) GetID() string { + return a.ID.String() +} + +func (a AuthRequest) GetACR() string { + return "" // TODO: the hell is ACR??? +} + +func (a AuthRequest) GetAMR() []string { + return []string{} // TODO: the hell is this??? +} + +func (a AuthRequest) GetAudience() []string { + return []string{a.ID.String()} // TODO: check if we need to return something else +} + +func (a AuthRequest) GetAuthTime() time.Time { + return a.AuthTime +} + +func (a AuthRequest) GetClientID() string { + return a.ID.String() // small hack since we actually need the AuthRequestID here +} + +func (a AuthRequest) GetCodeChallenge() *oidc.CodeChallenge { + return &oidc.CodeChallenge{ + Challenge: a.CodeChallenge, + Method: oidc.CodeChallengeMethod(a.CodeChallengeMethod), + } +} + +func (a AuthRequest) GetNonce() string { + return a.Nonce +} + +func (a AuthRequest) GetRedirectURI() string { + return a.RedirectURI +} + +func (a AuthRequest) GetResponseType() oidc.ResponseType { + return oidc.ResponseType(a.ResponseType) +} + +func (a AuthRequest) GetResponseMode() oidc.ResponseMode { + return oidc.ResponseModeQuery // TODO: check if this is good +} + +func (a AuthRequest) GetScopes() []string { + return a.Scopes +} + +func (a AuthRequest) GetState() string { + return a.State +} + +func (a AuthRequest) GetSubject() string { + return a.UserID.String() +} + +func (a AuthRequest) Done() bool { + return a.done +} + +func (a *AuthRequest) FromOIDCAuthRequest(req *oidc.AuthRequest, backendID uuid.UUID) { + a.ID = uuid.New() + a.ClientID = req.ClientID + a.Scopes = strings.Split(req.Scopes.String(), " ") + a.RedirectURI = req.RedirectURI + a.State = req.State + a.Nonce = req.Nonce + a.ResponseType = string(req.ResponseType) + a.CreationDate = time.Now().UTC() + a.CodeChallenge = req.CodeChallenge + a.CodeChallengeMethod = string(req.CodeChallengeMethod) + a.BackendID = backendID +} diff --git a/polyculeconnect/internal/model/backend.go b/polyculeconnect/internal/model/backend.go new file mode 100644 index 0000000..1453733 --- /dev/null +++ b/polyculeconnect/internal/model/backend.go @@ -0,0 +1,16 @@ +package model + +import "github.com/google/uuid" + +type BackendOIDCConfig struct { + Issuer string + ClientID string + ClientSecret string + RedirectURI string +} + +type Backend struct { + ID uuid.UUID + Name string + OIDCConfig BackendOIDCConfig +} diff --git a/polyculeconnect/internal/model/client.go b/polyculeconnect/internal/model/client.go new file mode 100644 index 0000000..f2cdda7 --- /dev/null +++ b/polyculeconnect/internal/model/client.go @@ -0,0 +1,93 @@ +package model + +import ( + "time" + + "github.com/zitadel/oidc/v3/pkg/oidc" + "github.com/zitadel/oidc/v3/pkg/op" +) + +type ClientConfig struct { + ID string + Secret string + RedirectURIs []string + TrustedPeers []string + Name string + AuthRequest *AuthRequest +} + +type Client struct { + ClientConfig +} + +func (c Client) GetID() string { + return c.ClientConfig.ID +} + +func (c Client) RedirectURIs() []string { + return c.ClientConfig.RedirectURIs +} + +func (c Client) PostLogoutRedirectURIs() []string { + return nil +} + +func (c Client) ApplicationType() op.ApplicationType { + return op.ApplicationTypeWeb // TODO: should we support more? +} + +func (c Client) AuthMethod() oidc.AuthMethod { + return oidc.AuthMethodNone +} + +func (c Client) ResponseTypes() []oidc.ResponseType { + return []oidc.ResponseType{oidc.ResponseTypeCode} +} + +func (c Client) GrantTypes() []oidc.GrantType { + return []oidc.GrantType{oidc.GrantTypeCode} +} + +func (c Client) LoginURL(authRequestID string) string { + if c.AuthRequest == nil { + return "" // we don't have a request, let's return nothing + } + + return c.AuthRequest.Backend.OIDCConfig.Issuer +} + +func (c Client) AccessTokenType() op.AccessTokenType { + return op.AccessTokenTypeJWT +} + +func (c Client) IDTokenLifetime() time.Duration { + return 1 * time.Hour +} + +func (c Client) DevMode() bool { + return true +} + +func (c Client) RestrictAdditionalIdTokenScopes() func(scopes []string) []string { + return func(scopes []string) []string { + return scopes + } +} + +func (c Client) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string { + return func(scopes []string) []string { + return scopes + } +} + +func (c Client) IsScopeAllowed(scope string) bool { + return true +} + +func (c Client) IDTokenUserinfoClaimsAssertion() bool { + return true +} + +func (c Client) ClockSkew() time.Duration { + return 0 +} diff --git a/polyculeconnect/internal/storage/local.go b/polyculeconnect/internal/storage/local.go new file mode 100644 index 0000000..c964712 --- /dev/null +++ b/polyculeconnect/internal/storage/local.go @@ -0,0 +1,4 @@ +package storage + +type LocalStorage struct { +} diff --git a/polyculeconnect/internal/storage/storage.go b/polyculeconnect/internal/storage/storage.go new file mode 100644 index 0000000..902c8a1 --- /dev/null +++ b/polyculeconnect/internal/storage/storage.go @@ -0,0 +1,185 @@ +package storage + +import ( + "context" + "errors" + "fmt" + "time" + + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" + "github.com/go-jose/go-jose/v4" + "github.com/google/uuid" + "github.com/zitadel/oidc/v3/pkg/oidc" + "github.com/zitadel/oidc/v3/pkg/op" +) + +func ErrNotImplemented(name string) error { + return fmt.Errorf("%s is not implemented", name) +} + +// Storage implements the Storage interface from zitadel/oidc/op +type Storage struct { + LocalStorage db.Storage +} + +/* +Auth storage interface +*/ +func (s *Storage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (op.AuthRequest, error) { + // validate that the connector is correct + backendName, ok := stringFromCtx(ctx, "backendName") + if !ok { + return nil, errors.New("no backend name provided") + } + selectedBackend, err := s.LocalStorage.BackendStorage().GetBackendByName(ctx, backendName) + if err != nil { + return nil, fmt.Errorf("failed to get backend: %w", err) + } + + var opReq model.AuthRequest + opReq.FromOIDCAuthRequest(req, selectedBackend.ID) + + if err := s.LocalStorage.AuthRequestStorage().CreateAuthRequest(ctx, opReq); err != nil { + return nil, fmt.Errorf("failed to save auth request: %w", err) + } + + return opReq, nil +} + +func (s *Storage) AuthRequestByID(ctx context.Context, requestID string) (op.AuthRequest, error) { + return nil, ErrNotImplemented("AuthRequestByID") +} + +func (s *Storage) AuthRequestByCode(ctx context.Context, requestCode string) (op.AuthRequest, error) { + return nil, ErrNotImplemented("AuthRequestByCode") +} + +func (s *Storage) SaveAuthCode(ctx context.Context, id string, code string) error { + return ErrNotImplemented("SaveAuthCode") +} + +func (s *Storage) DeleteAuthRequest(ctx context.Context, id string) error { + return ErrNotImplemented("DeleteAuthRequest") +} + +func (s *Storage) CreateAccessToken(ctx context.Context, req op.TokenRequest) (accessTokenID string, expiration time.Time, err error) { + return "", time.Time{}, ErrNotImplemented("CreateAccessToken") +} + +func (s *Storage) CreateAccessAndRefreshTokens(ctx context.Context, request op.TokenRequest, currentRefreshToken string) (accessTokenID string, newRefreshTokenID string, expiration time.Time, err error) { + return "", "", time.Time{}, ErrNotImplemented("CreateAccessAndRefreshTokens") +} + +func (s *Storage) TokenRequestByRefreshToken(ctx context.Context, refreshTokenID string) (op.RefreshTokenRequest, error) { + return nil, ErrNotImplemented("TokenRequestByRefreshToken") +} + +func (s *Storage) TerminateSession(ctx context.Context, userID string, clientID string) error { + return ErrNotImplemented("TerminateSession") +} + +func (s *Storage) RevokeToken(ctx context.Context, tokenOrTokenID string, userID string, clientID string) *oidc.Error { + return nil +} + +func (s *Storage) GetRefreshTokenInfo(ctx context.Context, clientID string, stoken string) (string, string, error) { + return "", "", ErrNotImplemented("GetRefreshTokenInfo") +} + +func (s *Storage) SigningKey(ctx context.Context) (op.SigningKey, error) { + return nil, ErrNotImplemented("SigningKey") +} + +func (s *Storage) SignatureAlgorithms(ctx context.Context) ([]jose.SignatureAlgorithm, error) { + return nil, ErrNotImplemented("SignatureAlgorithms") +} + +func (s *Storage) KeySet(ctx context.Context) ([]op.Key, error) { + return nil, ErrNotImplemented("KeySet") +} + +/* + OP storage +*/ + +func (s *Storage) getClientWithDetails(ctx context.Context, authRequestID uuid.UUID) (op.Client, error) { + authRequest, err := s.LocalStorage.AuthRequestStorage().GetAuthRequestByID(ctx, authRequestID) + if err != nil { + return nil, fmt.Errorf("failed to get authRequest from local storage: %w", err) + } + backend, err := s.LocalStorage.BackendStorage().GetBackendByID(ctx, authRequest.BackendID) + if err != nil { + return nil, fmt.Errorf("failed to get associated backend from local storage: %w", err) + } + client, err := s.LocalStorage.ClientStorage().GetClientByID(ctx, authRequest.ClientID) + if err != nil { + return nil, fmt.Errorf("failed to get associated client from local storage: %w", err) + } + + authRequest.Backend = backend + client.AuthRequest = authRequest + + return client, nil +} + +// We're cheating a bit here since we're using the authrequest to get its associated client +// but a request is always associated to a backend, and we really need both, so we have no +// choice here. I'll maybe need to have a more elegant solution later, but not choice for now +func (s *Storage) GetClientByClientID(ctx context.Context, id string) (op.Client, error) { + + authRequestID, err := uuid.Parse(id) + if err != nil { + // it's not a UUID, it means this was called using client_id, we just return the client without details + client, err := s.LocalStorage.ClientStorage().GetClientByID(ctx, id) + if err != nil { + return nil, fmt.Errorf("failed to get client %s from local storage: %w", id, err) + } + return client, nil + } + + // we have a UUID, it means we got a requestID, so we can get all details here + return s.getClientWithDetails(ctx, authRequestID) +} + +func (s *Storage) AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string) error { + return ErrNotImplemented("AuthorizeClientIDSecret") +} + +func (s *Storage) SetUserinfoFromScopes(ctx context.Context, userinfo *oidc.UserInfo, userID, clientID string, scopes []string) error { + return ErrNotImplemented("SetUserinfoFromScopes") +} + +func (s *Storage) SetUserinfoFromToken(ctx context.Context, userinfo *oidc.UserInfo, tokenID, subject, origin string) error { + return ErrNotImplemented("SetUserinfoFromToken") +} + +func (s *Storage) SetIntrospectionFromToken(ctx context.Context, userinfo *oidc.IntrospectionResponse, tokenID, subject, clientID string) error { + return ErrNotImplemented("SetIntrospectionFromToken") +} + +func (s *Storage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (map[string]interface{}, error) { + return nil, ErrNotImplemented("GetPrivateClaimsFromScopes") +} + +func (s *Storage) GetKeyByIDAndClientID(ctx context.Context, keyID, clientID string) (*jose.JSONWebKey, error) { + return nil, ErrNotImplemented("GetKeyByIDAndClientID") +} + +func (s *Storage) ValidateJWTProfileScopes(ctx context.Context, userID string, scopes []string) ([]string, error) { + return nil, ErrNotImplemented("ValidateJWTProfileScopes") +} + +func (s *Storage) Health(ctx context.Context) error { + return ErrNotImplemented("Health") +} + +func stringFromCtx(ctx context.Context, key string) (string, bool) { + rawVal := ctx.Value(key) + if rawVal == nil { + return "", false + } + + val, ok := rawVal.(string) + return val, ok +} diff --git a/polyculeconnect/logger/logger.go b/polyculeconnect/logger/logger.go index 31b8a0e..da777cf 100644 --- a/polyculeconnect/logger/logger.go +++ b/polyculeconnect/logger/logger.go @@ -1,10 +1,28 @@ package logger -import "github.com/sirupsen/logrus" +import ( + "fmt" -var L *logrus.Logger + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var L *zap.SugaredLogger + +func Init(level zap.AtomicLevel) { + conf := zap.Config{ + Level: level, + Encoding: "console", + OutputPaths: []string{"stdout"}, + ErrorOutputPaths: []string{"stderr"}, + EncoderConfig: zap.NewDevelopmentEncoderConfig(), + } + conf.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + + if l, err := conf.Build(); err != nil { + panic(fmt.Errorf("failed to init logger: %w", err)) + } else { + L = l.Sugar() + } -func Init(level logrus.Level) { - L = logrus.New() - L.SetLevel(level) } diff --git a/polyculeconnect/middlewares/middlewarechain.go b/polyculeconnect/middlewares/middlewarechain.go deleted file mode 100644 index f1eb3ea..0000000 --- a/polyculeconnect/middlewares/middlewarechain.go +++ /dev/null @@ -1,14 +0,0 @@ -package middlewares - -import ( - "net/http" - - "github.com/sirupsen/logrus" -) - -func WithLogger(handler http.Handler, l *logrus.Logger) http.Handler { - return &LoggerMiddleware{ - l: l, - h: handler, - } -} diff --git a/polyculeconnect/migrations/0_create_backend_table.down.sql b/polyculeconnect/migrations/0_create_backend_table.down.sql new file mode 100644 index 0000000..898fe6b --- /dev/null +++ b/polyculeconnect/migrations/0_create_backend_table.down.sql @@ -0,0 +1 @@ +DROP TABLE "backend"; \ No newline at end of file diff --git a/polyculeconnect/migrations/0_create_backend_table.up.sql b/polyculeconnect/migrations/0_create_backend_table.up.sql new file mode 100644 index 0000000..498fef0 --- /dev/null +++ b/polyculeconnect/migrations/0_create_backend_table.up.sql @@ -0,0 +1,8 @@ +CREATE TABLE "backend" ( + id TEXT NOT NULL PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + oidc_issuer TEXT NOT NULL, + oidc_client_id TEXT NOT NULL, + oidc_client_secret TEXT NOT NULL, + oidc_redirect_uri TEXT NOT NULL +); diff --git a/polyculeconnect/migrations/1_create_auth_request.down.sql b/polyculeconnect/migrations/1_create_auth_request.down.sql new file mode 100644 index 0000000..998bfa6 --- /dev/null +++ b/polyculeconnect/migrations/1_create_auth_request.down.sql @@ -0,0 +1 @@ +DROP TABLE "auth_request_2"; \ No newline at end of file diff --git a/polyculeconnect/migrations/1_create_auth_request.up.sql b/polyculeconnect/migrations/1_create_auth_request.up.sql new file mode 100644 index 0000000..534cadc --- /dev/null +++ b/polyculeconnect/migrations/1_create_auth_request.up.sql @@ -0,0 +1,11 @@ +CREATE TABLE "auth_request_2" ( + id TEXT NOT NULL PRIMARY KEY, + client_id TEXT NOT NULL, + backend_id TEXT NOT NULL, + scopes blob NOT NULL, -- list of strings, json-encoded + redirect_uri TEXT NOT NULL, + state TEXT NOT NULL, + nonce TEXT NOT NULL, + response_type TEXT NOT NULL, + CREATION_TIME timestamp NOT NULL +); \ No newline at end of file diff --git a/polyculeconnect/polyculeconnect.db b/polyculeconnect/polyculeconnect.db new file mode 100644 index 0000000..0cc1857 Binary files /dev/null and b/polyculeconnect/polyculeconnect.db differ diff --git a/polyculeconnect/server/server.go b/polyculeconnect/server/server.go index 84a8b5e..0785610 100644 --- a/polyculeconnect/server/server.go +++ b/polyculeconnect/server/server.go @@ -10,9 +10,9 @@ import ( "git.faercol.me/faercol/polyculeconnect/polyculeconnect/config" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/controller/ui" - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/middlewares" - dex_server "github.com/dexidp/dex/server" - "github.com/sirupsen/logrus" + "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/middlewares" + "github.com/zitadel/oidc/v3/pkg/op" + "go.uber.org/zap" ) type Server struct { @@ -24,7 +24,7 @@ type Server struct { address string handler *http.ServeMux controllers map[string]http.Handler - l *logrus.Logger + l *zap.SugaredLogger } func newUnixListener(sockPath string) (net.Listener, error) { @@ -42,7 +42,7 @@ func newUnixListener(sockPath string) (net.Listener, error) { return sock, nil } -func New(appConf *config.AppConfig, dexSrv *dex_server.Server, logger *logrus.Logger) (*Server, error) { +func New(appConf *config.AppConfig, oidcHandler *op.Provider, logger *zap.SugaredLogger) (*Server, error) { var listener net.Listener var addr string var err error @@ -65,7 +65,7 @@ func New(appConf *config.AppConfig, dexSrv *dex_server.Server, logger *logrus.Lo controllers := map[string]http.Handler{ ui.StaticRoute: middlewares.WithLogger(ui.NewStaticController(appConf.StaticDir), logger), - "/": middlewares.WithLogger(ui.NewIndexController(logger, dexSrv, appConf.StaticDir), logger), + "/": middlewares.WithLogger(ui.NewIndexController(logger, oidcHandler, appConf.StaticDir), logger), } m := http.NewServeMux() diff --git a/polyculeconnect/services/backend/backend.go b/polyculeconnect/services/backend/backend.go deleted file mode 100644 index 9f9d6f5..0000000 --- a/polyculeconnect/services/backend/backend.go +++ /dev/null @@ -1,123 +0,0 @@ -package backend - -import ( - "encoding/json" - "errors" - "fmt" - - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/connector" - "github.com/dexidp/dex/connector/oidc" - "github.com/dexidp/dex/storage" -) - -var ErrUnsupportedType = errors.New("unsupported connector type") - -type BackendConfig struct { - ID string - Name string - Issuer string - ClientID string - ClientSecret string - RedirectURI string -} - -func (bc *BackendConfig) OIDC() oidc.Config { - return oidc.Config{ - Issuer: bc.Issuer, - ClientID: bc.ClientID, - ClientSecret: bc.ClientSecret, - RedirectURI: bc.RedirectURI, - } -} - -func (bc *BackendConfig) Storage() (storage.Connector, error) { - oidcJSON, err := json.Marshal(bc.OIDC()) - if err != nil { - return storage.Connector{}, fmt.Errorf("failed to serialize oidc config: %w", err) - } - - return storage.Connector{ - ID: bc.ID, - Type: "oidc", - Name: bc.Name, - Config: oidcJSON, - }, nil -} - -func (bc *BackendConfig) FromConnector(connector storage.Connector) error { - var oidc oidc.Config - if connector.Type != "oidc" { - return ErrUnsupportedType - } - if err := json.Unmarshal(connector.Config, &oidc); err != nil { - return fmt.Errorf("invalid OIDC config: %w", err) - } - bc.ID = connector.ID - bc.Name = connector.Name - bc.ClientID = oidc.ClientID - bc.ClientSecret = oidc.ClientSecret - bc.Issuer = oidc.Issuer - bc.RedirectURI = oidc.RedirectURI - return nil -} - -type Service interface { - ListBackends() ([]BackendConfig, error) - GetBackend(id string) (BackendConfig, error) - AddBackend(config BackendConfig) error - RemoveBackend(id string) error -} - -type concreteBackendService struct { - s storage.Storage -} - -func (cbs *concreteBackendService) ListBackends() ([]BackendConfig, error) { - connectors, err := cbs.s.ListConnectors() - if err != nil { - return nil, fmt.Errorf("failed to get connectors from storage: %w", err) - } - var res []BackendConfig - for _, c := range connectors { - - // We know that this type is special, we don't want to use it at all here - if c.Type == connector.TypeRefuseAll { - continue - } - - var b BackendConfig - if err := b.FromConnector(c); err != nil { - return res, err - } - res = append(res, b) - } - return res, nil -} - -func (cbs *concreteBackendService) GetBackend(connectorID string) (BackendConfig, error) { - c, err := cbs.s.GetConnector(connectorID) - if err != nil { - return BackendConfig{}, fmt.Errorf("failed to get connector from storage: %w", err) - } - var res BackendConfig - if err := res.FromConnector(c); err != nil { - return BackendConfig{}, err - } - return res, nil -} - -func (cbs *concreteBackendService) AddBackend(config BackendConfig) error { - storageConf, err := config.Storage() - if err != nil { - return fmt.Errorf("failed to create storage configuration: %w", err) - } - return cbs.s.CreateConnector(storageConf) -} - -func (cbs *concreteBackendService) RemoveBackend(connectorID string) error { - return cbs.s.DeleteConnector(connectorID) -} - -func New(s storage.Storage) Service { - return &concreteBackendService{s} -} diff --git a/polyculeconnect/services/backend/backend_test.go b/polyculeconnect/services/backend/backend_test.go deleted file mode 100644 index 4fde675..0000000 --- a/polyculeconnect/services/backend/backend_test.go +++ /dev/null @@ -1,215 +0,0 @@ -package backend_test - -import ( - "encoding/json" - "fmt" - "testing" - - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/connector" - "git.faercol.me/faercol/polyculeconnect/polyculeconnect/services/backend" - "github.com/dexidp/dex/storage" - "github.com/dexidp/dex/storage/memory" - logt "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -const ( - testDomain string = "https://test.domain.com" - testClientID string = "this_is_an_id" - testClientSecret string = "this_is_a_secret" - testRedirectURI string = "http://127.0.0.1:5000/callback" - testConnectorName string = "Test connector" -) - -func generateConnector(id string) storage.Connector { - confJson := fmt.Sprintf(`{ - "issuer": "%s", - "clientID": "%s", - "clientSecret": "%s", - "redirectURI": "%s" -}`, testDomain, testClientID, testClientSecret, testRedirectURI) - storageConfig := storage.Connector{ - ID: id, - Name: testConnectorName, - Type: "oidc", - Config: []byte(confJson), - } - return storageConfig -} - -func generateConfig(id string) backend.BackendConfig { - return backend.BackendConfig{ - ID: id, - Name: testConnectorName, - Issuer: testDomain, - ClientID: testClientID, - ClientSecret: testClientSecret, - RedirectURI: testRedirectURI, - } -} - -func checkStrInMap(t *testing.T, vals map[string]interface{}, key, expected string) { - rawVal, ok := vals[key] - require.Truef(t, ok, "missing key %s", key) - strVal, ok := rawVal.(string) - require.Truef(t, ok, "invalid string format %v", rawVal) - assert.Equal(t, expected, strVal, "unexpected value") -} - -func initStorage(t *testing.T) storage.Storage { - logger, _ := logt.NewNullLogger() - s := memory.New(logger) - - require.NoError(t, s.CreateConnector(connector.RefuseAllConnectorConfig)) - require.NoError(t, s.CreateConnector(generateConnector("test0"))) - require.NoError(t, s.CreateConnector(generateConnector("test1"))) - - return s -} - -func TestBackendConfigFromConnector(t *testing.T) { - connector := generateConnector("test") - var bc backend.BackendConfig - require.NoError(t, bc.FromConnector(connector)) - - assert.Equal(t, testDomain, bc.Issuer) - assert.Equal(t, testClientID, bc.ClientID) - assert.Equal(t, testClientSecret, bc.ClientSecret) - assert.Equal(t, testRedirectURI, bc.RedirectURI) - assert.Equal(t, testConnectorName, bc.Name) - assert.Equal(t, "test", bc.ID) -} - -func TestBackendConfigInvalidType(t *testing.T) { - connector := generateConnector("test") - connector.Type = "test" - var bc backend.BackendConfig - assert.ErrorIs(t, bc.FromConnector(connector), backend.ErrUnsupportedType) -} - -func TestBackendConfigInvalidOIDCConfig(t *testing.T) { - connector := generateConnector("test") - connector.Config = []byte("toto") - var bc backend.BackendConfig - assert.ErrorContains(t, bc.FromConnector(connector), "invalid OIDC config") -} - -func TestOIDCConfigFromBackendConfig(t *testing.T) { - conf := generateConfig("test") - oidcConf := conf.OIDC() - - assert.Equal(t, testDomain, oidcConf.Issuer) - assert.Equal(t, testClientID, oidcConf.ClientID) - assert.Equal(t, testClientSecret, oidcConf.ClientSecret) - assert.Equal(t, testRedirectURI, oidcConf.RedirectURI) -} - -func TestConnectorConfigFromBackendConfig(t *testing.T) { - conf := generateConfig("test") - con, err := conf.Storage() - require.NoError(t, err) - - // The OIDC config is stored as JSON data, we just want the raw keys here - var oidcConf map[string]interface{} - require.NoError(t, json.Unmarshal(con.Config, &oidcConf)) - - assert.Equal(t, "oidc", con.Type) - assert.Equal(t, "test", con.ID) - assert.Equal(t, testConnectorName, con.Name) - checkStrInMap(t, oidcConf, "issuer", testDomain) - checkStrInMap(t, oidcConf, "clientID", testClientID) - checkStrInMap(t, oidcConf, "clientSecret", testClientSecret) - checkStrInMap(t, oidcConf, "redirectURI", testRedirectURI) -} - -func TestListBackendsEmpty(t *testing.T) { - logger, _ := logt.NewNullLogger() - s := memory.New(logger) - - // add the default refuse all connector, it should not be visible in the list - require.NoError(t, s.CreateConnector(connector.RefuseAllConnectorConfig)) - srv := backend.New(s) - - backends, err := srv.ListBackends() // empty list, and no error - require.NoError(t, err) - require.Len(t, backends, 0) -} - -func TestListBackendsNotEmpty(t *testing.T) { - s := initStorage(t) - srv := backend.New(s) - - backends, err := srv.ListBackends() // empty list, and no error - expectedIds := []string{"test0", "test1"} - require.NoError(t, err) - assert.Len(t, backends, 2) - for _, c := range backends { - assert.Contains(t, expectedIds, c.ID) - } -} - -func TestGetBackend(t *testing.T) { - s := initStorage(t) - srv := backend.New(s) - - t.Run("OK", func(t *testing.T) { - conf, err := srv.GetBackend("test0") - require.NoError(t, err) - assert.Equal(t, testDomain, conf.Issuer) - assert.Equal(t, testClientID, conf.ClientID) - assert.Equal(t, testClientSecret, conf.ClientSecret) - assert.Equal(t, testRedirectURI, conf.RedirectURI) - assert.Equal(t, testConnectorName, conf.Name) - assert.Equal(t, "test0", conf.ID) - }) - - t.Run("Not exist", func(t *testing.T) { - _, err := srv.GetBackend("toto") - assert.ErrorIs(t, err, storage.ErrNotFound) - }) - - t.Run("Invalid type", func(t *testing.T) { - _, err := srv.GetBackend("null") // null has a RefuseAll type, which is unsupported here - assert.ErrorIs(t, err, backend.ErrUnsupportedType) - }) -} - -func TestAddBackend(t *testing.T) { - s := initStorage(t) - srv := backend.New(s) - - t.Run("OK", func(t *testing.T) { - conf := generateConfig("test_add") - require.NoError(t, srv.AddBackend(conf)) - - var parsedConf backend.BackendConfig - storageConf, err := s.GetConnector("test_add") - require.NoError(t, err) - require.NoError(t, parsedConf.FromConnector(storageConf)) - assert.Equal(t, conf, parsedConf) - }) - - t.Run("Already exists", func(t *testing.T) { - require.ErrorIs(t, srv.AddBackend(generateConfig("test0")), storage.ErrAlreadyExists) - }) -} - -func TestRemoveBackend(t *testing.T) { - s := initStorage(t) - srv := backend.New(s) - - t.Run("OK", func(t *testing.T) { - require.NoError(t, srv.AddBackend(generateConfig("to_remove"))) - _, err := s.GetConnector("to_remove") - require.NoError(t, err) // no error means it's present - - require.NoError(t, srv.RemoveBackend("to_remove")) - _, err = s.GetConnector("to_remove") - assert.ErrorIs(t, err, storage.ErrNotFound) // means it's been deleted - }) - - t.Run("No present", func(t *testing.T) { - require.ErrorIs(t, srv.RemoveBackend("toto"), storage.ErrNotFound) - }) -}