mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-01-07 14:05:50 +00:00
pinniped CLI should print the audit-ID in certain error cases
Co-authored-by: Ryan Richard <richardry@vmware.com>
This commit is contained in:
@@ -204,7 +204,7 @@ func handleCreateOrUpdate(
|
|||||||
negotiatedSerializer runtime.NegotiatedSerializer,
|
negotiatedSerializer runtime.NegotiatedSerializer,
|
||||||
) (bool, *http.Response, error) {
|
) (bool, *http.Response, error) {
|
||||||
if req.GetBody == nil {
|
if req.GetBody == nil {
|
||||||
return true, nil, fmt.Errorf("unreadible body for request: %#v", middlewareReq) // this should never happen
|
return true, nil, fmt.Errorf("unreadable body for request: %#v", middlewareReq) // this should never happen
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := req.GetBody()
|
body, err := req.GetBody()
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import (
|
|||||||
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
|
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
|
||||||
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
|
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
|
||||||
"go.pinniped.dev/internal/httputil/httperr"
|
"go.pinniped.dev/internal/httputil/httperr"
|
||||||
|
"go.pinniped.dev/internal/httputil/roundtripper"
|
||||||
"go.pinniped.dev/internal/httputil/securityheader"
|
"go.pinniped.dev/internal/httputil/securityheader"
|
||||||
"go.pinniped.dev/internal/net/phttp"
|
"go.pinniped.dev/internal/net/phttp"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/plog"
|
||||||
@@ -357,6 +358,40 @@ type nopCache struct{}
|
|||||||
func (*nopCache) GetToken(SessionCacheKey) *oidctypes.Token { return nil }
|
func (*nopCache) GetToken(SessionCacheKey) *oidctypes.Token { return nil }
|
||||||
func (*nopCache) PutToken(SessionCacheKey, *oidctypes.Token) {}
|
func (*nopCache) PutToken(SessionCacheKey, *oidctypes.Token) {}
|
||||||
|
|
||||||
|
// maybePrintAuditID will choose to log the auditID when certain failure cases are detected,
|
||||||
|
// to give a breadcrumb for an admin to follow.
|
||||||
|
// Older Supervisors and other OIDC identity providers may not provide this header.
|
||||||
|
func maybePrintAuditID(rt http.RoundTripper) http.RoundTripper {
|
||||||
|
return roundtripper.WrapFunc(rt, func(r *http.Request) (*http.Response, error) {
|
||||||
|
path := r.URL.Path
|
||||||
|
response, responseErr := rt.RoundTrip(r)
|
||||||
|
if response != nil && response.Header.Get("audit-ID") != "" {
|
||||||
|
switch {
|
||||||
|
case response.StatusCode >= http.StatusMultipleChoices && response.StatusCode < http.StatusBadRequest:
|
||||||
|
// failing oauth2/authorize redirects from audit-enabled Supervisors
|
||||||
|
|
||||||
|
location, err := url.Parse(response.Header.Get(httpLocationHeaderName))
|
||||||
|
if err != nil || location.Query().Get("error") != "" {
|
||||||
|
plog.Info("Received auditID for failed request",
|
||||||
|
"path", path,
|
||||||
|
"statusCode", response.StatusCode,
|
||||||
|
"auditID", response.Header.Get("audit-ID"))
|
||||||
|
}
|
||||||
|
case response.StatusCode >= http.StatusBadRequest:
|
||||||
|
// failing discovery, oauth2/authorize, or oauth2/token responses from audit-enabled Supervisors
|
||||||
|
|
||||||
|
plog.Info("Received auditID for failed request",
|
||||||
|
"path", path,
|
||||||
|
"statusCode", response.StatusCode,
|
||||||
|
"auditID", response.Header.Get("audit-ID"))
|
||||||
|
default:
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response, responseErr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Login performs an OAuth2/OIDC authorization code login using a localhost listener.
|
// Login performs an OAuth2/OIDC authorization code login using a localhost listener.
|
||||||
func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, error) {
|
func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, error) {
|
||||||
h := handlerState{
|
h := handlerState{
|
||||||
@@ -379,7 +414,15 @@ func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, er
|
|||||||
getEnv: os.Getenv,
|
getEnv: os.Getenv,
|
||||||
listen: net.Listen,
|
listen: net.Listen,
|
||||||
stdinIsTTY: func() bool { return term.IsTerminal(stdin()) },
|
stdinIsTTY: func() bool { return term.IsTerminal(stdin()) },
|
||||||
getProvider: upstreamoidc.New,
|
getProvider: func(config *oauth2.Config, provider *coreosoidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||||
|
// can't use upstreamoidc.New here since it does not set the Name
|
||||||
|
return &upstreamoidc.ProviderConfig{
|
||||||
|
Name: issuer, // use the issuer as the Name
|
||||||
|
Config: config,
|
||||||
|
Provider: provider,
|
||||||
|
Client: client,
|
||||||
|
}
|
||||||
|
},
|
||||||
validateIDToken: func(ctx context.Context, provider *coreosoidc.Provider, audience string, token string) (*coreosoidc.IDToken, error) {
|
validateIDToken: func(ctx context.Context, provider *coreosoidc.Provider, audience string, token string) (*coreosoidc.IDToken, error) {
|
||||||
return provider.Verifier(&coreosoidc.Config{ClientID: audience}).Verify(ctx, token)
|
return provider.Verifier(&coreosoidc.Config{ClientID: audience}).Verify(ctx, token)
|
||||||
},
|
},
|
||||||
@@ -393,6 +436,8 @@ func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.httpClient.Transport = maybePrintAuditID(h.httpClient.Transport)
|
||||||
|
|
||||||
if h.cliToSendCredentials {
|
if h.cliToSendCredentials {
|
||||||
if h.loginFlow != "" {
|
if h.loginFlow != "" {
|
||||||
return nil, fmt.Errorf("do not use deprecated option WithCLISendingCredentials when using option WithLoginFlow")
|
return nil, fmt.Errorf("do not use deprecated option WithCLISendingCredentials when using option WithLoginFlow")
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ func (e *TestEnv) WithoutCapability(cap Capability) *TestEnv {
|
|||||||
// Please use this sparingly. We would prefer that a test run on every cluster type where it can possibly run, so
|
// Please use this sparingly. We would prefer that a test run on every cluster type where it can possibly run, so
|
||||||
// prefer to run everywhere when possible or use cluster capabilities when needed, rather than looking at the
|
// prefer to run everywhere when possible or use cluster capabilities when needed, rather than looking at the
|
||||||
// type of cluster to decide to skip a test. However, there are some tests that do not depend on or interact with
|
// type of cluster to decide to skip a test. However, there are some tests that do not depend on or interact with
|
||||||
// Kubernetes itself which really only need to run on on a single platform to give us the coverage that we desire.
|
// Kubernetes itself which really only need to run on a single platform to give us the coverage that we desire.
|
||||||
func (e *TestEnv) WithKubeDistribution(distro KubeDistro) *TestEnv {
|
func (e *TestEnv) WithKubeDistribution(distro KubeDistro) *TestEnv {
|
||||||
e.t.Helper()
|
e.t.Helper()
|
||||||
if e.KubernetesDistribution != distro {
|
if e.KubernetesDistribution != distro {
|
||||||
|
|||||||
Reference in New Issue
Block a user