From aaad1e3c8ca3804e9bfca64d8b30158b781187df Mon Sep 17 00:00:00 2001 From: Lexman Date: Mon, 15 Jul 2019 11:04:45 -0700 Subject: [PATCH] adds Cache-Control header to oidc .well-known endpoints (#7108) --- http/logical.go | 4 ++++ sdk/logical/response.go | 4 ++++ vault/identity_store_oidc.go | 26 +++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/http/logical.go b/http/logical.go index ac9326af7e..b9481bc61f 100644 --- a/http/logical.go +++ b/http/logical.go @@ -456,6 +456,10 @@ WRITE_RESPONSE: w.Header().Set("Content-Type", contentType) } + if cacheControl, ok := resp.Data[logical.HTTPRawCacheControl].(string); ok { + w.Header().Set("Cache-Control", cacheControl) + } + w.WriteHeader(status) w.Write(body) } diff --git a/sdk/logical/response.go b/sdk/logical/response.go index 7f8dbab851..ecc208f96e 100644 --- a/sdk/logical/response.go +++ b/sdk/logical/response.go @@ -33,6 +33,10 @@ const ( // that it has already been unmarshaled. That way we don't need to simply // ignore errors. HTTPRawBodyAlreadyJSONDecoded = "http_raw_body_already_json_decoded" + + // If set, HTTPRawCacheControl will replace the default Cache-Control=no-store header + // set by the generic wrapping handler. The value must be a string. + HTTPRawCacheControl = "http_raw_cache_control" ) // Response is a struct that stores the response of a request. diff --git a/vault/identity_store_oidc.go b/vault/identity_store_oidc.go index b7120c96f0..0090c997b9 100644 --- a/vault/identity_store_oidc.go +++ b/vault/identity_store_oidc.go @@ -1018,9 +1018,10 @@ func (i *IdentityStore) pathOIDCDiscovery(ctx context.Context, req *logical.Requ resp := &logical.Response{ Data: map[string]interface{}{ - logical.HTTPStatusCode: 200, - logical.HTTPRawBody: data, - logical.HTTPContentType: "application/json", + logical.HTTPStatusCode: 200, + logical.HTTPRawBody: data, + logical.HTTPContentType: "application/json", + logical.HTTPRawCacheControl: "max-age=3600", }, } @@ -1061,6 +1062,25 @@ func (i *IdentityStore) pathOIDCReadPublicKeys(ctx context.Context, req *logical }, } + // set a Cache-Control header only if there are keys, if there aren't keys + // then nextRun should not be used to set Cache-Control header because it chooses + // a time in the future that isn't based on key rotation/expiration values + keys, err := listOIDCPublicKeys(ctx, req.Storage) + if err != nil { + return nil, err + } + if len(keys) > 0 { + if v, ok := i.oidcCache.Get(nilNamespace, "nextRun"); ok { + now := time.Now() + expireAt := v.(time.Time) + if expireAt.After(now) { + expireInSeconds := expireAt.Sub(time.Now()).Seconds() + expireInString := fmt.Sprintf("max-age=%.0f", expireInSeconds) + resp.Data[logical.HTTPRawCacheControl] = expireInString + } + } + } + return resp, nil }