diff --git a/changelog.md b/changelog.md index 8a264b7..3efaccf 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +### Changed +- use a session to transport data from the login to the consent screens +- implement skip of consent screen for existing consent +- adapt to Hydra 2.x + ## [0.2.1] - 2023-08-03 ### Changed - improve formatting and german translation of login page diff --git a/cmd/idp/main.go b/cmd/idp/main.go index 50a2ecd..c83b6b9 100644 --- a/cmd/idp/main.go +++ b/cmd/idp/main.go @@ -31,10 +31,11 @@ import ( "sync/atomic" "time" - "github.com/go-openapi/runtime/client" "github.com/gorilla/csrf" "github.com/knadh/koanf" - hydra "github.com/ory/hydra-client-go/client" + "github.com/knadh/koanf/parsers/toml" + "github.com/knadh/koanf/providers/confmap" + hydra "github.com/ory/hydra-client-go/v2" log "github.com/sirupsen/logrus" "code.cacert.org/cacert/oidc-idp/internal/handlers" @@ -51,6 +52,9 @@ const ( DefaultCSRFMaxAge = 600 httpsDefaultPort = 443 + + sessionKeyLength = 32 + sessionAuthKeyLength = 64 ) var ( @@ -90,16 +94,17 @@ func main() { logger.WithError(err).Fatal("could not add messages for i18n") } + sessionAuthKey, sessionEncKey := configureSessionParameters(config) + services.InitSessionStore(sessionAuthKey, sessionEncKey) + clientTransport, err := configureAdminClient(config) if err != nil { logger.WithError(err).Fatal("could not configure Hydra admin client") } - adminClient := hydra.New(clientTransport, nil) - - loginHandler := handlers.NewLoginHandler(logger, bundle, catalog, adminClient.Admin) - consentHandler := handlers.NewConsentHandler(logger, bundle, catalog, adminClient.Admin) - logoutHandler := handlers.NewLogoutHandler(logger, adminClient.Admin) + loginHandler := handlers.NewLoginHandler(logger, bundle, catalog, clientTransport.OAuth2Api) + consentHandler := handlers.NewConsentHandler(logger, bundle, catalog, clientTransport.OAuth2Api) + logoutHandler := handlers.NewLogoutHandler(logger, clientTransport.OAuth2Api) logoutSuccessHandler := handlers.NewLogoutSuccessHandler(logger, bundle, catalog) errorHandler := handlers.NewErrorHandler(logger, bundle, catalog) @@ -144,13 +149,20 @@ func main() { startServer(logger, config, handlerChain) } -func configureAdminClient(config *koanf.Koanf) (*client.Runtime, error) { +func configureAdminClient(config *koanf.Koanf) (*hydra.APIClient, error) { adminURL, err := url.Parse(config.MustString("admin.url")) if err != nil { return nil, fmt.Errorf("error parsing admin URL: %w", err) } - tlsClientConfig := &tls.Config{MinVersion: tls.VersionTLS12} + configuration := hydra.NewConfiguration() + configuration.Servers = []hydra.ServerConfiguration{ + { + URL: adminURL.String(), + }, + } + + tlsClientConfig := &tls.Config{MinVersion: tls.VersionTLS12, ServerName: adminURL.Hostname()} if config.Exists("api-client.rootCAs") { rootCAFile := config.MustString("api-client.rootCAs") @@ -166,15 +178,12 @@ func configureAdminClient(config *koanf.Koanf) (*client.Runtime, error) { } tlsClientTransport := &http.Transport{TLSClientConfig: tlsClientConfig} - httpClient := &http.Client{Transport: tlsClientTransport} - clientTransport := client.NewWithClient( - adminURL.Host, - adminURL.Path, - []string{adminURL.Scheme}, - httpClient, - ) - - return clientTransport, nil + + c := hydra.NewAPIClient(configuration) + + configuration.HTTPClient.Transport = tlsClientTransport + + return c, nil } func startServer(logger *log.Logger, config *koanf.Koanf, handlerChain http.Handler) { @@ -252,3 +261,43 @@ func publicAddress(serverName string, serverPort int) string { return fmt.Sprintf("https://%s/", serverName) } + +func configureSessionParameters(config *koanf.Koanf) ([]byte, []byte) { + sessionAuthKey, err := base64.StdEncoding.DecodeString(config.String("session.auth-key")) + if err != nil { + log.WithError(err).Fatal("could not decode session auth key") + } + + sessionEncKey, err := base64.StdEncoding.DecodeString(config.String("session.enc-key")) + if err != nil { + log.WithError(err).Fatal("could not decode session encryption key") + } + + generated := false + + if len(sessionAuthKey) != sessionAuthKeyLength { + sessionAuthKey = services.GenerateKey(sessionAuthKeyLength) + generated = true + } + + if len(sessionEncKey) != sessionKeyLength { + sessionEncKey = services.GenerateKey(sessionKeyLength) + generated = true + } + + if generated { + _ = config.Load(confmap.Provider(map[string]interface{}{ + "session.auth-key": sessionAuthKey, + "session.enc-key": sessionEncKey, + }, "."), nil) + + tomlData, err := config.Marshal(toml.Parser()) + if err != nil { + log.WithError(err).Fatal("could not encode session config") + } + + log.Infof("put the following in your resource_app.toml:\n%s", string(tomlData)) + } + + return sessionAuthKey, sessionEncKey +} diff --git a/go.mod b/go.mod index 62a378a..11e5c64 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.19 require ( github.com/BurntSushi/toml v1.3.2 - github.com/go-openapi/runtime v0.26.0 github.com/go-playground/form/v4 v4.2.1 github.com/gorilla/csrf v1.7.1 + github.com/gorilla/sessions v1.2.1 github.com/knadh/koanf v1.5.0 github.com/lestrrat-go/jwx v1.2.26 github.com/nicksnyder/go-i18n/v2 v2.2.1 - github.com/ory/hydra-client-go v1.10.6 + github.com/ory/hydra-client-go/v2 v2.1.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/pflag v1.0.5 github.com/yuin/goldmark v1.5.5 @@ -18,43 +18,25 @@ require ( ) require ( - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.4 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/strfmt v0.21.7 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/go-openapi/validate v0.22.1 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/gorilla/securecookie v1.1.1 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/oklog/ulid v1.3.1 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect - go.mongodb.org/mongo-driver v1.12.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/crypto v0.11.0 // indirect + golang.org/x/net v0.13.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sys v0.10.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/go.sum b/go.sum index be97b57..4f3d5ef 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -16,9 +14,6 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= @@ -40,7 +35,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -67,80 +61,12 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -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-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= -github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= -github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= -github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/form/v4 v4.2.1 h1:HjdRDKO0fftVMU5epjPW2SOREcZ6/wLUzEobqUGJuPw= github.com/go-playground/form/v4 v4.2.1/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -162,6 +88,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -169,20 +97,19 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/gorilla/csrf v1.7.1 h1:Ir3o2c1/Uzj6FBxMlAUB6SivgVMy1ONXwYgXn+/aHPE= github.com/gorilla/csrf v1.7.1/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= @@ -221,38 +148,27 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 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/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= @@ -266,13 +182,6 @@ github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDu github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -295,8 +204,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -306,20 +213,14 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA= github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/ory/hydra-client-go v1.10.6 h1:w+uPgePbmztyLzwxWxOF89E/AG6wZuWTteHILn57BoQ= -github.com/ory/hydra-client-go v1.10.6/go.mod h1:HK2SkwXHKFC2TxHd+Ll9Xq2kJIYTQf2JTkqiC+sKcuA= +github.com/ory/hydra-client-go/v2 v2.1.1 h1:3JatU9uFbw5XhF3lgPCas1l1Kok2v5Mq1p26zZwGHNg= +github.com/ory/hydra-client-go/v2 v2.1.1/go.mod h1:IiIwChp/9wRvPoyFQblqPvg78uVishCCrV9+/M7Pl34= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= @@ -351,24 +252,15 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -383,18 +275,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -404,30 +286,15 @@ github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5ta go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= -go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= @@ -449,6 +316,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -459,19 +327,20 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= 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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -488,9 +357,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -509,8 +376,6 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -533,7 +398,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 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= @@ -544,11 +408,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -563,6 +423,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -588,15 +450,12 @@ 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= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -608,8 +467,6 @@ 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-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/handlers/common.go b/internal/handlers/common.go new file mode 100644 index 0000000..b7ed3ba --- /dev/null +++ b/internal/handlers/common.go @@ -0,0 +1,38 @@ +/* +Copyright 2023 CAcert Inc. +SPDX-License-Identifier: Apache-2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handlers + +import ( + "fmt" + "net/http" + + "github.com/gorilla/sessions" + + "code.cacert.org/cacert/oidc-idp/internal/services" +) + +const sessionName = "idp_session" + +func GetSession(r *http.Request) (*sessions.Session, error) { + session, err := services.GetSessionStore().Get(r, sessionName) + if err != nil { + return nil, fmt.Errorf("could not get session") + } + + return session, nil +} diff --git a/internal/handlers/consent.go b/internal/handlers/consent.go index 031f72d..417803c 100644 --- a/internal/handlers/consent.go +++ b/internal/handlers/consent.go @@ -29,10 +29,10 @@ import ( "github.com/go-playground/form/v4" "github.com/gorilla/csrf" + "github.com/gorilla/sessions" "github.com/lestrrat-go/jwx/jwt/openid" "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/ory/hydra-client-go/client/admin" - hydra "github.com/ory/hydra-client-go/models" + client "github.com/ory/hydra-client-go/v2" log "github.com/sirupsen/logrus" "code.cacert.org/cacert/oidc-idp/internal/models" @@ -42,7 +42,7 @@ import ( ) type ConsentHandler struct { - adminClient admin.ClientService + adminClient client.OAuth2Api bundle *i18n.Bundle consentTemplate *template.Template logger *log.Logger @@ -71,8 +71,6 @@ const ( ScopeEmail = "email" ) -const OneDayInSeconds = 86400 - func init() { supportedScopes = make(map[string]*i18n.Message) supportedScopes[ScopeOpenID] = &i18n.Message{ @@ -125,80 +123,194 @@ func (h *ConsentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + session, err := GetSession(r) + if err != nil { + h.logger.WithError(err).Error("could get session for request") + + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + + return + } + switch r.Method { case http.MethodGet: - if err := h.renderConsentForm(w, r, consentData, requestedClaims, localizer); err != nil { - h.logger.WithError(err).Error("could not render consent form") + h.handleGet(w, r, consentData, requestedClaims, session, challenge, localizer) + case http.MethodPost: + h.handlePost(w, r, consentData, requestedClaims, session, challenge) + } +} + +func (h *ConsentHandler) handleGet( + w http.ResponseWriter, + r *http.Request, + consentData *client.OAuth2ConsentRequest, + requestedClaims *models.OIDCClaimsRequest, + session *sessions.Session, + challenge string, + localizer *i18n.Localizer, +) { + // Hydra has a previous session for this user and client + if consentData.GetSkip() { + consentRequest, err := h.handleExistingConsent(consentData, requestedClaims, session) + if err != nil { + h.logger.WithError(err).Error("could not handle existing consent") + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } - case http.MethodPost: - var consentInfo ConsentInformation - // validate input - decoder := form.NewDecoder() - if err := decoder.Decode(&consentInfo, r.Form); err != nil { - h.logger.WithError(err).Error("could not decode consent form") - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + err = h.acceptConsent(w, r, challenge, consentRequest) + if err != nil { + h.logger.WithError(err).Error("could not accept consent") - return + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } - if consentInfo.ConsentChecked { - sessionData, err := h.getSessionData(r, consentInfo, requestedClaims, consentData.Payload) - if err != nil { - h.logger.WithError(err).Error("could not get session data") - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } - return - } + if err := h.renderConsentForm(w, r, consentData, requestedClaims, localizer); err != nil { + h.logger.WithError(err).Error("could not render consent form") + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } +} - consentRequest, err := h.adminClient.AcceptConsentRequest( - admin.NewAcceptConsentRequestParams().WithConsentChallenge(challenge).WithBody( - &hydra.AcceptConsentRequest{ - GrantAccessTokenAudience: nil, - GrantScope: consentInfo.GrantedScopes, - HandledAt: hydra.NullTime(time.Now()), - Remember: true, - RememberFor: OneDayInSeconds, - Session: sessionData, - }).WithTimeout(TimeoutTen)) - if err != nil { - h.logger.WithError(err).Error("accept consent request failed") - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) +func (h *ConsentHandler) handlePost( + w http.ResponseWriter, + r *http.Request, + consentData *client.OAuth2ConsentRequest, + requestedClaims *models.OIDCClaimsRequest, + session *sessions.Session, + challenge string, +) { + var consentInfo ConsentInformation - return - } + // validate input + decoder := form.NewDecoder() + if err := decoder.Decode(&consentInfo, r.Form); err != nil { + h.logger.WithError(err).Error("could not decode consent form") + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - w.Header().Add("Location", *consentRequest.GetPayload().RedirectTo) - w.WriteHeader(http.StatusFound) + return + } - return + if consentInfo.ConsentChecked { + consentRequest, err := h.rememberNewConsent(consentData, consentInfo, requestedClaims, session) + if err != nil { + h.logger.WithError(err).Error("could not accept consent") + + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } - consentRequest, err := h.adminClient.RejectConsentRequest( - admin.NewRejectConsentRequestParams().WithConsentChallenge(challenge).WithBody( - &hydra.RejectRequest{})) + err = h.acceptConsent(w, r, challenge, consentRequest) if err != nil { - h.logger.WithError(err).Error("reject consent request failed") - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + h.logger.WithError(err).Error("could not accept consent") - return + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } - w.Header().Add("Location", *consentRequest.GetPayload().RedirectTo) - w.WriteHeader(http.StatusFound) + return + } + + consentRequest, response, err := h.adminClient.RejectOAuth2ConsentRequest( + r.Context(), + ).ConsentChallenge(challenge).Execute() + if err != nil { + h.logger.WithError(err).Error("reject consent request failed") + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + + return } + + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "reject_consent_request": consentRequest}, + ).Debug("received response for RejectOAuth2ConsentRequest") + + w.Header().Add("Location", consentRequest.GetRedirectTo()) + w.WriteHeader(http.StatusFound) +} + +func (h *ConsentHandler) rememberNewConsent( + consentData *client.OAuth2ConsentRequest, + consentInfo ConsentInformation, + requestedClaims *models.OIDCClaimsRequest, + session *sessions.Session, +) (*client.AcceptOAuth2ConsentRequest, error) { + sessionData, err := h.getSessionData( + consentData.GetRequestedScope(), + consentInfo.GrantedScopes, + consentInfo.SelectedClaims, + requestedClaims, + session, + ) + if err != nil { + return nil, fmt.Errorf("could not get session data: %w", err) + } + + request := client.NewAcceptOAuth2ConsentRequestWithDefaults() + request.SetRemember(true) + request.SetHandledAt(time.Now()) + request.SetGrantAccessTokenAudience(consentData.RequestedAccessTokenAudience) + request.SetGrantScope(consentInfo.GrantedScopes) + request.SetRememberFor(0) + request.SetSession(*sessionData) + + return request, nil +} + +func (h *ConsentHandler) acceptConsent( + w http.ResponseWriter, r *http.Request, challenge string, request *client.AcceptOAuth2ConsentRequest, +) error { + oAuth2RedirectTo, response, err := h.adminClient.AcceptOAuth2ConsentRequest( + r.Context(), + ).ConsentChallenge(challenge).AcceptOAuth2ConsentRequest(*request).Execute() + if err != nil { + return fmt.Errorf("accept consent request failed: %w", err) + } + + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "redirect_to": oAuth2RedirectTo}, + ).Debug("received response for AcceptOAuth2ConsentRequest") + + w.Header().Add("Location", oAuth2RedirectTo.GetRedirectTo()) + w.WriteHeader(http.StatusFound) + + return nil +} + +func (h *ConsentHandler) handleExistingConsent( + data *client.OAuth2ConsentRequest, + claims *models.OIDCClaimsRequest, + session *sessions.Session, +) (*client.AcceptOAuth2ConsentRequest, error) { + sessionData, err := h.getSessionData(data.GetRequestedScope(), + data.GetRequestedScope(), []string{}, claims, session) + if err != nil { + return nil, fmt.Errorf("could not get session data: %w", err) + } + + request := client.NewAcceptOAuth2ConsentRequestWithDefaults() + request.SetGrantScope(data.RequestedScope) + request.SetHandledAt(time.Now()) + request.SetGrantAccessTokenAudience(data.RequestedAccessTokenAudience) + request.SetSession(*sessionData) + + return request, nil } func (h *ConsentHandler) getRequestedConsentInformation(challenge string, r *http.Request) ( - *admin.GetConsentRequestOK, + *client.OAuth2ConsentRequest, *models.OIDCClaimsRequest, error, ) { - consentData, err := h.adminClient.GetConsentRequest( - admin.NewGetConsentRequestParams().WithConsentChallenge(challenge)) + consentRequest, response, err := h.adminClient.GetOAuth2ConsentRequest( + r.Context(), + ).ConsentChallenge(challenge).Execute() if err != nil { h.logger.WithError(err).Error("error getting consent information") @@ -214,12 +326,20 @@ func (h *ConsentHandler) getRequestedConsentInformation(challenge string, r *htt return nil, nil, fmt.Errorf("error getting consent information: %w", err) } + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "consent_request": consentRequest}, + ).Debug("response for GetOAuth2ConsentRequest") + var requestedClaims models.OIDCClaimsRequest - requestURL, err := url.Parse(consentData.Payload.RequestURL) + requestURLStr := consentRequest.GetRequestUrl() + + requestURL, err := url.Parse(requestURLStr) if err != nil { h.logger.WithError(err).WithField( - "request_url", consentData.Payload.RequestURL, + "request_url", requestURLStr, ).Warn("could not parse original request URL") } else { claimsParameter := requestURL.Query().Get("claims") @@ -234,13 +354,13 @@ func (h *ConsentHandler) getRequestedConsentInformation(challenge string, r *htt } } - return consentData, &requestedClaims, nil + return consentRequest, &requestedClaims, nil } func (h *ConsentHandler) renderConsentForm( w http.ResponseWriter, r *http.Request, - consentData *admin.GetConsentRequestOK, + consentRequest *client.OAuth2ConsentRequest, claims *models.OIDCClaimsRequest, localizer *i18n.Localizer, ) error { @@ -253,26 +373,26 @@ func (h *ConsentHandler) renderConsentForm( } // render consent form - client := consentData.GetPayload().Client + oAuth2Client := consentRequest.Client err := h.consentTemplate.Lookup("base").Execute(w, map[string]interface{}{ "Title": trans("TitleRequestConsent"), csrf.TemplateTag: csrf.TemplateField(r), "errors": map[string]string{}, - "client": client, - "requestedScope": h.mapRequestedScope(consentData.GetPayload().RequestedScope, localizer), + "client": oAuth2Client, + "requestedScope": h.mapRequestedScope(consentRequest.RequestedScope, localizer), "requestedClaims": h.mapRequestedClaims(claims, localizer), "LabelSubmit": trans("LabelSubmit"), "LabelConsent": trans("LabelConsent"), "IntroMoreInformation": template.HTML( //nolint:gosec trans("IntroConsentMoreInformation", map[string]interface{}{ - "client": client.ClientName, - "clientLink": client.ClientURI, + "client": oAuth2Client.GetClientName(), + "clientLink": oAuth2Client.GetClientUri(), })), "ClaimsInformation": template.HTML( //nolint:gosec trans("ClaimsInformation", nil)), "IntroConsentRequested": template.HTML( //nolint:gosec trans("IntroConsentRequested", map[string]interface{}{ - "client": client.ClientName, + "client": oAuth2Client.GetClientName(), })), }) @@ -289,7 +409,7 @@ type scopeWithLabel struct { } func (h *ConsentHandler) mapRequestedScope( - scope hydra.StringSlicePipeDelimiter, + scope []string, localizer *i18n.Localizer, ) []*scopeWithLabel { result := make([]*scopeWithLabel, 0) @@ -361,41 +481,43 @@ func (h *ConsentHandler) mapRequestedClaims( } func (h *ConsentHandler) getSessionData( - r *http.Request, - info ConsentInformation, + requestedScopes, + grantedScopes, + selectedClaims []string, claims *models.OIDCClaimsRequest, - payload *hydra.ConsentRequest, -) (*hydra.ConsentRequestSession, error) { - idTokenData := make(map[string]interface{}, 0) - accessTokenData := make(map[string]interface{}, 0) - - userInfo := h.GetUserInfoFromClientCertificate(r, payload.Subject) - - if err := h.fillTokenData(accessTokenData, payload.RequestedScope, claims, info, userInfo); err != nil { + session *sessions.Session, +) (*client.AcceptOAuth2ConsentRequestSession, error) { + idTokenData := make(map[string]interface{}) + + if err := h.fillTokenData( + idTokenData, + requestedScopes, + grantedScopes, + claims, + selectedClaims, + session.Values, + ); err != nil { return nil, err } - if err := h.fillTokenData(idTokenData, payload.RequestedScope, claims, info, userInfo); err != nil { - return nil, err - } + consentSession := client.NewAcceptOAuth2ConsentRequestSession() + consentSession.SetIdToken(idTokenData) - return &hydra.ConsentRequestSession{ - AccessToken: accessTokenData, - IDToken: idTokenData, - }, nil + return consentSession, nil } func (h *ConsentHandler) fillTokenData( m map[string]interface{}, - requestedScope hydra.StringSlicePipeDelimiter, + requestedScopes []string, + grantedScopes []string, claimsRequest *models.OIDCClaimsRequest, - consentInformation ConsentInformation, - userInfo *UserInfo, + selectedClaims []string, + sessionData map[interface{}]interface{}, ) error { - for _, scope := range requestedScope { + for _, scope := range requestedScopes { granted := false - for _, k := range consentInformation.GrantedScopes { + for _, k := range grantedScopes { if k == scope { granted = true @@ -412,8 +534,8 @@ func (h *ConsentHandler) fillTokenData( // email // OPTIONAL. This scope value requests access to the email and // email_verified Claims. - m[openid.EmailKey] = userInfo.Email - m[openid.EmailVerifiedKey] = userInfo.EmailVerified + m[openid.EmailKey] = sessionData[services.SessionEmail] + m[openid.EmailVerifiedKey] = true case ScopeProfile: // profile // OPTIONAL. This scope value requests access to the @@ -421,12 +543,12 @@ func (h *ConsentHandler) fillTokenData( // family_name, given_name, middle_name, nickname, // preferred_username, profile, picture, website, gender, // birthdate, zoneinfo, locale, and updated_at. - m[openid.NameKey] = userInfo.GetFullName() + m[openid.NameKey] = sessionData[services.SessionFullName] } } if userInfoClaims := claimsRequest.GetUserInfo(); userInfoClaims != nil { - err := h.parseUserInfoClaims(m, userInfoClaims, consentInformation) + err := h.parseUserInfoClaims(m, userInfoClaims, selectedClaims) if err != nil { return err } @@ -438,12 +560,12 @@ func (h *ConsentHandler) fillTokenData( func (h *ConsentHandler) parseUserInfoClaims( m map[string]interface{}, userInfoClaims *models.ClaimElement, - consentInformation ConsentInformation, + selectedClaims []string, ) error { for claimName, claim := range *userInfoClaims { granted := false - for _, k := range consentInformation.SelectedClaims { + for _, k := range selectedClaims { if k == claimName { granted = true @@ -478,45 +600,11 @@ func (h *ConsentHandler) parseUserInfoClaims( return nil } -func (h *ConsentHandler) GetUserInfoFromClientCertificate(r *http.Request, subject string) *UserInfo { - if r.TLS != nil && r.TLS.PeerCertificates != nil && len(r.TLS.PeerCertificates) > 0 { - firstCert := r.TLS.PeerCertificates[0] - - var verified bool - - for _, email := range firstCert.EmailAddresses { - h.logger.WithField( - "email", email, - ).Info("authenticated with client certificate for email address") - - if subject == email { - verified = true - } - } - - if !verified { - h.logger.WithField( - "subject", subject, - ).Warn("authentication attempt with a wrong certificate that did not contain the requested address") - - return nil - } - - return &UserInfo{ - Email: subject, - EmailVerified: verified, - CommonName: firstCert.Subject.CommonName, - } - } - - return nil -} - func NewConsentHandler( logger *log.Logger, bundle *i18n.Bundle, messageCatalog *services.MessageCatalog, - adminClient admin.ClientService, + adminClient client.OAuth2Api, ) *ConsentHandler { consentTemplate := template.Must( template.ParseFS( diff --git a/internal/handlers/login.go b/internal/handlers/login.go index d7fad65..07b8968 100644 --- a/internal/handlers/login.go +++ b/internal/handlers/login.go @@ -21,17 +21,14 @@ import ( "bytes" "context" "crypto/x509" - "errors" "fmt" "html/template" + "io" "net/http" - "strconv" - "time" "github.com/gorilla/csrf" "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/ory/hydra-client-go/client/admin" - hydra "github.com/ory/hydra-client-go/models" + client "github.com/ory/hydra-client-go/v2" log "github.com/sirupsen/logrus" "code.cacert.org/cacert/oidc-idp/internal/services" @@ -41,9 +38,10 @@ import ( type acrType string const ( - ClientCertificate acrType = "cert" // client certificate login - // ClientCertificateOTP acrType = "cert+otp" - // ClientCertificateToken acrType = "cert+token" + // ClientCertificate represents a client certificate login + ClientCertificate acrType = "urn:cacert:1fa:cert" + // ClientCertificateOTP acrType = "urn:cacert:2fa:cert+otp" + // ClientCertificateToken acrType = "urn:cacert:2fa:cert+token" ) type contextKey int @@ -60,10 +58,8 @@ const ( NoChallengeInRequest templateName = "no_challenge" ) -const TimeoutTen = 10 * time.Second - type LoginHandler struct { - adminClient admin.ClientService + adminClient client.OAuth2Api bundle *i18n.Bundle logger *log.Logger templates map[templateName]*template.Template @@ -90,7 +86,7 @@ func (h *LoginHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.logger.WithField("challenge", challenge).Debug("received login challenge") - certEmails := h.getEmailAddressesFromClientCertificate(r) + certFullName, certEmails := h.getDataFromClientCert(r) if certEmails == nil { h.renderNoEmailsInClientCertificate(w, localizer) @@ -101,7 +97,7 @@ func (h *LoginHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { h.handleGet(w, r, challenge, certEmails, localizer) } else { - h.handlePost(w, r, challenge, certEmails, localizer) + h.handlePost(w, r, challenge, certFullName, certEmails, localizer) } } @@ -112,37 +108,26 @@ func (h *LoginHandler) handleGet( certEmails []string, localizer *i18n.Localizer, ) { - loginRequest, err := h.adminClient.GetLoginRequest(admin.NewGetLoginRequestParams().WithLoginChallenge(challenge)) + oAuth2LoginRequest, response, err := h.adminClient.GetOAuth2LoginRequest( + r.Context(), + ).LoginChallenge(challenge).Execute() if err != nil { h.logger.WithError(err).WithField( "challenge", challenge, ).Warn("could not get login request for challenge") - var notFound *admin.GetLoginRequestNotFound - - if errors.As(err, ¬Found) { - w.WriteHeader(http.StatusNotFound) - - http.Error(w, notFound.GetPayload().ErrorDescription, http.StatusNotFound) - - return - } - - var gone *admin.GetLoginRequestGone - - if errors.As(err, &gone) { - w.Header().Set("Location", *gone.GetPayload().RedirectTo) - w.WriteHeader(http.StatusGone) - - return - } - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } - h.renderRequestForClientCert(w, r, certEmails, localizer, loginRequest) + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "login_request": oAuth2LoginRequest}, + ).Debug("got response for GetOAuth2LoginRequest") + + h.renderRequestForClientCert(w, r, certEmails, localizer, oAuth2LoginRequest) } type FlashMessage struct { @@ -154,11 +139,12 @@ func (h *LoginHandler) handlePost( w http.ResponseWriter, r *http.Request, challenge string, + certFullName string, certEmails []string, localizer *i18n.Localizer, ) { if r.FormValue("use-identity") != "accept" { - h.rejectLogin(w, challenge, localizer) + h.rejectLogin(w, r, challenge, localizer) return } @@ -177,7 +163,10 @@ func (h *LoginHandler) handlePost( } // perform certificate auth - h.logger.WithField("emails", certEmails).Info("will perform certificate authentication") + h.logger.WithFields(log.Fields{ + "emails": certEmails, + "full_name": certFullName, + }).Info("will perform certificate authentication") userID, err := h.performCertificateLogin(certEmails, r) if err != nil { @@ -187,32 +176,66 @@ func (h *LoginHandler) handlePost( return } + session, err := GetSession(r) + if err != nil { + h.logger.WithError(err).Error("could not perform certificate login") + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + + return + } + + session.Values[services.SessionFullName] = certFullName + session.Values[services.SessionEmail] = userID + session.Options.HttpOnly = true + session.Options.Secure = true + + if err = session.Save(r, w); err != nil { + h.logger.WithError(err).Error("could not save session") + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + + return + } + // finish login and redirect to target - loginRequest, err := h.adminClient.AcceptLoginRequest( - admin.NewAcceptLoginRequestParams().WithLoginChallenge(challenge).WithBody( - &hydra.AcceptLoginRequest{ - Acr: string(ClientCertificate), - Remember: true, - RememberFor: 0, - Subject: &userID, - }).WithTimeout(TimeoutTen)) + acceptRequest := client.NewAcceptOAuth2LoginRequest(userID) + acceptRequest.SetRemember(true) + acceptRequest.SetRememberFor(0) + acceptRequest.SetAcr(string(ClientCertificate)) + + loginRequest, response, err := h.adminClient.AcceptOAuth2LoginRequest( + r.Context(), + ).LoginChallenge(challenge).AcceptOAuth2LoginRequest(*acceptRequest).Execute() if err != nil { h.logger.WithError(err).Error("error getting login request") - h.fillAcceptLoginRequestErrorBucket(r, err) + // h.fillAcceptLoginRequestErrorBucket(r, err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } - w.Header().Add("Location", *loginRequest.GetPayload().RedirectTo) + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "accept_login_request": loginRequest}, + ).Debug("got response for AcceptOAuth2LoginRequest") + + if h.logger.IsLevelEnabled(log.TraceLevel) { + if rb, err := io.ReadAll(response.Body); err == nil { + h.logger.WithField("response_body", rb).Trace("response body from Hydra") + } + } + + w.Header().Add("Location", loginRequest.GetRedirectTo()) w.WriteHeader(http.StatusFound) } +/* func (h *LoginHandler) fillAcceptLoginRequestErrorBucket(r *http.Request, err error) { if errorBucket := GetErrorBucket(r); errorBucket != nil { var ( errorDetails *ErrorDetails - acceptLoginRequestNotFound *admin.AcceptLoginRequestNotFound + acceptLoginRequestNotFound *client.AcceptLoginRequestNotFound ) if errors.As(err, &acceptLoginRequestNotFound) { @@ -235,18 +258,22 @@ func (h *LoginHandler) fillAcceptLoginRequestErrorBucket(r *http.Request, err er errorBucket.AddError(errorDetails) } } +*/ -func (h *LoginHandler) rejectLogin(w http.ResponseWriter, challenge string, localizer *i18n.Localizer) { - const Ten = 10 * time.Second - - rejectLoginRequest, err := h.adminClient.RejectLoginRequest( - admin.NewRejectLoginRequestParams().WithLoginChallenge(challenge).WithBody( - &hydra.RejectRequest{ - ErrorDescription: h.messageCatalog.LookupMessage("LoginDeniedByUser", nil, localizer), - ErrorHint: h.messageCatalog.LookupMessage("HintChooseAnIdentityForAuthentication", nil, localizer), - StatusCode: http.StatusForbidden, - }, - ).WithTimeout(Ten)) +func (h *LoginHandler) rejectLogin( + w http.ResponseWriter, + r *http.Request, + challenge string, + localizer *i18n.Localizer, +) { + rejectRequest := client.NewRejectOAuth2RequestWithDefaults() + rejectRequest.SetErrorDescription(h.messageCatalog.LookupMessage("LoginDeniedByUser", nil, localizer)) + rejectRequest.SetErrorHint(h.messageCatalog.LookupMessage("HintChooseAnIdentityForAuthentication", nil, localizer)) + rejectRequest.SetStatusCode(http.StatusForbidden) + + rejectLoginRequest, response, err := h.adminClient.RejectOAuth2LoginRequest( + r.Context(), + ).LoginChallenge(challenge).RejectOAuth2Request(*rejectRequest).Execute() if err != nil { h.logger.WithError(err).Error("error getting reject login request") http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) @@ -254,16 +281,22 @@ func (h *LoginHandler) rejectLogin(w http.ResponseWriter, challenge string, loca return } - w.Header().Set("Location", *rejectLoginRequest.GetPayload().RedirectTo) + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "reject_login_request": rejectLoginRequest}, + ).Debug("go response for RejectOAuth2LoginRequest") + + w.Header().Set("Location", rejectLoginRequest.GetRedirectTo()) w.WriteHeader(http.StatusFound) } -func (h *LoginHandler) getEmailAddressesFromClientCertificate(r *http.Request) []string { +func (h *LoginHandler) getDataFromClientCert(r *http.Request) (string, []string) { if r.TLS != nil && r.TLS.PeerCertificates != nil && len(r.TLS.PeerCertificates) > 0 { firstCert := r.TLS.PeerCertificates[0] if !isClientCertificate(firstCert) { - return nil + return "", nil } for _, email := range firstCert.EmailAddresses { @@ -272,10 +305,10 @@ func (h *LoginHandler) getEmailAddressesFromClientCertificate(r *http.Request) [ ).Info("authenticated with a client certificate for email address") } - return firstCert.EmailAddresses + return firstCert.Subject.CommonName, firstCert.EmailAddresses } - return nil + return "", nil } func isClientCertificate(cert *x509.Certificate) bool { @@ -293,7 +326,7 @@ func (h *LoginHandler) renderRequestForClientCert( r *http.Request, emails []string, localizer *i18n.Localizer, - loginRequest *admin.GetLoginRequestOK, + loginRequest *client.OAuth2LoginRequest, ) { msg := h.messageCatalog.LookupMessage msgPlural := h.messageCatalog.LookupMessagePlural @@ -306,7 +339,7 @@ func (h *LoginHandler) renderRequestForClientCert( csrf.TemplateTag: csrf.TemplateField(r), "IntroText": template.HTML(msgMarkdown( //nolint:gosec "CertLoginIntroText", - map[string]interface{}{"ClientName": loginRequest.GetPayload().Client.ClientName}, + map[string]interface{}{"ClientName": loginRequest.Client.ClientName}, localizer, )), "EmailChoiceText": msgPlural("EmailChoiceText", nil, localizer, len(emails)), @@ -375,7 +408,7 @@ func NewLoginHandler( logger *log.Logger, bundle *i18n.Bundle, messageCatalog *services.MessageCatalog, - adminClient admin.ClientService, + adminClient client.OAuth2Api, ) *LoginHandler { return &LoginHandler{ adminClient: adminClient, diff --git a/internal/handlers/logout.go b/internal/handlers/logout.go index 711740f..4bbcc88 100644 --- a/internal/handlers/logout.go +++ b/internal/handlers/logout.go @@ -21,10 +21,9 @@ import ( "bytes" "html/template" "net/http" - "time" "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/ory/hydra-client-go/client/admin" + client "github.com/ory/hydra-client-go/v2" log "github.com/sirupsen/logrus" "code.cacert.org/cacert/oidc-idp/internal/services" @@ -32,18 +31,17 @@ import ( ) type LogoutHandler struct { - adminClient admin.ClientService + adminClient client.OAuth2Api logger *log.Logger } func (h *LogoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - const Ten = 10 * time.Second - challenge := r.URL.Query().Get("logout_challenge") h.logger.WithField("challenge", challenge).Debug("received logout challenge") - logoutRequest, err := h.adminClient.GetLogoutRequest( - admin.NewGetLogoutRequestParams().WithLogoutChallenge(challenge).WithTimeout(Ten)) + logoutRequest, response, err := h.adminClient.GetOAuth2LogoutRequest( + r.Context(), + ).LogoutChallenge(challenge).Execute() if err != nil { h.logger.WithError(err).Error("error getting logout requests") http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) @@ -51,20 +49,31 @@ func (h *LogoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - h.logger.WithField("logout_request", logoutRequest.Payload).Debug("received logout request") + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "logout_request": logoutRequest}, + ).Debug("got response for GetOAuth2LogoutRequest") - acceptLogoutRequest, err := h.adminClient.AcceptLogoutRequest( - admin.NewAcceptLogoutRequestParams().WithLogoutChallenge(challenge)) + acceptLogoutRequest, response, err := h.adminClient.AcceptOAuth2LogoutRequest( + r.Context(), + ).LogoutChallenge(challenge).Execute() if err != nil { h.logger.WithError(err).Error("accept logout request failed") http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } - w.Header().Set("Location", *acceptLogoutRequest.GetPayload().RedirectTo) + defer func() { _ = response.Body.Close() }() + + h.logger.WithFields( + log.Fields{"response": response.Status, "accept_logout_request": acceptLogoutRequest}, + ).Debug("got response for AcceptOAuth2LogoutRequest") + + w.Header().Set("Location", acceptLogoutRequest.GetRedirectTo()) w.WriteHeader(http.StatusFound) } -func NewLogoutHandler(logger *log.Logger, adminClient admin.ClientService) *LogoutHandler { +func NewLogoutHandler(logger *log.Logger, adminClient client.OAuth2Api) *LogoutHandler { return &LogoutHandler{ logger: logger, adminClient: adminClient, diff --git a/internal/services/security.go b/internal/services/security.go new file mode 100644 index 0000000..f0ab0ae --- /dev/null +++ b/internal/services/security.go @@ -0,0 +1,39 @@ +/* +Copyright 2023 CAcert Inc. +SPDX-License-Identifier: Apache-2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package services + +import ( + "crypto/rand" + + log "github.com/sirupsen/logrus" +) + +func GenerateKey(length int) []byte { + key := make([]byte, length) + + read, err := rand.Read(key) + if err != nil { + log.WithError(err).Fatal("could not generate key") + } + + if read != length { + log.WithFields(log.Fields{"read": read, "expected": length}).Fatal("read unexpected number of bytes") + } + + return key +} diff --git a/internal/services/session.go b/internal/services/session.go new file mode 100644 index 0000000..a6522d6 --- /dev/null +++ b/internal/services/session.go @@ -0,0 +1,37 @@ +/* +Copyright 2023 CAcert Inc. +SPDX-License-Identifier: Apache-2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package services + +import ( + "github.com/gorilla/sessions" +) + +var store *sessions.CookieStore + +const ( + SessionFullName = iota + SessionEmail +) + +func InitSessionStore(keys ...[]byte) { + store = sessions.NewCookieStore(keys...) +} + +func GetSessionStore() *sessions.CookieStore { + return store +} diff --git a/ui/templates/consent.gohtml b/ui/templates/consent.gohtml index 8b6d052..e0c81a4 100644 --- a/ui/templates/consent.gohtml +++ b/ui/templates/consent.gohtml @@ -2,9 +2,9 @@