mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2025-12-23 14:25: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,
|
||||
) (bool, *http.Response, error) {
|
||||
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()
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
|
||||
"go.pinniped.dev/internal/federationdomain/upstreamprovider"
|
||||
"go.pinniped.dev/internal/httputil/httperr"
|
||||
"go.pinniped.dev/internal/httputil/roundtripper"
|
||||
"go.pinniped.dev/internal/httputil/securityheader"
|
||||
"go.pinniped.dev/internal/net/phttp"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
@@ -357,6 +358,40 @@ type nopCache struct{}
|
||||
func (*nopCache) GetToken(SessionCacheKey) *oidctypes.Token { return nil }
|
||||
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.
|
||||
func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, error) {
|
||||
h := handlerState{
|
||||
@@ -379,7 +414,15 @@ func Login(issuer string, clientID string, opts ...Option) (*oidctypes.Token, er
|
||||
getEnv: os.Getenv,
|
||||
listen: net.Listen,
|
||||
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) {
|
||||
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.loginFlow != "" {
|
||||
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
|
||||
// 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
|
||||
// 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 {
|
||||
e.t.Helper()
|
||||
if e.KubernetesDistribution != distro {
|
||||
|
||||
Reference in New Issue
Block a user