Update all deps to latest where possible, bump Kube deps to v0.23.1
Highlights from this dep bump: 1. Made a copy of the v0.4.0 github.com/go-logr/stdr implementation for use in tests. We must bump this dep as Kube code uses a newer version now. We would have to rewrite hundreds of test log assertions without this copy. 2. Use github.com/felixge/httpsnoop to undo the changes made by ory/fosite#636 for CLI based login flows. This is required for backwards compatibility with older versions of our CLI. A separate change after this will update the CLI to be more flexible (it is purposefully not part of this change to confirm that we did not break anything). For all browser login flows, we now redirect using http.StatusSeeOther instead of http.StatusFound. 3. Drop plog.RemoveKlogGlobalFlags as klog no longer mutates global process flags 4. Only bump github.com/ory/x to v0.0.297 instead of the latest v0.0.321 because v0.0.298+ pulls in a newer version of go.opentelemetry.io/otel/semconv which breaks k8s.io/apiserver. We should update k8s.io/apiserver to use the newer code. 5. Migrate all code from k8s.io/apimachinery/pkg/util/clock to k8s.io/utils/clock and k8s.io/utils/clock/testing 6. Delete testutil.NewDeleteOptionsRecorder and migrate to the new kubetesting.NewDeleteActionWithOptions 7. Updated ExpectedAuthorizeCodeSessionJSONFromFuzzing caused by fosite's new rotated_secrets OAuth client field. This new field is currently not relevant to us as we have no private clients. Signed-off-by: Monis Khan <mok@vmware.com>
This commit is contained in:
parent
69d5951296
commit
9599ffcfb9
@ -2850,7 +2850,7 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
})
|
||||
issuerEndpointPtr = &issuerEndpoint
|
||||
|
||||
testLog := testlogger.New(t)
|
||||
testLog := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
cmd := kubeconfigCommand(kubeconfigDeps{
|
||||
getPathToSelf: func() (string, error) {
|
||||
if tt.getPathToSelfErr != nil {
|
||||
@ -2876,7 +2876,7 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}
|
||||
return fake, nil
|
||||
},
|
||||
log: testLog,
|
||||
log: testLog.Logger,
|
||||
})
|
||||
require.NotNil(t, cmd)
|
||||
|
||||
|
@ -358,8 +358,8 @@ func TestLoginOIDCCommand(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testLogger := testlogger.New(t)
|
||||
klog.SetLogger(testLogger)
|
||||
testLogger := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
klog.SetLogger(testLogger.Logger)
|
||||
var (
|
||||
gotOptions []oidcclient.Option
|
||||
)
|
||||
|
@ -165,8 +165,8 @@ func TestLoginStaticCommand(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testLogger := testlogger.New(t)
|
||||
klog.SetLogger(testLogger)
|
||||
testLogger := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
klog.SetLogger(testLogger.Logger)
|
||||
cmd := staticLoginCommand(staticLoginDeps{
|
||||
lookupEnv: func(s string) (string, bool) {
|
||||
v, ok := tt.env[s]
|
||||
|
@ -7,8 +7,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
//nolint: gochecknoglobals
|
||||
@ -19,12 +17,6 @@ var rootCmd = &cobra.Command{
|
||||
SilenceUsage: true, // do not print usage message when commands fail
|
||||
}
|
||||
|
||||
//nolint: gochecknoinits
|
||||
func init() {
|
||||
// We don't want klog flags showing up in our CLI.
|
||||
plog.RemoveKlogGlobalFlags()
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
|
136
go.mod
136
go.mod
@ -17,153 +17,161 @@ go 1.17
|
||||
// As long as it does, we probably need to keep this replace directive.
|
||||
replace github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1
|
||||
|
||||
// bumping github.com/ory/x to higher than v0.0.297 breaks k8s.io/apiserver via go.opentelemetry.io/otel/semconv
|
||||
// force the use of an old version for now as it seems to allow a newer ory/x without breaking the apiserver lib.
|
||||
replace (
|
||||
go.opentelemetry.io/otel => go.opentelemetry.io/otel v0.20.0
|
||||
go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v0.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1
|
||||
github.com/coreos/go-oidc/v3 v3.0.0
|
||||
github.com/creack/pty v1.1.14
|
||||
github.com/coreos/go-oidc/v3 v3.1.0
|
||||
github.com/creack/pty v1.1.17
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/felixge/httpsnoop v1.0.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.1
|
||||
github.com/go-logr/logr v0.4.0
|
||||
github.com/go-logr/stdr v0.4.0
|
||||
github.com/go-logr/logr v1.2.2
|
||||
github.com/go-logr/stdr v1.2.2
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.5.6
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/ory/fosite v0.40.2
|
||||
github.com/ory/x v0.0.212
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
|
||||
github.com/ory/fosite v0.41.0
|
||||
github.com/ory/x v0.0.321
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sclevine/agouti v3.0.0+incompatible
|
||||
github.com/sclevine/spec v1.4.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/tdewolff/minify/v2 v2.9.21
|
||||
go.uber.org/atomic v1.7.0
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
|
||||
github.com/tdewolff/minify/v2 v2.9.24
|
||||
go.uber.org/atomic v1.9.0
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
golang.org/x/text v0.3.6
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
k8s.io/api v0.22.2
|
||||
k8s.io/apiextensions-apiserver v0.22.2
|
||||
k8s.io/apimachinery v0.22.2
|
||||
k8s.io/apiserver v0.22.2
|
||||
k8s.io/client-go v0.22.2
|
||||
k8s.io/component-base v0.22.2
|
||||
k8s.io/gengo v0.0.0-20210203185629-de9496dff47b
|
||||
k8s.io/klog/v2 v2.10.0
|
||||
k8s.io/kube-aggregator v0.22.1
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
k8s.io/api v0.23.1
|
||||
k8s.io/apiextensions-apiserver v0.23.1
|
||||
k8s.io/apimachinery v0.23.1
|
||||
k8s.io/apiserver v0.23.1
|
||||
k8s.io/client-go v0.23.1
|
||||
k8s.io/component-base v0.23.1
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185
|
||||
k8s.io/klog/v2 v2.30.0
|
||||
k8s.io/kube-aggregator v0.23.1
|
||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.81.0 // indirect
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.5 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/goveralls v0.0.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/goveralls v0.0.11 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ory/go-acc v0.2.6 // indirect
|
||||
github.com/ory/go-convenience v0.1.0 // indirect
|
||||
github.com/ory/viper v1.7.5 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.3.2-0.20200723214538-8d17101741c8 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.5.19 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.5.26 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
|
||||
go.opentelemetry.io/contrib v0.20.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel v1.0.1 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.0.1 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.17.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
|
||||
go.uber.org/zap v1.19.0 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
golang.org/x/tools v0.1.2 // indirect
|
||||
golang.org/x/tools v0.1.8 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||
google.golang.org/grpc v1.38.0 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.42.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
)
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||
@ -211,7 +212,7 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
||||
}
|
||||
|
||||
// wire up a fake audit backend at the metadata level so we can preserve the original user during nested impersonation
|
||||
serverConfig.AuditPolicyChecker = policy.FakeChecker(auditinternal.LevelMetadata, nil)
|
||||
serverConfig.AuditPolicyRuleEvaluator = policy.NewFakePolicyRuleEvaluator(auditinternal.LevelMetadata, nil)
|
||||
serverConfig.AuditBackend = &auditfake.Backend{}
|
||||
|
||||
// Probe the API server to figure out if anonymous auth is enabled.
|
||||
@ -511,7 +512,7 @@ func newImpersonationReverseProxyFunc(restConfig *rest.Config) (func(*genericapi
|
||||
return
|
||||
}
|
||||
|
||||
ae := request.AuditEventFrom(r.Context())
|
||||
ae := audit.AuditEventFrom(r.Context())
|
||||
if ae == nil {
|
||||
plog.Warning("aggregated API server logic did not set audit event but it is always supposed to do so",
|
||||
"url", r.URL.String(),
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
@ -712,8 +713,8 @@ func TestImpersonator(t *testing.T) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
||||
case "/apis/flowcontrol.apiserver.k8s.io/v1beta1/prioritylevelconfigurations",
|
||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta1/flowschemas":
|
||||
case "/apis/flowcontrol.apiserver.k8s.io/v1beta2/prioritylevelconfigurations",
|
||||
"/apis/flowcontrol.apiserver.k8s.io/v1beta2/flowschemas":
|
||||
// ignore requests related to priority and fairness logic
|
||||
require.Equal(t, http.MethodGet, r.Method)
|
||||
http.NotFound(w, r)
|
||||
@ -1125,7 +1126,7 @@ func TestImpersonatorHTTPHandler(t *testing.T) {
|
||||
Groups: testGroups,
|
||||
Extra: testExtra,
|
||||
}, nil, "")
|
||||
ctx := request.WithAuditEvent(req.Context(), nil)
|
||||
ctx := audit.WithAuditContext(req.Context(), nil)
|
||||
req = req.WithContext(ctx)
|
||||
return req
|
||||
}(),
|
||||
@ -1880,7 +1881,7 @@ func newRequest(t *testing.T, h http.Header, userInfo user.Info, event *auditint
|
||||
if event != nil {
|
||||
ae = event
|
||||
}
|
||||
ctx = request.WithAuditEvent(ctx, ae)
|
||||
ctx = audit.WithAuditContext(ctx, &audit.AuditContext{Event: ae})
|
||||
|
||||
reqInfo := &request.RequestInfo{
|
||||
IsResourceRequest: false,
|
||||
|
@ -35,7 +35,6 @@ import (
|
||||
"go.pinniped.dev/internal/here"
|
||||
"go.pinniped.dev/internal/issuer"
|
||||
"go.pinniped.dev/internal/kubeclient"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/registry/credentialrequest"
|
||||
)
|
||||
|
||||
@ -96,8 +95,6 @@ func addCommandlineFlagsToCommand(cmd *cobra.Command, app *App) {
|
||||
"/etc/podinfo",
|
||||
"path to Downward API volume mount",
|
||||
)
|
||||
|
||||
plog.RemoveKlogGlobalFlags()
|
||||
}
|
||||
|
||||
// Boot the aggregated API server, which will in turn boot the controllers.
|
||||
|
@ -251,13 +251,10 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
0,
|
||||
)
|
||||
|
||||
opts := &[]metav1.DeleteOptions{}
|
||||
trackDeleteClient := testutil.NewDeleteOptionsRecorder(kubeAPIClient, opts)
|
||||
|
||||
c := NewCertsExpirerController(
|
||||
namespace,
|
||||
certsSecretResourceName,
|
||||
trackDeleteClient,
|
||||
kubeAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
test.renewBefore,
|
||||
@ -281,7 +278,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
if test.wantDelete {
|
||||
exActions = append(
|
||||
exActions,
|
||||
kubetesting.NewDeleteAction(
|
||||
kubetesting.NewDeleteActionWithOptions(
|
||||
schema.GroupVersionResource{
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
@ -289,18 +286,12 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
},
|
||||
namespace,
|
||||
name,
|
||||
testutil.NewPreconditions(testUID, testRV),
|
||||
),
|
||||
)
|
||||
}
|
||||
acActions := kubeAPIClient.Actions()
|
||||
require.Equal(t, exActions, acActions)
|
||||
|
||||
if test.wantDelete {
|
||||
require.Len(t, *opts, 1)
|
||||
require.Equal(t, testutil.NewPreconditions(testUID, testRV), (*opts)[0])
|
||||
} else {
|
||||
require.Len(t, *opts, 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -143,11 +143,11 @@ func TestController(t *testing.T) {
|
||||
if tt.initialCache != nil {
|
||||
tt.initialCache(t, cache)
|
||||
}
|
||||
testLog := testlogger.New(t)
|
||||
testLog := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
|
||||
webhooks := informers.Authentication().V1alpha1().WebhookAuthenticators()
|
||||
jwtAuthenticators := informers.Authentication().V1alpha1().JWTAuthenticators()
|
||||
controller := New(cache, webhooks, jwtAuthenticators, testLog)
|
||||
controller := New(cache, webhooks, jwtAuthenticators, testLog.Logger)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
@ -318,13 +318,13 @@ func TestController(t *testing.T) {
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.jwtAuthenticators...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := authncache.New()
|
||||
testLog := testlogger.New(t)
|
||||
testLog := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
|
||||
if tt.cache != nil {
|
||||
tt.cache(t, cache, tt.wantClose)
|
||||
}
|
||||
|
||||
controller := New(cache, informers.Authentication().V1alpha1().JWTAuthenticators(), testLog)
|
||||
controller := New(cache, informers.Authentication().V1alpha1().JWTAuthenticators(), testLog.Logger)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
@ -88,9 +88,9 @@ func TestController(t *testing.T) {
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.webhooks...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := authncache.New()
|
||||
testLog := testlogger.New(t)
|
||||
testLog := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
|
||||
controller := New(cache, informers.Authentication().V1alpha1().WebhookAuthenticators(), testLog)
|
||||
controller := New(cache, informers.Authentication().V1alpha1().WebhookAuthenticators(), testLog.Logger)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||
|
@ -29,12 +29,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
|
||||
@ -95,7 +94,7 @@ func TestImpersonatorConfigControllerOptions(t *testing.T) {
|
||||
nil,
|
||||
caSignerName,
|
||||
nil,
|
||||
testLog,
|
||||
testLog.Logger,
|
||||
)
|
||||
credIssuerInformerFilter = observableWithInformerOption.GetFilterForInformer(credIssuerInformer)
|
||||
servicesInformerFilter = observableWithInformerOption.GetFilterForInformer(servicesInformer)
|
||||
@ -270,8 +269,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
|
||||
var subject controllerlib.Controller
|
||||
var kubeAPIClient *kubernetesfake.Clientset
|
||||
var deleteOptions *[]metav1.DeleteOptions
|
||||
var deleteOptionsRecorder kubernetes.Interface
|
||||
var pinnipedAPIClient *pinnipedfake.Clientset
|
||||
var pinnipedInformerClient *pinnipedfake.Clientset
|
||||
var pinnipedInformers pinnipedinformers.SharedInformerFactory
|
||||
@ -550,7 +547,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
subject = NewImpersonatorConfigController(
|
||||
installedInNamespace,
|
||||
credentialIssuerResourceName,
|
||||
deleteOptionsRecorder,
|
||||
kubeAPIClient,
|
||||
pinnipedAPIClient,
|
||||
pinnipedInformers.Config().V1alpha1().CredentialIssuers(),
|
||||
kubeInformers.Core().V1().Services(),
|
||||
@ -562,11 +559,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
tlsSecretName,
|
||||
caSecretName,
|
||||
labels,
|
||||
clock.NewFakeClock(frozenNow),
|
||||
clocktesting.NewFakeClock(frozenNow),
|
||||
impersonatorFunc,
|
||||
caSignerName,
|
||||
signingCertProvider,
|
||||
testLog,
|
||||
testLog.Logger,
|
||||
)
|
||||
controllerlib.TestWrap(t, subject, func(syncer controllerlib.Syncer) controllerlib.Syncer {
|
||||
tlsServingCertDynamicCertProvider = syncer.(*impersonatorConfigController).tlsServingCertDynamicCertProvider
|
||||
@ -1032,10 +1029,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
r.Equal("secrets", deleteAction.GetResource().Resource)
|
||||
|
||||
// validate that we set delete preconditions correctly
|
||||
r.NotEmpty(*deleteOptions)
|
||||
for _, opt := range *deleteOptions {
|
||||
r.Equal(testutil.NewPreconditions("uid-1234", "rv-5678"), opt)
|
||||
}
|
||||
r.Equal(testutil.NewPreconditions("uid-1234", "rv-5678"), deleteAction.GetDeleteOptions())
|
||||
}
|
||||
|
||||
var requireCASecretWasCreated = func(action coretesting.Action) []byte {
|
||||
@ -1114,8 +1108,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
kubeinformers.WithNamespace(installedInNamespace),
|
||||
)
|
||||
kubeAPIClient = kubernetesfake.NewSimpleClientset()
|
||||
deleteOptions = &[]metav1.DeleteOptions{}
|
||||
deleteOptionsRecorder = testutil.NewDeleteOptionsRecorder(kubeAPIClient, deleteOptions)
|
||||
pinnipedAPIClient = pinnipedfake.NewSimpleClientset()
|
||||
frozenNow = time.Date(2021, time.March, 2, 7, 42, 0, 0, time.Local)
|
||||
signingCertProvider = dynamiccert.NewCA(name)
|
||||
|
@ -23,13 +23,13 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
appsv1informers "k8s.io/client-go/informers/apps/v1"
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/klog/v2/klogr"
|
||||
"k8s.io/utils/clock"
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||
|
@ -20,11 +20,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||
@ -1027,17 +1027,14 @@ func TestAgentController(t *testing.T) {
|
||||
tt.addKubeReactions(kubeClientset)
|
||||
}
|
||||
|
||||
actualDeleteActionOpts := &[]metav1.DeleteOptions{}
|
||||
trackDeleteKubeClient := testutil.NewDeleteOptionsRecorder(kubeClientset, actualDeleteActionOpts)
|
||||
|
||||
kubeInformers := informers.NewSharedInformerFactory(kubeClientset, 0)
|
||||
log := testlogger.New(t)
|
||||
log := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mockExecutor := mocks.NewMockPodCommandExecutor(ctrl)
|
||||
mockDynamicCert := mocks.NewMockDynamicCertPrivate(ctrl)
|
||||
fakeClock := clock.NewFakeClock(now)
|
||||
fakeClock := clocktesting.NewFakeClock(now)
|
||||
execCache := cache.NewExpiringWithClock(fakeClock)
|
||||
if tt.mocks != nil {
|
||||
tt.mocks(t, mockExecutor.EXPECT(), mockDynamicCert.EXPECT(), execCache)
|
||||
@ -1059,7 +1056,7 @@ func TestAgentController(t *testing.T) {
|
||||
},
|
||||
DiscoveryURLOverride: tt.discoveryURLOverride,
|
||||
},
|
||||
&kubeclient.Client{Kubernetes: trackDeleteKubeClient, PinnipedConcierge: conciergeClientset},
|
||||
&kubeclient.Client{Kubernetes: kubeClientset, PinnipedConcierge: conciergeClientset},
|
||||
kubeInformers.Core().V1().Pods(),
|
||||
kubeInformers.Apps().V1().Deployments(),
|
||||
kubeInformers.Core().V1().Pods(),
|
||||
@ -1069,13 +1066,13 @@ func TestAgentController(t *testing.T) {
|
||||
mockDynamicCert,
|
||||
fakeClock,
|
||||
execCache,
|
||||
log,
|
||||
log.Logger,
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
errorMessages := runControllerUntilQuiet(ctx, t, controller, hasDeploymentSynced(trackDeleteKubeClient, kubeInformers), kubeInformers, conciergeInformers)
|
||||
errorMessages := runControllerUntilQuiet(ctx, t, controller, hasDeploymentSynced(kubeClientset, kubeInformers), kubeInformers, conciergeInformers)
|
||||
|
||||
actualErrors := deduplicate(errorMessages)
|
||||
assert.Subsetf(t, actualErrors, tt.wantDistinctErrors, "required error(s) were not found in the actual errors")
|
||||
@ -1088,16 +1085,20 @@ func TestAgentController(t *testing.T) {
|
||||
|
||||
// Assert on all actions that happened to deployments.
|
||||
var actualDeploymentActionVerbs []string
|
||||
var actualDeleteActionOpts []metav1.DeleteOptions
|
||||
for _, a := range kubeClientset.Actions() {
|
||||
if a.GetResource().Resource == "deployments" && a.GetVerb() != "get" { // ignore gets caused by hasDeploymentSynced
|
||||
actualDeploymentActionVerbs = append(actualDeploymentActionVerbs, a.GetVerb())
|
||||
if deleteAction, ok := a.(coretesting.DeleteAction); ok {
|
||||
actualDeleteActionOpts = append(actualDeleteActionOpts, deleteAction.GetDeleteOptions())
|
||||
}
|
||||
}
|
||||
}
|
||||
if tt.wantDeploymentActionVerbs != nil {
|
||||
assert.Equal(t, tt.wantDeploymentActionVerbs, actualDeploymentActionVerbs)
|
||||
}
|
||||
if tt.wantDeploymentDeleteActionOpts != nil {
|
||||
assert.Equal(t, tt.wantDeploymentDeleteActionOpts, *actualDeleteActionOpts)
|
||||
assert.Equal(t, tt.wantDeploymentDeleteActionOpts, actualDeleteActionOpts)
|
||||
}
|
||||
|
||||
// Assert that the agent deployment is in the expected final state.
|
||||
|
@ -58,12 +58,10 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
wantDistinctErrors []string
|
||||
wantDistinctLogs []string
|
||||
wantActions []coretesting.Action
|
||||
wantDeleteOptions []metav1.DeleteOptions
|
||||
}{
|
||||
{
|
||||
name: "no pods",
|
||||
wantActions: []coretesting.Action{},
|
||||
wantDeleteOptions: []metav1.DeleteOptions{},
|
||||
},
|
||||
{
|
||||
name: "mix of pods",
|
||||
@ -78,12 +76,9 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
},
|
||||
wantActions: []coretesting.Action{ // the first delete triggers the informer again, but the second invocation triggers a Not Found
|
||||
coretesting.NewGetAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
coretesting.NewDeleteAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
coretesting.NewDeleteActionWithOptions(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name, testutil.NewPreconditions("3", "4")),
|
||||
coretesting.NewGetAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
},
|
||||
wantDeleteOptions: []metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("3", "4"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fail to delete",
|
||||
@ -102,13 +97,9 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
},
|
||||
wantActions: []coretesting.Action{
|
||||
coretesting.NewGetAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
coretesting.NewDeleteAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
coretesting.NewDeleteActionWithOptions(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name, testutil.NewPreconditions("3", "4")),
|
||||
coretesting.NewGetAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
coretesting.NewDeleteAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
},
|
||||
wantDeleteOptions: []metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("3", "4"),
|
||||
testutil.NewPreconditions("3", "4"),
|
||||
coretesting.NewDeleteActionWithOptions(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name, testutil.NewPreconditions("3", "4")),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -126,10 +117,7 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
wantDistinctErrors: []string{""},
|
||||
wantActions: []coretesting.Action{
|
||||
coretesting.NewGetAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
coretesting.NewDeleteAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
},
|
||||
wantDeleteOptions: []metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("3", "4"),
|
||||
coretesting.NewDeleteActionWithOptions(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name, testutil.NewPreconditions("3", "4")),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -148,7 +136,6 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
wantActions: []coretesting.Action{
|
||||
coretesting.NewGetAction(corev1.Resource("pods").WithVersion("v1"), "concierge", legacyAgentPodWithExtraLabel.Name),
|
||||
},
|
||||
wantDeleteOptions: []metav1.DeleteOptions{},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -161,19 +148,16 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
tt.addKubeReactions(kubeClientset)
|
||||
}
|
||||
|
||||
opts := &[]metav1.DeleteOptions{}
|
||||
trackDeleteClient := testutil.NewDeleteOptionsRecorder(kubeClientset, opts)
|
||||
|
||||
kubeInformers := informers.NewSharedInformerFactory(kubeClientset, 0)
|
||||
log := testlogger.New(t)
|
||||
log := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
controller := NewLegacyPodCleanerController(
|
||||
AgentConfig{
|
||||
Namespace: "concierge",
|
||||
Labels: map[string]string{"extralabel": "labelvalue"},
|
||||
},
|
||||
&kubeclient.Client{Kubernetes: trackDeleteClient},
|
||||
&kubeclient.Client{Kubernetes: kubeClientset},
|
||||
kubeInformers.Core().V1().Pods(),
|
||||
log,
|
||||
log.Logger,
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
@ -183,7 +167,6 @@ func TestLegacyPodCleanerController(t *testing.T) {
|
||||
assert.Equal(t, tt.wantDistinctErrors, deduplicate(errorMessages), "unexpected errors")
|
||||
assert.Equal(t, tt.wantDistinctLogs, deduplicate(log.Lines()), "unexpected logs")
|
||||
assert.Equal(t, tt.wantActions, kubeClientset.Actions()[2:], "unexpected actions")
|
||||
assert.Equal(t, tt.wantDeleteOptions, *opts, "unexpected delete options")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned"
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
|
||||
@ -116,7 +116,7 @@ func TestSync(t *testing.T) {
|
||||
// Set this at the last second to allow for injection of server override.
|
||||
subject = NewFederationDomainWatcherController(
|
||||
providersSetter,
|
||||
clock.NewFakeClock(frozenNow),
|
||||
clocktesting.NewFakeClock(frozenNow),
|
||||
pinnipedAPIClient,
|
||||
federationDomainInformers.Config().V1alpha1().FederationDomains(),
|
||||
controllerlib.WithInformer,
|
||||
|
@ -91,7 +91,7 @@ func TestOIDCUpstreamWatcherControllerFilterSecret(t *testing.T) {
|
||||
nil,
|
||||
pinnipedInformers.IDP().V1alpha1().OIDCIdentityProviders(),
|
||||
secretInformer,
|
||||
testLog,
|
||||
testLog.Logger,
|
||||
withInformer.WithInformer,
|
||||
)
|
||||
|
||||
@ -1123,7 +1123,7 @@ oidc: issuer did not match the issuer returned by provider, expected "` + testIs
|
||||
pinnipedInformers := pinnipedinformers.NewSharedInformerFactory(fakePinnipedClient, 0)
|
||||
fakeKubeClient := fake.NewSimpleClientset(tt.inputSecrets...)
|
||||
kubeInformers := informers.NewSharedInformerFactory(fakeKubeClient, 0)
|
||||
testLog := testlogger.New(t)
|
||||
testLog := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
cache := provider.NewDynamicUpstreamIDPProvider()
|
||||
cache.SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI{
|
||||
&upstreamoidc.ProviderConfig{Name: "initial-entry"},
|
||||
@ -1134,7 +1134,7 @@ oidc: issuer did not match the issuer returned by provider, expected "` + testIs
|
||||
fakePinnipedClient,
|
||||
pinnipedInformers.IDP().V1alpha1().OIDCIdentityProviders(),
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
testLog,
|
||||
testLog.Logger,
|
||||
controllerlib.WithInformer,
|
||||
)
|
||||
|
||||
|
@ -13,9 +13,10 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/utils/clock"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
@ -88,7 +89,7 @@ func GarbageCollectorController(
|
||||
|
||||
func (c *garbageCollectorController) Sync(ctx controllerlib.Context) error {
|
||||
// make sure we have a consistent, static meaning for the current time during the sync loop
|
||||
frozenClock := clock.NewFakeClock(c.clock.Now())
|
||||
frozenClock := clocktesting.NewFakeClock(c.clock.Now())
|
||||
|
||||
// The Sync method is triggered upon any change to any Secret, which would make this
|
||||
// controller too chatty, so it rate limits itself to a more reasonable interval.
|
||||
|
@ -18,11 +18,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
kubetesting "k8s.io/client-go/testing"
|
||||
"k8s.io/utils/clock"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/fositestorage/accesstoken"
|
||||
@ -127,13 +127,11 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
subject controllerlib.Controller
|
||||
kubeInformerClient *kubernetesfake.Clientset
|
||||
kubeClient *kubernetesfake.Clientset
|
||||
deleteOptions *[]metav1.DeleteOptions
|
||||
deleteOptionsRecorder kubernetes.Interface
|
||||
kubeInformers kubeinformers.SharedInformerFactory
|
||||
cancelContext context.Context
|
||||
cancelContextCancelFunc context.CancelFunc
|
||||
syncContext *controllerlib.Context
|
||||
fakeClock *clock.FakeClock
|
||||
fakeClock *clocktesting.FakeClock
|
||||
frozenNow time.Time
|
||||
)
|
||||
|
||||
@ -144,7 +142,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
subject = GarbageCollectorController(
|
||||
idpCache,
|
||||
fakeClock,
|
||||
deleteOptionsRecorder,
|
||||
kubeClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
)
|
||||
@ -172,11 +170,9 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
|
||||
kubeInformerClient = kubernetesfake.NewSimpleClientset()
|
||||
kubeClient = kubernetesfake.NewSimpleClientset()
|
||||
deleteOptions = &[]metav1.DeleteOptions{}
|
||||
deleteOptionsRecorder = testutil.NewDeleteOptionsRecorder(kubeClient, deleteOptions)
|
||||
kubeInformers = kubeinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
frozenNow = time.Now().UTC()
|
||||
fakeClock = clock.NewFakeClock(frozenNow)
|
||||
fakeClock = clocktesting.NewFakeClock(frozenNow)
|
||||
|
||||
unrelatedSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -252,18 +248,11 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "first expired secret"),
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "second expired secret"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "first expired secret", testutil.NewPreconditions("uid-123", "rv-456")),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "second expired secret", testutil.NewPreconditions("uid-789", "rv-555")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-456"),
|
||||
testutil.NewPreconditions("uid-789", "rv-555"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
list, err := kubeClient.CoreV1().Secrets(installedInNamespace).List(context.Background(), metav1.ListOptions{})
|
||||
r.NoError(err)
|
||||
r.Len(list.Items, 2)
|
||||
@ -384,18 +373,11 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// Both authcode session secrets are deleted.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "activeOIDCAuthcodeSession"),
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "inactiveOIDCAuthcodeSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "activeOIDCAuthcodeSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "inactiveOIDCAuthcodeSession", testutil.NewPreconditions("uid-456", "rv-456")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
testutil.NewPreconditions("uid-456", "rv-456"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -460,16 +442,10 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// The invalid authcode session secrets is still deleted because it is expired.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "invalidOIDCAuthcodeSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "invalidOIDCAuthcodeSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -536,16 +512,10 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// The authcode session secrets is still deleted because it is expired.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "wrongProviderNameOIDCAuthcodeSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "wrongProviderNameOIDCAuthcodeSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -612,16 +582,10 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// The authcode session secrets is still deleted because it is expired.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "wrongProviderNameOIDCAuthcodeSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "wrongProviderNameOIDCAuthcodeSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -767,16 +731,10 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// The authcode session secrets is deleted.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "activeOIDCAuthcodeSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "activeOIDCAuthcodeSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -893,18 +851,11 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// Both session secrets are deleted.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "offlineAccessGrantedOIDCAccessTokenSession"),
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "offlineAccessNotGrantedOIDCAccessTokenSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "offlineAccessGrantedOIDCAccessTokenSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "offlineAccessNotGrantedOIDCAccessTokenSession", testutil.NewPreconditions("uid-456", "rv-456")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
testutil.NewPreconditions("uid-456", "rv-456"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -976,16 +927,10 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// The secret is deleted.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "oidcRefreshSession"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "oidcRefreshSession", testutil.NewPreconditions("uid-123", "rv-123")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
r.ElementsMatch(
|
||||
[]metav1.DeleteOptions{
|
||||
testutil.NewPreconditions("uid-123", "rv-123"),
|
||||
},
|
||||
*deleteOptions,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -996,6 +941,8 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "expired secret",
|
||||
Namespace: installedInNamespace,
|
||||
UID: "uid-747",
|
||||
ResourceVersion: "rv-609",
|
||||
Annotations: map[string]string{
|
||||
"storage.pinniped.dev/garbage-collect-after": frozenNow.Add(20 * time.Second).Format(time.RFC3339),
|
||||
},
|
||||
@ -1033,7 +980,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
// It should have deleted the expired secret.
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "expired secret"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "expired secret", testutil.NewPreconditions("uid-747", "rv-609")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
@ -1061,6 +1008,8 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "expired secret",
|
||||
Namespace: installedInNamespace,
|
||||
UID: "uid-748",
|
||||
ResourceVersion: "rv-608",
|
||||
Annotations: map[string]string{
|
||||
"storage.pinniped.dev/garbage-collect-after": frozenNow.Add(-time.Second).Format(time.RFC3339),
|
||||
},
|
||||
@ -1076,7 +1025,7 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "expired secret"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "expired secret", testutil.NewPreconditions("uid-748", "rv-608")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
@ -1093,6 +1042,8 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "erroring secret",
|
||||
Namespace: installedInNamespace,
|
||||
UID: "uid-111",
|
||||
ResourceVersion: "rv-222",
|
||||
Annotations: map[string]string{
|
||||
"storage.pinniped.dev/garbage-collect-after": frozenNow.Add(-time.Second).Format(time.RFC3339),
|
||||
},
|
||||
@ -1110,6 +1061,8 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "expired secret",
|
||||
Namespace: installedInNamespace,
|
||||
UID: "uid-333",
|
||||
ResourceVersion: "rv-444",
|
||||
Annotations: map[string]string{
|
||||
"storage.pinniped.dev/garbage-collect-after": frozenNow.Add(-time.Second).Format(time.RFC3339),
|
||||
},
|
||||
@ -1125,8 +1078,8 @@ func TestGarbageCollectorControllerSync(t *testing.T) {
|
||||
|
||||
r.ElementsMatch(
|
||||
[]kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "erroring secret"),
|
||||
kubetesting.NewDeleteAction(secretsGVR, installedInNamespace, "expired secret"),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "erroring secret", testutil.NewPreconditions("uid-111", "rv-222")),
|
||||
kubetesting.NewDeleteActionWithOptions(secretsGVR, installedInNamespace, "expired secret", testutil.NewPreconditions("uid-333", "rv-444")),
|
||||
},
|
||||
kubeClient.Actions(),
|
||||
)
|
||||
|
@ -9,10 +9,10 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog/v2/klogr"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||
pinnipedinformers "go.pinniped.dev/generated/latest/client/concierge/informers/externalversions"
|
||||
|
@ -18,9 +18,9 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
)
|
||||
|
||||
func TestStorage(t *testing.T) {
|
||||
@ -62,7 +62,7 @@ func TestStorage(t *testing.T) {
|
||||
name string
|
||||
resource string
|
||||
mocks func(*testing.T, mocker)
|
||||
run func(*testing.T, Storage, *clock.FakeClock) error
|
||||
run func(*testing.T, Storage, *clocktesting.FakeClock) error
|
||||
wantActions []coretesting.Action
|
||||
wantSecrets []corev1.Secret
|
||||
wantErr string
|
||||
@ -71,7 +71,7 @@ func TestStorage(t *testing.T) {
|
||||
name: "get non-existent",
|
||||
resource: "authcode",
|
||||
mocks: nil,
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
_, err := storage.Get(ctx, "not-exists", nil)
|
||||
return err
|
||||
},
|
||||
@ -85,7 +85,7 @@ func TestStorage(t *testing.T) {
|
||||
name: "delete non-existent",
|
||||
resource: "tokens",
|
||||
mocks: nil,
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
return storage.Delete(ctx, "not-a-token")
|
||||
},
|
||||
wantActions: []coretesting.Action{
|
||||
@ -98,7 +98,7 @@ func TestStorage(t *testing.T) {
|
||||
name: "delete non-existent by label",
|
||||
resource: "tokens",
|
||||
mocks: nil,
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
return storage.DeleteByLabel(ctx, "additionalLabel", "matching-value")
|
||||
},
|
||||
wantActions: []coretesting.Action{
|
||||
@ -113,7 +113,7 @@ func TestStorage(t *testing.T) {
|
||||
name: "create and get",
|
||||
resource: "access-tokens",
|
||||
mocks: nil,
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode1)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -177,7 +177,7 @@ func TestStorage(t *testing.T) {
|
||||
name: "create multiple, each gets the correct lifetime timestamp",
|
||||
resource: "access-tokens",
|
||||
mocks: nil,
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
data := &testJSON{Data: "create1"}
|
||||
rv1, err := storage.Create(ctx, "sig1", data, nil)
|
||||
require.Empty(t, rv1) // fake client does not set this
|
||||
@ -272,7 +272,7 @@ func TestStorage(t *testing.T) {
|
||||
name: "create and get with additional labels",
|
||||
resource: "access-tokens",
|
||||
mocks: nil,
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode1)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -360,7 +360,7 @@ func TestStorage(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode2)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -429,7 +429,7 @@ func TestStorage(t *testing.T) {
|
||||
return false, nil, nil // we mutated the secret in place but we do not "handle" it
|
||||
})
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode3)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -521,7 +521,7 @@ func TestStorage(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode2)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -615,7 +615,7 @@ func TestStorage(t *testing.T) {
|
||||
Type: "storage.pinniped.dev/walruses",
|
||||
}))
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
return storage.DeleteByLabel(ctx, "additionalLabel", "matching-value")
|
||||
},
|
||||
wantActions: []coretesting.Action{
|
||||
@ -696,7 +696,7 @@ func TestStorage(t *testing.T) {
|
||||
return true, nil, fmt.Errorf("some delete error")
|
||||
})
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
return storage.DeleteByLabel(ctx, "additionalLabel", "matching-value")
|
||||
},
|
||||
wantActions: []coretesting.Action{
|
||||
@ -749,7 +749,7 @@ func TestStorage(t *testing.T) {
|
||||
return true, nil, fmt.Errorf("some listing error")
|
||||
})
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
return storage.DeleteByLabel(ctx, "additionalLabel", "matching-value")
|
||||
},
|
||||
wantActions: []coretesting.Action{
|
||||
@ -783,7 +783,7 @@ func TestStorage(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode3)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -847,7 +847,7 @@ func TestStorage(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode3)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -911,7 +911,7 @@ func TestStorage(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode3)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -975,7 +975,7 @@ func TestStorage(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clock.FakeClock) error {
|
||||
run: func(t *testing.T, storage Storage, fakeClock *clocktesting.FakeClock) error {
|
||||
signature := hmac.AuthorizeCodeSignature(authorizationCode3)
|
||||
require.NotEmpty(t, signature)
|
||||
require.NotEmpty(t, validateSecretName(signature, false)) // signature is not valid secret name as-is
|
||||
@ -1025,7 +1025,7 @@ func TestStorage(t *testing.T) {
|
||||
tt.mocks(t, client)
|
||||
}
|
||||
secrets := client.CoreV1().Secrets(namespace)
|
||||
fakeClock := clock.NewFakeClock(fakeNow)
|
||||
fakeClock := clocktesting.NewFakeClock(fakeNow)
|
||||
storage := New(tt.resource, secrets, fakeClock.Now, lifetime)
|
||||
|
||||
err := tt.run(t, storage, fakeClock)
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
@ -276,7 +276,7 @@ func TestCreateWithoutRequesterID(t *testing.T) {
|
||||
func makeTestSubject() (context.Context, *fake.Clientset, corev1client.SecretInterface, RevocationStorage) {
|
||||
client := fake.NewSimpleClientset()
|
||||
secrets := client.CoreV1().Secrets(namespace)
|
||||
return context.Background(), client, secrets, New(secrets, clock.NewFakeClock(fakeNow).Now, lifetime)
|
||||
return context.Background(), client, secrets, New(secrets, clocktesting.NewFakeClock(fakeNow).Now, lifetime)
|
||||
}
|
||||
|
||||
func TestReadFromSecret(t *testing.T) {
|
||||
|
@ -196,32 +196,38 @@ const ExpectedAuthorizeCodeSessionJSONFromFuzzing = `{
|
||||
"client": {
|
||||
"id": ":NJ¸Ɣ8(黋馛ÄRɴJa¶z",
|
||||
"client_secret": "UQ==",
|
||||
"rotated_secrets": [
|
||||
"Bno=",
|
||||
"0j8=",
|
||||
"1c4="
|
||||
],
|
||||
"redirect_uris": [
|
||||
"ǖ枭kʍ切厦ȳ箦;¥ʊXĝ奨誷傥祩d",
|
||||
"ʊXĝ",
|
||||
"Ƿ"
|
||||
],
|
||||
"grant_types": [
|
||||
"祩d",
|
||||
"zŇZ",
|
||||
"優蒼ĊɌț訫DŽǽeʀO2ƚ\u0026N"
|
||||
],
|
||||
"grant_types": [
|
||||
"response_types": [
|
||||
"唐W6ɻ橩斚薛ɑƐ"
|
||||
],
|
||||
"response_types": [
|
||||
"scopes": [
|
||||
"w",
|
||||
"ǔŭe[u@阽羂ŷ-Ĵ½輢OÅ濲喾H"
|
||||
],
|
||||
"scopes": [
|
||||
"audience": [
|
||||
"G螩歐湡ƙı唡ɸğƎ\u0026胢輢Ƈĵƚ"
|
||||
],
|
||||
"audience": [
|
||||
"ě"
|
||||
],
|
||||
"public": false,
|
||||
"jwks_uri": "o*泞羅ʘ Ⱦķ瀊垰7ã\")",
|
||||
"jwks_uri": "潌țjA9;焋Ēƕ",
|
||||
"jwks": {
|
||||
"keys": [
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "nK9xgX_iN7u3u_i8YOO7ZRT_WK028Vd_nhtsUu7Eo6E",
|
||||
"x": "LHMZ29A64WecPQSLotS8hfZ2mae0SR17CtPdnMDP7ZI",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
@ -238,7 +244,24 @@ const ExpectedAuthorizeCodeSessionJSONFromFuzzing = `{
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "UbbswQgzWhfGCRlwQmMp6fw_HoIoqkIaKT-2XN2fuYU",
|
||||
"x": "1PwKrC4qDe8cabzGTdA0NjuMJhAZAw7Bu7Tj9z2Y4pE",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
"User": null,
|
||||
"Host": "",
|
||||
"Path": "",
|
||||
"RawPath": "",
|
||||
"ForceQuery": false,
|
||||
"RawQuery": "",
|
||||
"Fragment": "",
|
||||
"RawFragment": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
"x": "j4b-Vld5buh_2KIpjjaDRJ8OY7l7d6XAumvDtVTT9BI",
|
||||
"x5u": {
|
||||
"Scheme": "",
|
||||
"Opaque": "",
|
||||
@ -254,104 +277,107 @@ const ExpectedAuthorizeCodeSessionJSONFromFuzzing = `{
|
||||
}
|
||||
]
|
||||
},
|
||||
"token_endpoint_auth_method": "ƿʥǟȒ伉\u003cx¹T鼓c吏",
|
||||
"token_endpoint_auth_method": "趀Ȁ;hYGe天蹗ĽǙ澅j翕q骽",
|
||||
"request_uris": [
|
||||
"Ć捘j]=谅ʑɑɮ$Ól4Ȟ",
|
||||
",Q7钎漡臧n"
|
||||
"Ǐ蛓ȿ,JwwƐ\u003c涵ØƉKĵ",
|
||||
"Ȟú",
|
||||
"Q7钎漡臧n栀,i"
|
||||
],
|
||||
"request_object_signing_alg": "3@¡廜+v,淬Ʋ4Dʧ呩锏緍场",
|
||||
"token_endpoint_auth_signing_alg": "(ưƓǴ罷ǹ~]ea胠"
|
||||
"request_object_signing_alg": "廜+v,淬Ʋ4Dʧ呩锏緍场脋",
|
||||
"token_endpoint_auth_signing_alg": "ưƓǴ罷ǹ~]ea胠Ĺĩv絹b垇I"
|
||||
},
|
||||
"scopes": [
|
||||
"ĩv絹b垇IŕĩǀŻQ'k頂箨J-a稆",
|
||||
"啶#昏Q遐*\\髎bŸ"
|
||||
"ĩǀŻQ'k頂箨J-a",
|
||||
"ɓ啶#昏Q遐*\\髎bŸ1慂U"
|
||||
],
|
||||
"grantedScopes": [
|
||||
"慂UFƼĮǡ鑻Z"
|
||||
"ƼĮǡ鑻Z¥篚h°ʣ£ǖ%\"砬ʍ"
|
||||
],
|
||||
"form": {
|
||||
"褾攚ŝlĆ厦駳骪l拁乖¡J¿Ƈ妔": [
|
||||
"懧¥ɂĵ~Čyʊ恀c\"NJřðȿ/",
|
||||
"裢?霃谥vƘ:ƿ/濔Aʉ\u003c",
|
||||
"ȭ$奍囀Dž悷鵱民撲ʓeŘ嬀j¤"
|
||||
"¡": [
|
||||
"Ła卦牟懧¥ɂĵ",
|
||||
"ɎǛƍdÚ慂+槰蚪i齥篗裢?霃谥vƘ:",
|
||||
"/濔Aʉ\u003cS獾蔀OƭUǦ"
|
||||
],
|
||||
"诞": [
|
||||
"狲N\u003cCq罉ZPſĝEK郊©l",
|
||||
"餚LJ/ɷȑ潠[ĝU噤'pX ",
|
||||
"Y妶ǵ!ȁu狍ɶȳsčɦƦ诱"
|
||||
"民撲ʓeŘ嬀j¤囡莒汗狲N\u003cCq": [
|
||||
"5ȏ樛ȧ.mĔ櫓Ǩ療騃Ǐ}ɟ",
|
||||
"潠[ĝU噤'",
|
||||
"ŁȗɉY妶ǵ!ȁ"
|
||||
],
|
||||
"褰ʎɰ癟VĎĢ婄磫绒u妔隤ʑƍš駎竪": [
|
||||
"鱙翑ȲŻ麤ã桒嘞\\摗Ǘū稖咾鎅ǸÖ"
|
||||
]
|
||||
},
|
||||
"session": {
|
||||
"fosite": {
|
||||
"Claims": {
|
||||
"JTI": "u妔隤ʑƍš駎竪0ɔ闏À1",
|
||||
"Issuer": "麤ã桒嘞\\摗Ǘū稖咾鎅ǸÖ绝TF",
|
||||
"Subject": "巽ēđų蓼tùZ蛆鬣a\"ÙǞ0觢Û±",
|
||||
"JTI": "褗6巽ēđų蓼tùZ蛆鬣a\"ÙǞ0觢",
|
||||
"Issuer": "j¦鲶H股ƲLŋZ-{",
|
||||
"Subject": "ehpƧ蓟",
|
||||
"Audience": [
|
||||
"H股ƲL",
|
||||
"肟v\u0026đehpƧ",
|
||||
"5^驜Ŗ~ů崧軒q腟u尿"
|
||||
"驜Ŗ~ů崧軒q腟u尿宲!"
|
||||
],
|
||||
"Nonce": "ğ",
|
||||
"ExpiresAt": "2016-11-22T21:33:58.460521133Z",
|
||||
"IssuedAt": "1990-07-25T23:42:07.055978334Z",
|
||||
"RequestedAt": "1971-01-30T00:23:36.377684025Z",
|
||||
"AuthTime": "2088-11-09T12:09:14.051840239Z",
|
||||
"AccessTokenHash": "蕖¤'+ʣȍ瓁U4鞀",
|
||||
"AuthenticationContextClassReference": "ʏÑęN\u003c_z",
|
||||
"AuthenticationMethodsReference": "ț髄A",
|
||||
"CodeHash": "4磔_袻vÓG-壧丵礴鋈k蟵pAɂʅ",
|
||||
"Nonce": "ǎ^嫯R忑隯ƗƋ*L\u0026",
|
||||
"ExpiresAt": "1989-06-02T14:40:29.613836765Z",
|
||||
"IssuedAt": "2052-03-26T02:39:27.882495556Z",
|
||||
"RequestedAt": "2038-04-06T10:46:24.698586972Z",
|
||||
"AuthTime": "2003-01-05T11:30:18.206004879Z",
|
||||
"AccessTokenHash": "ğǫ\\aȊ4ț髄Al",
|
||||
"AuthenticationContextClassReference": "曓蓳n匟鯘磹*金爃鶴滱ůĮǐ_c3#",
|
||||
"AuthenticationMethodsReferences": [
|
||||
"装ƹýĸŴB岺Ð嫹Sx镯荫őł疂ư墫"
|
||||
],
|
||||
"CodeHash": "\u0026鶡",
|
||||
"Extra": {
|
||||
"#\u0026PƢ曰l騌蘙螤\\阏Đ镴Ƥm蔻ǭ\\鿞": 1677215584,
|
||||
"Y\u0026鶡萷ɵ啜s攦Ɩïdnǔ": {
|
||||
",t猟i\u0026\u0026Q@ǤǟǗǪ飘ȱF?Ƈ": {
|
||||
"~劰û橸ɽ銐ƭ?}H": null,
|
||||
"癑勦e骲v0H晦XŘO溪V蔓": {
|
||||
"碼Ǫ": false
|
||||
"rǓ\\BRë_g\"ʎ啴SƇMǃļū": {
|
||||
"4撎胬龯,t猟i\u0026\u0026Q@ǤǟǗ": [
|
||||
1239190737
|
||||
],
|
||||
"飘ȱF?Ƈ畋": {
|
||||
"劰û橸ɽ銐ƭ?}HƟ玈鳚": null,
|
||||
"骲v0H晦XŘO溪V蔓Ȍ+~ē埅Ȝ": {
|
||||
"4Ǟ": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"钻煐ɨəÅDČ{Ȩʦ4撎": [
|
||||
3684968178
|
||||
]
|
||||
}
|
||||
"鑳绪": 2738428764
|
||||
}
|
||||
},
|
||||
"Headers": {
|
||||
"Extra": {
|
||||
"ĊdŘ鸨EJ毕懴řĬń戹": {
|
||||
"诳DT=3骜Ǹ,": {
|
||||
"\u003e": {
|
||||
"ǰ": false
|
||||
},
|
||||
"ɁOƪ穋嶿鳈恱va": null
|
||||
},
|
||||
"豑觳翢砜Fȏl": [
|
||||
927958776
|
||||
]
|
||||
},
|
||||
"埅ȜʁɁ;Bd謺錳4帳Ņ": 388005986
|
||||
"d謺錳4帳ŅǃĊ": 663773398,
|
||||
"Ř鸨EJ": {
|
||||
"Ǽǟ迍阊v\"豑觳翢砜": [
|
||||
995342744
|
||||
],
|
||||
"ȏl鐉诳DT=3骜Ǹ": {
|
||||
"厷ɁOƪ穋嶿鳈恱va|载ǰɱ汶C]ɲ": null,
|
||||
"荤Ý呐ʣ®DžȪǣǎǔ爣縗ɦü": {
|
||||
"H :靥湤庤毩fɤȆʪ融ƆuŤn": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExpiresAt": {
|
||||
"C]ɲ'=ĸ闒NȢȰ.醋": "1970-07-19T18:03:29.902062193Z",
|
||||
"fɤȆʪ融ƆuŤn": "2064-01-24T20:34:16.593152073Z",
|
||||
"爣縗ɦüHêQ仏1ő": "2102-03-17T06:24:40.256846902Z"
|
||||
"韁臯氃妪婝rȤ\"h丬鎒ơ娻}ɼƟ": "1970-04-27T04:31:30.902468229Z"
|
||||
},
|
||||
"Username": "韁臯氃妪婝rȤ\"h丬鎒ơ娻}ɼƟ",
|
||||
"Subject": "闺髉龳ǽÙ龦O亾EW莛8嘶×"
|
||||
"Username": "髉龳ǽÙ",
|
||||
"Subject": "\u0026¥潝邎Ȗ莅ŝǔ盕戙鵮碡ʯiŬŽ"
|
||||
},
|
||||
"custom": {
|
||||
"providerUID": "鵮碡ʯiŬŽ非Ĝ眧Ĭ葜SŦ餧Ĭ倏4",
|
||||
"providerName": "nŐǛ3",
|
||||
"providerType": "闣ʬ橳(ý綃ʃʚƟ覣k眐4Ĉt",
|
||||
"providerUID": "Ĝ眧Ĭ",
|
||||
"providerName": "ʼn2ƋŢ觛ǂ焺nŐǛ",
|
||||
"providerType": "ɥ闣ʬ橳(ý綃ʃʚƟ覣k眐4",
|
||||
"oidc": {
|
||||
"upstreamRefreshToken": "嵽痊w©Ź榨Q|ôɵt毇妬"
|
||||
"upstreamRefreshToken": "tC嵽痊w"
|
||||
},
|
||||
"ldap": {
|
||||
"userDN": "6鉢緋uƴŤȱʀļÂ?墖\u003cƬb獭潜Ʃ饾",
|
||||
"userDN": "Ź榨Q|ôɵt毇妬\u003e6鉢緋",
|
||||
"extraRefreshAttributes": {
|
||||
"ď逳鞪?3)藵睋邔\u0026Ű惫蜀Ģ¡圔": "墀jMʥ",
|
||||
"齁š%OpKȱ藚ɏ¬Ê蒭堜]ȗ韚ʫ": "鷞aŚB碠k9帴ʘ赱"
|
||||
"ƍ蛊ʚ£:設虝27": "b獭潜Ʃ饾k|鬌R蜚蠣麹概",
|
||||
"藚ɏ¬Ê蒭堜]ȗ韚ʫ": "鷞aŚB碠k9帴ʘ赱"
|
||||
}
|
||||
},
|
||||
"activedirectory": {
|
||||
|
@ -28,10 +28,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
kubetesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/internal/fositestorage"
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
@ -258,7 +258,7 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
func makeTestSubject() (context.Context, *fake.Clientset, corev1client.SecretInterface, oauth2.AuthorizeCodeStorage) {
|
||||
client := fake.NewSimpleClientset()
|
||||
secrets := client.CoreV1().Secrets(namespace)
|
||||
return context.Background(), client, secrets, New(secrets, clock.NewFakeClock(fakeNow).Now, lifetime)
|
||||
return context.Background(), client, secrets, New(secrets, clocktesting.NewFakeClock(fakeNow).Now, lifetime)
|
||||
}
|
||||
|
||||
// TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession asserts that we can correctly round trip our authorize code session.
|
||||
@ -396,7 +396,7 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
|
||||
// while the fuzzer will panic if AuthorizeRequest changes in a way that cannot be fuzzed,
|
||||
// if it adds a new field that can be fuzzed, this check will fail
|
||||
// thus if AuthorizeRequest changes, we will detect it here (though we could possibly miss an omitempty field)
|
||||
require.JSONEq(t, ExpectedAuthorizeCodeSessionJSONFromFuzzing, authorizeCodeSessionJSONFromFuzzing)
|
||||
require.JSONEq(t, ExpectedAuthorizeCodeSessionJSONFromFuzzing, authorizeCodeSessionJSONFromFuzzing, "actual:\n%s", authorizeCodeSessionJSONFromFuzzing)
|
||||
}
|
||||
|
||||
func TestReadFromSecret(t *testing.T) {
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
@ -100,7 +100,7 @@ func TestOpenIdConnectStorage(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, request, newRequest)
|
||||
|
||||
err = storage.DeleteOpenIDConnectSession(ctx, "fancy-code.fancy-signature")
|
||||
err = storage.DeleteOpenIDConnectSession(ctx, "fancy-code.fancy-signature") //nolint: staticcheck // we know this is deprecated and never called. our GC controller cleans these up.
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.LogActualJSONFromCreateAction(t, client, 0) // makes it easier to update expected values when needed
|
||||
@ -200,5 +200,5 @@ func TestAuthcodeHasNoDot(t *testing.T) {
|
||||
func makeTestSubject() (context.Context, *fake.Clientset, corev1client.SecretInterface, openid.OpenIDConnectRequestStorage) {
|
||||
client := fake.NewSimpleClientset()
|
||||
secrets := client.CoreV1().Secrets(namespace)
|
||||
return context.Background(), client, secrets, New(secrets, clock.NewFakeClock(fakeNow).Now, lifetime)
|
||||
return context.Background(), client, secrets, New(secrets, clocktesting.NewFakeClock(fakeNow).Now, lifetime)
|
||||
}
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
@ -199,5 +199,5 @@ func TestCreateWithWrongRequesterDataTypes(t *testing.T) {
|
||||
func makeTestSubject() (context.Context, *fake.Clientset, corev1client.SecretInterface, pkce.PKCERequestStorage) {
|
||||
client := fake.NewSimpleClientset()
|
||||
secrets := client.CoreV1().Secrets(namespace)
|
||||
return context.Background(), client, secrets, New(secrets, clock.NewFakeClock(fakeNow).Now, lifetime)
|
||||
return context.Background(), client, secrets, New(secrets, clocktesting.NewFakeClock(fakeNow).Now, lifetime)
|
||||
}
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
|
||||
"go.pinniped.dev/internal/oidc/clientregistry"
|
||||
"go.pinniped.dev/internal/psession"
|
||||
@ -276,7 +276,7 @@ func TestCreateWithoutRequesterID(t *testing.T) {
|
||||
func makeTestSubject() (context.Context, *fake.Clientset, corev1client.SecretInterface, RevocationStorage) {
|
||||
client := fake.NewSimpleClientset()
|
||||
secrets := client.CoreV1().Secrets(namespace)
|
||||
return context.Background(), client, secrets, New(secrets, clock.NewFakeClock(fakeNow).Now, lifetime)
|
||||
return context.Background(), client, secrets, New(secrets, clocktesting.NewFakeClock(fakeNow).Now, lifetime)
|
||||
}
|
||||
|
||||
func TestReadFromSecret(t *testing.T) {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
coreosoidc "github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/felixge/httpsnoop"
|
||||
"github.com/ory/fosite"
|
||||
"github.com/ory/fosite/handler/openid"
|
||||
"github.com/ory/fosite/token/jwt"
|
||||
@ -89,7 +90,7 @@ func handleAuthRequestForLDAPUpstream(
|
||||
ldapUpstream provider.UpstreamLDAPIdentityProviderI,
|
||||
idpType psession.ProviderType,
|
||||
) error {
|
||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper)
|
||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper, true)
|
||||
if !created {
|
||||
return nil
|
||||
}
|
||||
@ -106,7 +107,7 @@ func handleAuthRequestForLDAPUpstream(
|
||||
}
|
||||
if !authenticated {
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||
fosite.ErrAccessDenied.WithHintf("Username/password not accepted by LDAP provider."))
|
||||
fosite.ErrAccessDenied.WithHintf("Username/password not accepted by LDAP provider."), true)
|
||||
}
|
||||
|
||||
subject := downstreamSubjectFromUpstreamLDAP(ldapUpstream, authenticateResponse)
|
||||
@ -143,7 +144,7 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
||||
oauthHelper fosite.OAuth2Provider,
|
||||
oidcUpstream provider.UpstreamOIDCIdentityProviderI,
|
||||
) error {
|
||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper)
|
||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper, true)
|
||||
if !created {
|
||||
return nil
|
||||
}
|
||||
@ -157,7 +158,7 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
||||
// Return a user-friendly error for this case which is entirely within our control.
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||
fosite.ErrAccessDenied.WithHint(
|
||||
"Resource owner password credentials grant is not allowed for this upstream provider according to its configuration."))
|
||||
"Resource owner password credentials grant is not allowed for this upstream provider according to its configuration."), true)
|
||||
}
|
||||
|
||||
token, err := oidcUpstream.PasswordCredentialsGrantAndValidateTokens(r.Context(), username, password)
|
||||
@ -170,7 +171,7 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
||||
// the OIDC spec, so we don't try too hard to read the upstream errors in this case. (E.g. Dex departs from the
|
||||
// spec and returns something other than an "invalid_grant" error for bad resource owner credentials.)
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||
fosite.ErrAccessDenied.WithDebug(err.Error())) // WithDebug hides the error from the client
|
||||
fosite.ErrAccessDenied.WithDebug(err.Error()), true) // WithDebug hides the error from the client
|
||||
}
|
||||
|
||||
if token.RefreshToken == nil || token.RefreshToken.Token == "" {
|
||||
@ -180,14 +181,14 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
||||
"scopes", oidcUpstream.GetScopes())
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||
fosite.ErrAccessDenied.WithHint(
|
||||
"Refresh token not returned by upstream provider during password grant."))
|
||||
"Refresh token not returned by upstream provider during password grant."), true)
|
||||
}
|
||||
|
||||
subject, username, groups, err := downstreamsession.GetDownstreamIdentityFromUpstreamIDToken(oidcUpstream, token.IDToken.Claims)
|
||||
if err != nil {
|
||||
// Return a user-friendly error for this case which is entirely within our control.
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||
fosite.ErrAccessDenied.WithHintf("Reason: %s.", err.Error()),
|
||||
fosite.ErrAccessDenied.WithHintf("Reason: %s.", err.Error()), true,
|
||||
)
|
||||
}
|
||||
|
||||
@ -214,7 +215,7 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
||||
upstreamStateEncoder oidc.Encoder,
|
||||
cookieCodec oidc.Codec,
|
||||
) error {
|
||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper)
|
||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper, false)
|
||||
if !created {
|
||||
return nil
|
||||
}
|
||||
@ -231,7 +232,7 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, err)
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, err, false)
|
||||
}
|
||||
|
||||
csrfValue, nonceValue, pkceValue, err := generateValues(generateCSRF, generateNonce, generatePKCE)
|
||||
@ -274,7 +275,7 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
||||
|
||||
promptParam := r.Form.Get(promptParamName)
|
||||
if promptParam == promptParamNone && oidc.ScopeWasRequested(authorizeRequester, coreosoidc.ScopeOpenID) {
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, fosite.ErrLoginRequired)
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, fosite.ErrLoginRequired, false)
|
||||
}
|
||||
|
||||
for key, val := range oidcUpstream.GetAdditionalAuthcodeParams() {
|
||||
@ -295,13 +296,13 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
||||
encodedStateParamValue,
|
||||
authCodeOptions...,
|
||||
),
|
||||
302,
|
||||
http.StatusSeeOther, // match fosite and https://tools.ietf.org/id/draft-ietf-oauth-security-topics-18.html#section-4.11
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeAuthorizeError(w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, authorizeRequester fosite.AuthorizeRequester, err error) error {
|
||||
func writeAuthorizeError(w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, authorizeRequester fosite.AuthorizeRequester, err error, isBrowserless bool) error {
|
||||
if plog.Enabled(plog.LevelTrace) {
|
||||
// When trace level logging is enabled, include the stack trace in the log message.
|
||||
keysAndValues := oidc.FositeErrorForLog(err)
|
||||
@ -314,6 +315,9 @@ func writeAuthorizeError(w http.ResponseWriter, oauthHelper fosite.OAuth2Provide
|
||||
} else {
|
||||
plog.Info("authorize response error", oidc.FositeErrorForLog(err)...)
|
||||
}
|
||||
if isBrowserless {
|
||||
w = rewriteStatusSeeOtherToStatusFoundForBrowserless(w)
|
||||
}
|
||||
// Return an error according to OIDC spec 3.1.2.6 (second paragraph).
|
||||
oauthHelper.WriteAuthorizeError(w, authorizeRequester, err)
|
||||
return nil
|
||||
@ -333,29 +337,53 @@ func makeDownstreamSessionAndReturnAuthcodeRedirect(
|
||||
|
||||
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
||||
if err != nil {
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, err)
|
||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, err, true)
|
||||
}
|
||||
|
||||
w = rewriteStatusSeeOtherToStatusFoundForBrowserless(w)
|
||||
oauthHelper.WriteAuthorizeResponse(w, authorizeRequester, authorizeResponder)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func rewriteStatusSeeOtherToStatusFoundForBrowserless(w http.ResponseWriter) http.ResponseWriter {
|
||||
// rewrite http.StatusSeeOther to http.StatusFound for backwards compatibility with old pinniped CLIs.
|
||||
// we can drop this in a few releases once we feel enough time has passed for users to update.
|
||||
//
|
||||
// WriteAuthorizeResponse/WriteAuthorizeError calls used to result in http.StatusFound until
|
||||
// https://github.com/ory/fosite/pull/636 changed it to http.StatusSeeOther to address
|
||||
// https://tools.ietf.org/id/draft-ietf-oauth-security-topics-18.html#section-4.11
|
||||
// Safari has the bad behavior in the case of http.StatusFound and not just http.StatusTemporaryRedirect.
|
||||
//
|
||||
// in the browserless flows, the OAuth client is the pinniped CLI and it already has access to the user's
|
||||
// password. Thus there is no security issue with using http.StatusFound vs. http.StatusSeeOther.
|
||||
return httpsnoop.Wrap(w, httpsnoop.Hooks{
|
||||
WriteHeader: func(delegate httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc {
|
||||
return func(code int) {
|
||||
if code == http.StatusSeeOther {
|
||||
code = http.StatusFound
|
||||
}
|
||||
delegate(code)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func requireNonEmptyUsernameAndPasswordHeaders(r *http.Request, w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, authorizeRequester fosite.AuthorizeRequester) (string, string, bool) {
|
||||
username := r.Header.Get(supervisoroidc.AuthorizeUsernameHeaderName)
|
||||
password := r.Header.Get(supervisoroidc.AuthorizePasswordHeaderName)
|
||||
if username == "" || password == "" {
|
||||
_ = writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||
fosite.ErrAccessDenied.WithHintf("Missing or blank username or password."))
|
||||
fosite.ErrAccessDenied.WithHintf("Missing or blank username or password."), true)
|
||||
return "", "", false
|
||||
}
|
||||
return username, password, true
|
||||
}
|
||||
|
||||
func newAuthorizeRequest(r *http.Request, w http.ResponseWriter, oauthHelper fosite.OAuth2Provider) (fosite.AuthorizeRequester, bool) {
|
||||
func newAuthorizeRequest(r *http.Request, w http.ResponseWriter, oauthHelper fosite.OAuth2Provider, isBrowserless bool) (fosite.AuthorizeRequester, bool) {
|
||||
authorizeRequester, err := oauthHelper.NewAuthorizeRequest(r.Context(), r)
|
||||
if err != nil {
|
||||
_ = writeAuthorizeError(w, oauthHelper, authorizeRequester, err)
|
||||
_ = writeAuthorizeError(w, oauthHelper, authorizeRequester, err, isBrowserless)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
|
@ -533,7 +533,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: happyGetRequestPath,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), nil),
|
||||
@ -615,7 +615,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: happyGetRequestPath,
|
||||
csrfCookie: "__Host-pinniped-csrf=" + encodedIncomingCookieCSRFValue + " ",
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, incomingCookieCSRFValue, ""), nil),
|
||||
wantUpstreamStateParamInLocationHeader: true,
|
||||
@ -633,7 +633,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
path: "/some/path",
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
body: encodeQuery(happyGetRequestQueryMap),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "",
|
||||
wantBodyString: "",
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
@ -722,7 +722,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "login"}),
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
body: encodeQuery(happyGetRequestQueryMap),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantBodyStringWithLocationInHref: true,
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
@ -741,7 +741,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "login"}),
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
body: encodeQuery(happyGetRequestQueryMap),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantBodyStringWithLocationInHref: true,
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
@ -760,7 +760,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "none"}),
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
body: encodeQuery(happyGetRequestQueryMap),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeLoginRequiredErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -776,7 +776,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: happyGetRequestPath,
|
||||
csrfCookie: "__Host-pinniped-csrf=this-value-was-not-signed-by-pinniped",
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
// Generated a new CSRF cookie and set it in the response.
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
@ -796,7 +796,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
path: modifiedHappyGetRequestPath(map[string]string{
|
||||
"redirect_uri": downstreamRedirectURIWithDifferentPort, // not the same port number that is registered for the client
|
||||
}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{
|
||||
@ -862,7 +862,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"scope": "openid offline_access"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{
|
||||
@ -1170,7 +1170,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"response_type": "unsupported"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeUnsupportedResponseTypeErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1217,7 +1217,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"scope": "openid profile email tuna"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeInvalidScopeErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1268,7 +1268,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"response_type": ""}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeMissingResponseTypeErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1349,7 +1349,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"code_challenge": ""}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeMissingCodeChallengeErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1391,7 +1391,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"code_challenge_method": "this-is-not-a-valid-pkce-alg"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeInvalidCodeChallengeErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1433,7 +1433,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"code_challenge_method": "plain"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeMissingCodeChallengeMethodErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1475,7 +1475,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"code_challenge_method": ""}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeMissingCodeChallengeMethodErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1519,7 +1519,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "none login"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositePromptHasNoneAndOtherValueErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -1566,7 +1566,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
// The following prompt value is illegal when openid is requested, but note that openid is not requested.
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "none login", "scope": "email"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: htmlContentType,
|
||||
wantCSRFValueInCookieHeader: happyCSRF,
|
||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(
|
||||
@ -2049,7 +2049,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
cookieEncoder: happyCookieEncoder,
|
||||
method: http.MethodGet,
|
||||
path: modifiedHappyGetRequestPath(map[string]string{"state": "short"}),
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantContentType: "application/json; charset=utf-8",
|
||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeInvalidStateErrorQuery),
|
||||
wantBodyString: "",
|
||||
@ -2308,8 +2308,16 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
||||
case test.wantBodyJSON != "":
|
||||
require.JSONEq(t, test.wantBodyJSON, rsp.Body.String())
|
||||
case test.wantBodyStringWithLocationInHref:
|
||||
switch code := rsp.Code; code {
|
||||
case http.StatusFound:
|
||||
anchorTagWithLocationHref := fmt.Sprintf("<a href=\"%s\">Found</a>.\n\n", html.EscapeString(actualLocation))
|
||||
require.Equal(t, anchorTagWithLocationHref, rsp.Body.String())
|
||||
case http.StatusSeeOther:
|
||||
anchorTagWithLocationHref := fmt.Sprintf("<a href=\"%s\">See Other</a>.\n\n", html.EscapeString(actualLocation))
|
||||
require.Equal(t, anchorTagWithLocationHref, rsp.Body.String())
|
||||
default:
|
||||
t.Errorf("unexpected response code: %v", code)
|
||||
}
|
||||
default:
|
||||
require.Equal(t, test.wantBodyString, rsp.Body.String())
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -204,7 +204,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -229,7 +229,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -256,7 +256,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -284,7 +284,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound, // succeed despite `email_verified=false` because we're not using the email claim for anything
|
||||
wantStatus: http.StatusSeeOther, // succeed despite `email_verified=false` because we're not using the email claim for anything
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -372,7 +372,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -397,7 +397,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -422,7 +422,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -575,7 +575,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
Build(t, happyStateCodec),
|
||||
).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: downstreamRedirectURI + `\?code=([^&]+)&scope=&state=` + happyDownstreamState,
|
||||
wantDownstreamIDTokenUsername: oidcUpstreamUsername,
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -601,7 +601,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
Build(t, happyStateCodec),
|
||||
).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: downstreamRedirectURI + `\?code=([^&]+)&scope=openid\+offline_access&state=` + happyDownstreamState,
|
||||
wantDownstreamIDTokenUsername: oidcUpstreamUsername,
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
@ -698,7 +698,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
||||
method: http.MethodGet,
|
||||
path: newRequestPath().WithState(happyState).String(),
|
||||
csrfCookie: happyCSRFCookie,
|
||||
wantStatus: http.StatusFound,
|
||||
wantStatus: http.StatusSeeOther,
|
||||
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||
wantBody: "",
|
||||
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||
|
@ -114,7 +114,7 @@ func (k KubeStorage) GetOpenIDConnectSession(ctx context.Context, fullAuthcode s
|
||||
}
|
||||
|
||||
func (k KubeStorage) DeleteOpenIDConnectSession(ctx context.Context, fullAuthcode string) error {
|
||||
return k.oidcStorage.DeleteOpenIDConnectSession(ctx, fullAuthcode)
|
||||
return k.oidcStorage.DeleteOpenIDConnectSession(ctx, fullAuthcode) //nolint: staticcheck // we know this is deprecated and never called. our GC controller cleans these up.
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -121,7 +121,7 @@ func TestManager(t *testing.T) {
|
||||
r.False(fallbackHandlerWasCalled)
|
||||
|
||||
// Minimal check to ensure that the right endpoint was called
|
||||
r.Equal(http.StatusFound, recorder.Code)
|
||||
r.Equal(http.StatusSeeOther, recorder.Code)
|
||||
actualLocation := recorder.Header().Get("Location")
|
||||
r.True(
|
||||
strings.HasPrefix(actualLocation, expectedRedirectLocationPrefix),
|
||||
@ -160,7 +160,7 @@ func TestManager(t *testing.T) {
|
||||
|
||||
// Check just enough of the response to ensure that we wired up the callback endpoint correctly.
|
||||
// The endpoint's own unit tests cover everything else.
|
||||
r.Equal(http.StatusFound, recorder.Code)
|
||||
r.Equal(http.StatusSeeOther, recorder.Code)
|
||||
actualLocation := recorder.Header().Get("Location")
|
||||
r.True(
|
||||
strings.HasPrefix(actualLocation, downstreamRedirectURL),
|
||||
|
@ -2971,7 +2971,7 @@ func requireValidStoredRequest(
|
||||
|
||||
// At this time, we don't use any of these optional (per the OIDC spec) fields.
|
||||
require.Empty(t, claims.AuthenticationContextClassReference)
|
||||
require.Empty(t, claims.AuthenticationMethodsReference)
|
||||
require.Empty(t, claims.AuthenticationMethodsReferences)
|
||||
require.Empty(t, claims.CodeHash)
|
||||
}
|
||||
|
||||
|
@ -5,40 +5,10 @@ package plog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
//nolint: gochecknoglobals
|
||||
var removeKlogGlobalFlagsLock sync.Mutex
|
||||
|
||||
// RemoveKlogGlobalFlags attempts to "remove" flags that get unconditionally added by importing klog.
|
||||
func RemoveKlogGlobalFlags() {
|
||||
// since we mess with global state, we need a lock to synchronize us when called in parallel during tests
|
||||
removeKlogGlobalFlagsLock.Lock()
|
||||
defer removeKlogGlobalFlagsLock.Unlock()
|
||||
|
||||
// if this function starts to panic, it likely means that klog stopped mucking with global flags
|
||||
const globalLogFlushFlag = "log-flush-frequency"
|
||||
if err := pflag.CommandLine.MarkHidden(globalLogFlushFlag); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := pflag.CommandLine.MarkDeprecated(globalLogFlushFlag, "unsupported"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if pflag.CommandLine.Changed(globalLogFlushFlag) {
|
||||
panic("unsupported global klog flag set")
|
||||
}
|
||||
}
|
||||
|
||||
// KRef is (mostly) copied from klog - it is a standard way to represent a metav1.Object in logs
|
||||
// when you only have access to the namespace and name of the object.
|
||||
func KRef(namespace, name string) string {
|
||||
return fmt.Sprintf("%s/%s", namespace, name)
|
||||
}
|
||||
|
||||
// KObj is (mostly) copied from klog - it is a standard way to represent a metav1.Object in logs.
|
||||
func KObj(obj klog.KMetadata) string {
|
||||
return fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName())
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/sclevine/spec"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -71,11 +72,11 @@ func TestCreate(t *testing.T) {
|
||||
r = require.New(t)
|
||||
ctrl = gomock.NewController(t)
|
||||
logger = testutil.NewTranscriptLogger(t)
|
||||
klog.SetLogger(logger) // this is unfortunately a global logger, so can't run these tests in parallel :(
|
||||
klog.SetLogger(logr.New(logger)) // this is unfortunately a global logger, so can't run these tests in parallel :(
|
||||
})
|
||||
|
||||
it.After(func() {
|
||||
klog.SetLogger(nil)
|
||||
klog.ClearLogger()
|
||||
ctrl.Finish()
|
||||
})
|
||||
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@ -29,6 +28,7 @@ import (
|
||||
"k8s.io/component-base/logs"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/klog/v2/klogr"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned"
|
||||
@ -431,7 +431,6 @@ func runSupervisor(podInfo *downward.PodInfo, cfg *supervisor.Config) error {
|
||||
func main() error { // return an error instead of klog.Fatal to allow defer statements to run
|
||||
logs.InitLogs()
|
||||
defer logs.FlushLogs()
|
||||
plog.RemoveKlogGlobalFlags() // move this whenever the below code gets refactored to use cobra
|
||||
|
||||
klog.Infof("Running %s at %#v", rest.DefaultKubernetesUserAgent(), version.Get())
|
||||
klog.Infof("Command-line arguments were: %s %s %s", os.Args[0], os.Args[1], os.Args[2])
|
||||
|
@ -4,87 +4,10 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
)
|
||||
|
||||
func NewDeleteOptionsRecorder(client kubernetes.Interface, opts *[]metav1.DeleteOptions) kubernetes.Interface {
|
||||
return &clientWrapper{
|
||||
Interface: client,
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
type clientWrapper struct {
|
||||
kubernetes.Interface
|
||||
opts *[]metav1.DeleteOptions
|
||||
}
|
||||
|
||||
func (c *clientWrapper) CoreV1() corev1client.CoreV1Interface {
|
||||
return &coreWrapper{CoreV1Interface: c.Interface.CoreV1(), opts: c.opts}
|
||||
}
|
||||
|
||||
func (c *clientWrapper) AppsV1() appsv1client.AppsV1Interface {
|
||||
return &appsWrapper{AppsV1Interface: c.Interface.AppsV1(), opts: c.opts}
|
||||
}
|
||||
|
||||
type coreWrapper struct {
|
||||
corev1client.CoreV1Interface
|
||||
opts *[]metav1.DeleteOptions
|
||||
}
|
||||
|
||||
func (c *coreWrapper) Pods(namespace string) corev1client.PodInterface {
|
||||
return &podsWrapper{PodInterface: c.CoreV1Interface.Pods(namespace), opts: c.opts}
|
||||
}
|
||||
|
||||
func (c *coreWrapper) Secrets(namespace string) corev1client.SecretInterface {
|
||||
return &secretsWrapper{SecretInterface: c.CoreV1Interface.Secrets(namespace), opts: c.opts}
|
||||
}
|
||||
|
||||
type appsWrapper struct {
|
||||
appsv1client.AppsV1Interface
|
||||
opts *[]metav1.DeleteOptions
|
||||
}
|
||||
|
||||
func (c *appsWrapper) Deployments(namespace string) appsv1client.DeploymentInterface {
|
||||
return &deploymentsWrapper{DeploymentInterface: c.AppsV1Interface.Deployments(namespace), opts: c.opts}
|
||||
}
|
||||
|
||||
type podsWrapper struct {
|
||||
corev1client.PodInterface
|
||||
opts *[]metav1.DeleteOptions
|
||||
}
|
||||
|
||||
func (s *podsWrapper) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
|
||||
*s.opts = append(*s.opts, opts)
|
||||
return s.PodInterface.Delete(ctx, name, opts)
|
||||
}
|
||||
|
||||
type secretsWrapper struct {
|
||||
corev1client.SecretInterface
|
||||
opts *[]metav1.DeleteOptions
|
||||
}
|
||||
|
||||
func (s *secretsWrapper) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
|
||||
*s.opts = append(*s.opts, opts)
|
||||
return s.SecretInterface.Delete(ctx, name, opts)
|
||||
}
|
||||
|
||||
type deploymentsWrapper struct {
|
||||
appsv1client.DeploymentInterface
|
||||
opts *[]metav1.DeleteOptions
|
||||
}
|
||||
|
||||
func (s *deploymentsWrapper) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
|
||||
*s.opts = append(*s.opts, opts)
|
||||
return s.DeploymentInterface.Delete(ctx, name, opts)
|
||||
}
|
||||
|
||||
func NewPreconditions(uid types.UID, rv string) metav1.DeleteOptions {
|
||||
return metav1.DeleteOptions{
|
||||
Preconditions: &metav1.Preconditions{
|
||||
|
@ -1001,7 +1001,7 @@ func validateAuthcodeStorage(
|
||||
require.Empty(t, actualClaims.CodeHash)
|
||||
require.Empty(t, actualClaims.AccessTokenHash)
|
||||
require.Empty(t, actualClaims.AuthenticationContextClassReference)
|
||||
require.Empty(t, actualClaims.AuthenticationMethodsReference)
|
||||
require.Empty(t, actualClaims.AuthenticationMethodsReferences)
|
||||
|
||||
// Check that the custom Pinniped session data matches.
|
||||
require.Equal(t, wantCustomSessionData, storedSessionFromAuthcode.Custom)
|
||||
|
168
internal/testutil/testlogger/stdr_copied.go
Normal file
168
internal/testutil/testlogger/stdr_copied.go
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testlogger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"sort"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/go-logr/stdr"
|
||||
)
|
||||
|
||||
// newStdLogger returns a logr.Logger that matches the legacy v0.4.0 stdr.New implementation.
|
||||
// All unnecessary functionality has been stripped out. Avoid using this if possible.
|
||||
func newStdLogger(std stdr.StdLogger) logr.Logger {
|
||||
return logr.New(logger{
|
||||
std: std,
|
||||
prefix: "",
|
||||
values: nil,
|
||||
})
|
||||
}
|
||||
|
||||
type logger struct {
|
||||
std stdr.StdLogger
|
||||
prefix string
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
func (l logger) clone() logger {
|
||||
out := l
|
||||
l.values = copySlice(l.values)
|
||||
return out
|
||||
}
|
||||
|
||||
func copySlice(in []interface{}) []interface{} {
|
||||
out := make([]interface{}, len(in))
|
||||
copy(out, in)
|
||||
return out
|
||||
}
|
||||
|
||||
// Magic string for intermediate frames that we should ignore.
|
||||
const autogeneratedFrameName = "<autogenerated>"
|
||||
|
||||
// Discover how many frames we need to climb to find the caller. This approach
|
||||
// was suggested by Ian Lance Taylor of the Go team, so it *should* be safe
|
||||
// enough (famous last words).
|
||||
func framesToCaller() int {
|
||||
// 1 is the immediate caller. 3 should be too many.
|
||||
for i := 1; i < 3; i++ {
|
||||
_, file, _, _ := runtime.Caller(i + 1) // +1 for this function's frame
|
||||
if file != autogeneratedFrameName {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 1 // something went wrong, this is safe
|
||||
}
|
||||
|
||||
func flatten(kvList ...interface{}) string {
|
||||
keys := make([]string, 0, len(kvList))
|
||||
vals := make(map[string]interface{}, len(kvList))
|
||||
for i := 0; i < len(kvList); i += 2 {
|
||||
k, ok := kvList[i].(string)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("key is not a string: %s", pretty(kvList[i])))
|
||||
}
|
||||
var v interface{}
|
||||
if i+1 < len(kvList) {
|
||||
v = kvList[i+1]
|
||||
}
|
||||
keys = append(keys, k)
|
||||
vals[k] = v
|
||||
}
|
||||
sort.Strings(keys)
|
||||
buf := bytes.Buffer{}
|
||||
for i, k := range keys {
|
||||
v := vals[k]
|
||||
if i > 0 {
|
||||
buf.WriteRune(' ')
|
||||
}
|
||||
buf.WriteString(pretty(k))
|
||||
buf.WriteString("=")
|
||||
buf.WriteString(pretty(v))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func pretty(value interface{}) string {
|
||||
jb, _ := json.Marshal(value)
|
||||
return string(jb)
|
||||
}
|
||||
|
||||
func (l logger) Info(level int, msg string, kvList ...interface{}) {
|
||||
if l.Enabled(level) {
|
||||
builtin := make([]interface{}, 0, 4)
|
||||
builtin = append(builtin, "level", level, "msg", msg)
|
||||
builtinStr := flatten(builtin...)
|
||||
fixedStr := flatten(l.values...)
|
||||
userStr := flatten(kvList...)
|
||||
l.output(framesToCaller(), fmt.Sprintln(l.prefix, builtinStr, fixedStr, userStr))
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) Enabled(level int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (l logger) Error(err error, msg string, kvList ...interface{}) {
|
||||
builtin := make([]interface{}, 0, 4)
|
||||
builtin = append(builtin, "msg", msg)
|
||||
builtinStr := flatten(builtin...)
|
||||
var loggableErr interface{}
|
||||
if err != nil {
|
||||
loggableErr = err.Error()
|
||||
}
|
||||
errStr := flatten("error", loggableErr)
|
||||
fixedStr := flatten(l.values...)
|
||||
userStr := flatten(kvList...)
|
||||
l.output(framesToCaller(), fmt.Sprintln(l.prefix, builtinStr, errStr, fixedStr, userStr))
|
||||
}
|
||||
|
||||
func (l logger) output(calldepth int, s string) {
|
||||
depth := calldepth + 2 // offset for this adapter
|
||||
|
||||
// ignore errors - what can we really do about them?
|
||||
if l.std != nil {
|
||||
_ = l.std.Output(depth, s)
|
||||
} else {
|
||||
_ = log.Output(depth, s)
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) V(level int) logr.LogSink {
|
||||
return l.clone()
|
||||
}
|
||||
|
||||
// WithName returns a new logr.Logger with the specified name appended. stdr
|
||||
// uses '/' characters to separate name elements. Callers should not pass '/'
|
||||
// in the provided name string, but this library does not actually enforce that.
|
||||
func (l logger) WithName(name string) logr.LogSink {
|
||||
new := l.clone()
|
||||
if len(l.prefix) > 0 {
|
||||
new.prefix = l.prefix + "/"
|
||||
}
|
||||
new.prefix += name
|
||||
return new
|
||||
}
|
||||
|
||||
// WithValues returns a new logr.Logger with the specified key-and-values
|
||||
// saved.
|
||||
func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
|
||||
new := l.clone()
|
||||
new.values = append(new.values, kvList...)
|
||||
return new
|
||||
}
|
||||
|
||||
func (l logger) WithCallDepth(depth int) logr.LogSink {
|
||||
return l.clone()
|
||||
}
|
||||
|
||||
var _ logr.LogSink = logger{}
|
||||
var _ logr.CallDepthLogSink = logger{}
|
||||
|
||||
func (l logger) Init(info logr.RuntimeInfo) {}
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package testlogger implements a logr.Logger suitable for writing test assertions.
|
||||
// Package testlogger wraps logr.Logger to allow for writing test assertions.
|
||||
package testlogger
|
||||
|
||||
import (
|
||||
@ -17,20 +17,27 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Logger implements logr.Logger in a way that captures logs for test assertions.
|
||||
// Logger wraps logr.Logger in a way that captures logs for test assertions.
|
||||
type Logger struct {
|
||||
logr.Logger
|
||||
Logger logr.Logger
|
||||
t *testing.T
|
||||
buffer syncBuffer
|
||||
}
|
||||
|
||||
// New returns a new test Logger.
|
||||
// New returns a new test Logger. Use this for all new tests.
|
||||
func New(t *testing.T) *Logger {
|
||||
res := Logger{t: t}
|
||||
res.Logger = stdr.New(log.New(&res.buffer, "", 0))
|
||||
return &res
|
||||
}
|
||||
|
||||
// Deprecated: NewLegacy returns a new test Logger. Use this for old tests if necessary.
|
||||
func NewLegacy(t *testing.T) *Logger {
|
||||
res := New(t)
|
||||
res.Logger = newStdLogger(log.New(&res.buffer, "", 0))
|
||||
return res
|
||||
}
|
||||
|
||||
// Lines returns the lines written to the test logger.
|
||||
func (l *Logger) Lines() []string {
|
||||
l.t.Helper()
|
||||
|
@ -17,7 +17,7 @@ type TranscriptLogger struct {
|
||||
transcript []TranscriptLogMessage
|
||||
}
|
||||
|
||||
var _ logr.Logger = &TranscriptLogger{}
|
||||
var _ logr.LogSink = &TranscriptLogger{}
|
||||
|
||||
type TranscriptLogMessage struct {
|
||||
Level string
|
||||
@ -36,7 +36,7 @@ func (log *TranscriptLogger) Transcript() []TranscriptLogMessage {
|
||||
return result
|
||||
}
|
||||
|
||||
func (log *TranscriptLogger) Info(msg string, keysAndValues ...interface{}) {
|
||||
func (log *TranscriptLogger) Info(level int, msg string, keysAndValues ...interface{}) {
|
||||
log.lock.Lock()
|
||||
defer log.lock.Unlock()
|
||||
log.transcript = append(log.transcript, TranscriptLogMessage{
|
||||
@ -54,18 +54,20 @@ func (log *TranscriptLogger) Error(_ error, msg string, _ ...interface{}) {
|
||||
})
|
||||
}
|
||||
|
||||
func (*TranscriptLogger) Enabled() bool {
|
||||
func (log *TranscriptLogger) Enabled(level int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (log *TranscriptLogger) V(_ int) logr.Logger {
|
||||
func (log *TranscriptLogger) V(_ int) logr.LogSink {
|
||||
return log
|
||||
}
|
||||
|
||||
func (log *TranscriptLogger) WithName(_ string) logr.Logger {
|
||||
func (log *TranscriptLogger) WithName(_ string) logr.LogSink {
|
||||
return log
|
||||
}
|
||||
|
||||
func (log *TranscriptLogger) WithValues(_ ...interface{}) logr.Logger {
|
||||
func (log *TranscriptLogger) WithValues(_ ...interface{}) logr.LogSink {
|
||||
return log
|
||||
}
|
||||
|
||||
func (log *TranscriptLogger) Init(info logr.RuntimeInfo) {}
|
||||
|
@ -19,8 +19,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/stdr"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -1571,9 +1569,8 @@ func TestLogin(t *testing.T) { // nolint:gocyclo
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testLogger := testlogger.New(t)
|
||||
klog.SetLogger(testLogger)
|
||||
stdr.SetVerbosity(debugLogLevel) // set stdr's global log level to debug so the test logger will send output.
|
||||
testLogger := testlogger.NewLegacy(t) //nolint: staticcheck // old test with lots of log statements
|
||||
klog.SetLogger(testLogger.Logger)
|
||||
|
||||
tok, err := Login(tt.issuer, tt.clientID,
|
||||
WithContext(context.Background()),
|
||||
@ -1581,7 +1578,7 @@ func TestLogin(t *testing.T) { // nolint:gocyclo
|
||||
WithScopes([]string{"test-scope"}),
|
||||
WithSkipBrowserOpen(),
|
||||
tt.opt(t),
|
||||
WithLogger(testLogger),
|
||||
WithLogger(testLogger.Logger),
|
||||
)
|
||||
testLogger.Expect(tt.wantLogs)
|
||||
if tt.wantErr != "" {
|
||||
|
Loading…
Reference in New Issue
Block a user