Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
182 commits
Select commit Hold shift + click to select a range
bcbfd97
Initial commit
impl Sep 17, 2019
1d93e7c
Initial implementation
impl Sep 17, 2019
07eff71
Add expiration time to access token response
impl Sep 17, 2019
c24abf7
Add tests
impl Sep 18, 2019
f9741c7
New: Initial release
impl Sep 18, 2019
40a884d
Chore: Release 1.0.0
semantic-release-bot Sep 18, 2019
0079193
Update: Expose token type in credential response
impl Sep 19, 2019
c21d3a5
Chore: Release 1.1.0
semantic-release-bot Sep 19, 2019
506c6a3
Fix: Do not propagate API errors from providers when token refresh fails
impl Oct 7, 2019
95708bc
Merge pull request #1 from puppetlabs/bugs/token-refresh-failure-prop…
impl Oct 7, 2019
936623d
Chore: Release 1.1.1
semantic-release-bot Oct 7, 2019
e21370d
New: Add refresh_token option to creds write
DrDaveD Apr 6, 2020
a4f788f
Merge pull request #6 from DrDaveD/add-refresh-token-opt
impl Apr 6, 2020
24d64f6
Chore: Release 1.2.0
semantic-release-bot Apr 6, 2020
8ff7f19
New: add Google OAuth support
itdaniher Jul 13, 2020
e7b8fad
Merge pull request #11 from itdaniher/master
impl Jul 13, 2020
fed0930
Chore: Release 1.3.0
semantic-release-bot Jul 13, 2020
82f04ab
New: Add discovery_url
DrDaveD Aug 17, 2020
1500ea3
Fix: Use OptionError when discovery_url fails
DrDaveD Sep 28, 2020
8e81257
Update: expand characters allowed for creds path
DrDaveD Sep 28, 2020
2ad954c
Update: Give more complete oauth2 error messages
DrDaveD Sep 28, 2020
db06893
New: Add minimum_seconds credential read option
DrDaveD Aug 27, 2020
a490845
Chore: Release 1.4.0
semantic-release-bot Sep 28, 2020
69bbdc5
Update: move oauth2 error messages to log
DrDaveD Sep 28, 2020
29321dd
Fix: add keys to logger function calls
DrDaveD Sep 28, 2020
5a5ee4e
Update: use local Regex function instead of expanding framework function
DrDaveD Sep 28, 2020
33b26f5
Merge pull request #14 from DrDaveD/include-oauth-errors
impl Sep 28, 2020
e20393f
Chore: Release 1.5.0
semantic-release-bot Sep 28, 2020
2e39c7f
Merge pull request #13 from DrDaveD/expand-creds-characters
impl Sep 28, 2020
8667063
Chore: Release 1.6.0
semantic-release-bot Sep 28, 2020
e4df443
Merge remote branch 'upstream/master' into add-min-seconds
DrDaveD Oct 8, 2020
5c8f9d0
Update: Treat zero time as never expired
DrDaveD Oct 23, 2020
e171e5c
Update: Make sure retrieved token meets all requirements
DrDaveD Oct 23, 2020
257118e
New: Add tests for minimum_seconds
DrDaveD Oct 23, 2020
66cbf2a
Update: Rename tokenOk2Reuse to tokenValid
DrDaveD Oct 24, 2020
c83e8a9
Merge pull request #16 from DrDaveD/add-min-seconds
impl Oct 27, 2020
c54013b
Chore: Release 1.7.0
semantic-release-bot Oct 27, 2020
929fb14
Cache configuration and provider, use per-credential locking
impl Dec 16, 2020
2381173
Provide context to provider factory, allow extra data for tokens, stu…
impl Dec 16, 2020
b00f8e8
Propagate cache reset to provider
impl Dec 16, 2020
0b90b97
Add real OIDC provider
impl Dec 17, 2020
404be2f
Add initial OIDC testing, refactor test framework
impl Dec 17, 2020
478dc6a
Fix test
impl Dec 17, 2020
d53f55c
Update README, use constant-time comparison for nonce
impl Dec 17, 2020
3fa6320
First pass at removing semantic-release
impl Dec 17, 2020
eb55010
Update changelog, README
impl Dec 17, 2020
b01d901
Fix typo in test script
impl Dec 17, 2020
109c9f1
Track dependency version for Go tools
impl Dec 18, 2020
b06fd28
Merge pull request #23 from puppetlabs/tasks/update-builds
impl Dec 18, 2020
8862516
Remove unnecessary plugin-wide context
impl Dec 18, 2020
57c8fcc
Merge pull request #22 from puppetlabs/features/oidc
impl Dec 18, 2020
266a2f9
Release v1.8.0
impl Dec 18, 2020
dbaac20
Release v1.8.1
impl Dec 18, 2020
27b912d
Release v1.8.2
impl Dec 18, 2020
0532030
Release v1.8.3
impl Dec 18, 2020
ab87fd5
Allow the nonce to be empty
DrDaveD Jan 6, 2021
13980ca
Use a *provider.Token for mock exchanges instead of a *oauth2.Token
impl Jan 13, 2021
1cd515c
Merge pull request #28 from puppetlabs/improvements/provider-token-mo…
impl Jan 14, 2021
68935b2
Expose errors from underlying providers more helpfully
impl Jan 14, 2021
083d11c
Merge remote-tracking branch 'upstream/master' into allow-empty-nonce
DrDaveD Jan 14, 2021
ac00147
Update CHANGELOG, errmap version
impl Jan 14, 2021
78fe212
Make all OIDC verification errors user errors, as they will certainly…
impl Jan 14, 2021
ed7d18a
Merge pull request #29 from puppetlabs/improvements/error-status-codes
impl Jan 14, 2021
494e699
Merge pull request #27 from DrDaveD/allow-empty-nonce
impl Jan 16, 2021
fbeded5
Implement client credentials flow
impl Jan 15, 2021
c97fb9e
Merge pull request #30 from puppetlabs/features/client-creds-exchange
impl Jan 19, 2021
e0bcdcb
Make auth code URL optional
impl Jan 19, 2021
4649b1f
Only revalidate ID tokens if provided on refresh
impl Jan 19, 2021
3f48413
Merge pull request #31 from puppetlabs/improvements/optional-auth-cod…
impl Jan 19, 2021
65ca4a7
Merge pull request #32 from puppetlabs/bugs/id-token-refresh-revalida…
impl Jan 19, 2021
5121456
Release v1.9.0
impl Jan 19, 2021
ef8a97e
Stub interfaces and API for device grant support
impl Mar 10, 2021
81d089a
Add provider implementation for device code flow
impl Mar 11, 2021
0af86bb
Get basic device code flow working
impl Mar 12, 2021
981ddb2
Refactor logical storage to a separate package
impl Mar 16, 2021
c47f1db
Clean up tests, make sure we refresh tokens without dropping them
impl Mar 16, 2021
5879cee
Add device flow mock and test
hunner Mar 19, 2021
32cb36e
Fixup authorization pending mock error unwrap
hunner Mar 19, 2021
edf01ed
Skip funky test
hunner Mar 24, 2021
1d46ed2
Merge pull request #38 from puppetlabs/patch/device-test
impl Mar 24, 2021
f90d646
Merge pull request #37 from puppetlabs/features/device-grant
impl Mar 24, 2021
d03a16d
Release v1.10.0-beta.1
impl Mar 24, 2021
9933248
Update CHANGELOG for version
impl Mar 24, 2021
8ee85f3
Fix token refresh test
impl Mar 26, 2021
507208c
Clean up mock and add new device code exchange test for the backend
impl Mar 26, 2021
b91a348
Update README
impl Mar 26, 2021
9f91a49
Wait for scheduler
impl Mar 26, 2021
99ebaa8
Minor README adjustments
impl Mar 26, 2021
11d5d99
Fix client credential storage
impl Mar 28, 2021
091a762
Merge pull request #39 from puppetlabs/tasks/fix-refresh-test
impl Mar 29, 2021
0643339
Release v1.10.0
impl Mar 29, 2021
28eb662
Update: fix minimum_seconds option
DrDaveD Apr 5, 2021
c0261b4
Update: add refresh_interval option
DrDaveD Apr 5, 2021
ea94f08
Update: ran goimports
DrDaveD Apr 5, 2021
c720c1f
Make it explicit that a provider RefreshToken should force a refresh
impl Apr 6, 2021
e416b1b
Merge pull request #44 from puppetlabs/bugs/minimum-seconds-force-ref…
impl Apr 7, 2021
667e0ef
Correctly request updated user information when an OIDC token is refr…
impl Apr 6, 2021
b208d95
Merge pull request #45 from puppetlabs/bugs/userinfo-after-refresh
impl Apr 7, 2021
8298163
Release v1.10.1
impl Apr 7, 2021
0906d5b
Update: allow slash in credential names
DrDaveD Mar 31, 2021
111fed7
Unrestrict credential names
impl Apr 7, 2021
9093fdd
Merge pull request #46 from puppetlabs/improvements/cred-name-format
impl Apr 9, 2021
1b783c5
Release v2.0.0
impl Apr 9, 2021
18a797d
Update: change refresh_interval to tune_refresh_check_interval_seconds
DrDaveD Apr 12, 2021
1ab0af0
Update: improve tune_refresh_check_interval_seconds per code review
DrDaveD Apr 12, 2021
464aeb2
Update: change refresh_interval doc to tune_refresh_check_interval_se…
DrDaveD Apr 12, 2021
f92d3d3
Update: limit tune_refresh_check_interval_seconds to non-negative, 90…
DrDaveD Apr 14, 2021
ad43773
Merge pull request #43 from DrDaveD/add-refresh-interval
impl Apr 15, 2021
ae4e295
Implement the Google provider with OpenID Connect
impl Jun 17, 2021
4e51ce9
Merge pull request #53 from puppetlabs/improvements/google-oidc
impl Jun 23, 2021
7fb6810
feat: Add support for azure AD multitenant app
vavsab May 27, 2021
e87e292
Use an endpoint factory for all basic operations
impl Jun 16, 2021
b77bf12
Add support for storing provider options with a token
impl Jun 17, 2021
adc3c0a
Try to clarify which options apply where
impl Jun 17, 2021
dd7d7da
Add tests
impl Jun 17, 2021
61c234d
Allow specifying provider_options when generating auth code URLs
impl Jun 17, 2021
d3aeabb
Update README
impl Jun 23, 2021
a3c5dfd
Merge pull request #52 from puppetlabs/improvements/azure-ad-multitenant
impl Jun 23, 2021
49e7681
Add refresher tests
impl Jun 24, 2021
41fe001
Merge pull request #54 from puppetlabs/tasks/refresh-interval-tests
impl Jun 24, 2021
17fa81d
Release v2.1.0
impl Jun 24, 2021
7cfd028
Support versioned configurations, re-enable refresher for old configu…
impl Jun 25, 2021
dd2e9b5
Merge pull request #55 from puppetlabs/bugs/config-without-tuning
impl Jun 26, 2021
c7837cc
Release v2.1.1
impl Jun 26, 2021
6d9fe84
Document initial options for performance tuning
impl Jun 26, 2021
6514139
Implement reaper, support for auto-refresh expiry factor
impl Jul 10, 2021
df201af
Implement provider timeout options
impl Jul 12, 2021
752f810
Clean up interfaces for provider timeouts, add tests
impl Jul 12, 2021
a25eed4
Add tests for reaper
impl Jul 13, 2021
70cd349
Update performance tuning section of README, update CHANGELOG
impl Jul 13, 2021
9e47368
Merge pull request #56 from puppetlabs/improvements/tuning
impl Jul 13, 2021
9ca06fa
Release v2.2.0
impl Jul 13, 2021
4b1a2fb
Add support for multiple providers in one engine
impl Jul 22, 2021
06a4c81
Add upgrade path
impl Jul 22, 2021
e976cf6
Merge pull request #58 from puppetlabs/features/multiple-providers
impl Jul 23, 2021
ad4161a
Release v3.0.0-beta.1
impl Jul 23, 2021
a7bcdfc
Release v3.0.0-beta.2 to remove unsupported architecture darwin/386
impl Jul 23, 2021
b7fa7ee
Release v3.0.0-beta.3 to remove unsupported architecture darwin/386
impl Jul 23, 2021
16fdd55
Add support for setting a default server in the configuration
impl Sep 14, 2021
5e7ec97
Merge pull request #66 from puppetlabs/tasks/default-server
impl Sep 16, 2021
2d57caf
Add support for listing servers
impl Sep 15, 2021
2c0aa1a
Merge pull request #67 from puppetlabs/features/list-servers
impl Sep 16, 2021
79d33ca
Add support for reaping credentials that have no backing server
impl Sep 16, 2021
73efa32
Merge pull request #68 from puppetlabs/improvements/reap-missing-servers
impl Sep 16, 2021
38129e7
Release v3.0.0-beta.4
impl Sep 16, 2021
0c617e6
Avoid having to loop over all creds during upgrade
impl Sep 16, 2021
e23f49f
Merge pull request #70 from puppetlabs/improvements/upgrade-loop
impl Sep 16, 2021
40405a9
Add support for fallback client secrets
impl Sep 17, 2021
23cf037
Merge pull request #71 from puppetlabs/improvements/client-secrets-fa…
impl Sep 17, 2021
7da3702
Release v3.0.0-beta.5
impl Sep 17, 2021
ecf1423
Release v3.0.0
impl Sep 17, 2021
f7bcfee
Merge pull request #72 from puppetlabs/tasks/release-3.0.0
impl Sep 20, 2021
9a0923d
Update: implement RFC 8693 token exchange
DrDaveD Sep 21, 2021
67c8a8a
Add support for custom expiry time in refresh token flow, for apps th…
RGulSecuritiAI Dec 19, 2022
4b32d96
Merge pull request #75 from RehmatGul0/features/tokenrefresh-support-…
impl Jan 11, 2023
4cdcdf1
Update package versions for linting and testing
impl Jan 13, 2023
f10ba06
Make maximum token expiry a top-level endpoint option, add tests
impl Jan 16, 2023
a24006e
Update to Go 1.18
impl Jan 16, 2023
2fa62cc
Move upgrade to initialization callback
impl Jan 17, 2023
271df37
Merge pull request #77 from puppetlabs/stage-token-custom-expiry
impl Jan 17, 2023
51e3c95
Merge pull request #41 from DrDaveD/merge-exchange-with-main
impl Jan 17, 2023
76ae9c4
Move STS operations to a separate sts/ endpoint
impl Jan 18, 2023
5313a08
Merge pull request #78 from puppetlabs/stage-sts
impl Jan 23, 2023
aff5fae
Release v3.1.0
impl Jan 23, 2023
dd0bde8
add STSPathPrefix to pathsSpecial
DrDaveD Feb 1, 2023
4dade1d
Merge pull request #79 from DrDaveD/fix-sts-path
impl Feb 2, 2023
b5c2d7b
Release v3.1.1
impl Feb 2, 2023
e2f5311
Update dependencies
impl Mar 30, 2023
5f513c1
Support for Apple Silicon
lucymhdavies Jan 5, 2024
0a05056
Merge pull request #88 from lucymhdavies/apple-silicon
impl Jan 5, 2024
b1e7c53
add caching of STS-exchanged access tokens
DrDaveD Mar 7, 2025
c0ff92d
Merge pull request #1 from DrDaveD/cache-sts-tokens
DrDaveD Mar 7, 2025
4fad35c
updates for move to openbao
DrDaveD Mar 7, 2025
0fadf71
change from hashicorp/vault apis to openbao/openbao v2
DrDaveD Mar 7, 2025
b58013c
update to latest golangci-lint v1.64.6
DrDaveD Mar 11, 2025
aee1989
update for 3.2.0 (#11)
DrDaveD Mar 12, 2025
d2cfcd2
Bump github.com/openbao/openbao/sdk/v2 from 2.3.1 to 2.4.0 (#27)
dependabot[bot] Sep 5, 2025
fb10778
Merge secrets/oauthapp plugin
JanMa Dec 6, 2025
d4f4444
secrets-oauthapp: fix imports
JanMa Dec 6, 2025
df695f3
secrets-consul: fix broken import
JanMa Dec 7, 2025
9842129
update internal/http
JanMa Dec 7, 2025
4d35426
vendor dependencies
JanMa Dec 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
15 changes: 0 additions & 15 deletions auth/gcp/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

347 changes: 262 additions & 85 deletions go.mod

Large diffs are not rendered by default.

1,235 changes: 992 additions & 243 deletions go.sum

Large diffs are not rendered by default.

181 changes: 86 additions & 95 deletions internal/http/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,42 +175,41 @@ func handler(props *vault.HandlerProperties) http.Handler {
mux.Handle("/v1/sys/init", handleSysInit(core))
mux.Handle("/v1/sys/seal-status", handleSysSealStatus(core))
mux.Handle("/v1/sys/seal", handleSysSeal(core))
mux.Handle("/v1/sys/step-down", handleRequestForwarding(core, handleSysStepDown(core)))
mux.Handle("/v1/sys/step-down", handleSysStepDown(core))
mux.Handle("/v1/sys/unseal", handleSysUnseal(core))
mux.Handle("/v1/sys/leader", handleSysLeader(core))
mux.Handle("/v1/sys/health", handleSysHealth(core))
mux.Handle("/v1/sys/monitor", handleLogicalNoForward(core))

mux.Handle("/v1/sys/generate-root/attempt", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysGenerateRootAttempt(core, vault.GenerateStandardRootTokenStrategy))))
mux.Handle("/v1/sys/generate-root/update", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysGenerateRootUpdate(core, vault.GenerateStandardRootTokenStrategy))))
mux.Handle("/v1/sys/generate-root/attempt",
handleAuditNonLogical(core, handleSysGenerateRootAttempt(core, vault.GenerateStandardRootTokenStrategy)))
mux.Handle("/v1/sys/generate-root/update",
handleAuditNonLogical(core, handleSysGenerateRootUpdate(core, vault.GenerateStandardRootTokenStrategy)))

// Register without unauthenticated rekey, if necessary.
if props.ListenerConfig == nil || !props.ListenerConfig.DisableUnauthedRekeyEndpoints {
mux.Handle("/v1/sys/rekey/init", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysRekeyInit(core, false))))
mux.Handle("/v1/sys/rekey/update", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysRekeyUpdate(core, false))))
mux.Handle("/v1/sys/rekey/verify", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysRekeyVerify(core, false))))
mux.Handle("/v1/sys/rekey-recovery-key/init", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysRekeyInit(core, true))))
mux.Handle("/v1/sys/rekey-recovery-key/update", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysRekeyUpdate(core, true))))
mux.Handle("/v1/sys/rekey-recovery-key/verify", handleRequestForwarding(core,
handleAuditNonLogical(core, handleSysRekeyVerify(core, true))))
if props.ListenerConfig != nil && props.ListenerConfig.DisableUnauthedRekeyEndpoints != nil && !*props.ListenerConfig.DisableUnauthedRekeyEndpoints {
mux.Handle("/v1/sys/rekey/init",
handleAuditNonLogical(core, handleSysRekeyInit(core, false)))
mux.Handle("/v1/sys/rekey/update",
handleAuditNonLogical(core, handleSysRekeyUpdate(core, false)))
mux.Handle("/v1/sys/rekey/verify",
handleAuditNonLogical(core, handleSysRekeyVerify(core, false)))
mux.Handle("/v1/sys/rekey-recovery-key/init",
handleAuditNonLogical(core, handleSysRekeyInit(core, true)))
mux.Handle("/v1/sys/rekey-recovery-key/update",
handleAuditNonLogical(core, handleSysRekeyUpdate(core, true)))
mux.Handle("/v1/sys/rekey-recovery-key/verify",
handleAuditNonLogical(core, handleSysRekeyVerify(core, true)))
}

mux.Handle("/v1/sys/storage/raft/bootstrap", handleSysRaftBootstrap(core))
mux.Handle("/v1/sys/storage/raft/join", handleSysRaftJoin(core))
mux.Handle("/v1/sys/internal/ui/feature-flags", handleSysInternalFeatureFlags(core))

for _, path := range injectDataIntoTopRoutes {
mux.Handle(path, handleRequestForwarding(core, handleLogicalWithInjector(core)))
mux.Handle(path, handleLogicalWithInjector(core))
}
mux.Handle("/v1/sys/", handleRequestForwarding(core, handleLogical(core)))
mux.Handle("/v1/", handleRequestForwarding(core, handleLogical(core)))
mux.Handle("/v1/sys/", handleLogical(core))
mux.Handle("/v1/", handleLogical(core))
if core.UIEnabled() {
if uiBuiltIn {
mux.Handle("/ui/", http.StripPrefix("/ui/", gziphandler.GzipHandler(handleUIHeaders(core, handleUI(http.FileServer(&UIAssetWrapper{FileSystem: assetFS()}))))))
Expand Down Expand Up @@ -256,8 +255,8 @@ func handler(props *vault.HandlerProperties) http.Handler {
corsWrappedHandler := wrapCORSHandler(helpWrappedHandler, core)
quotaWrappedHandler := rateLimitQuotaWrapping(corsWrappedHandler, core)
genericWrappedHandler := genericWrapping(core, quotaWrappedHandler, props)
wrappedHandler := wrapMaxRequestSizeHandler(genericWrappedHandler, props)

metricsWrappedHandler := wrapMetricsListenerHandler(genericWrappedHandler, props)
wrappedHandler := wrapMaxRequestSizeHandler(metricsWrappedHandler, props)
// Wrap the handler with PrintablePathCheckHandler to check for non-printable
// characters in the request path.
printablePathCheckHandler := wrappedHandler
Expand Down Expand Up @@ -300,15 +299,11 @@ func (w *copyResponseWriter) WriteHeader(code int) {

func handleAuditNonLogical(core *vault.Core, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origBody := new(bytes.Buffer)
reader := io.NopCloser(io.TeeReader(r.Body, origBody))
r.Body = reader
req, _, status, err := buildLogicalRequestNoAuth(w, r)
req, status, err := buildLogicalRequestNoAuth(w, r)
if err != nil || status != 0 {
respondError(w, status, err)
return
}
r.Body = io.NopCloser(origBody)
input := &logical.LogInput{
Request: req,
}
Expand All @@ -321,10 +316,8 @@ func handleAuditNonLogical(core *vault.Core, h http.Handler) http.Handler {
cw := newCopyResponseWriter(w)
h.ServeHTTP(cw, r)
data := make(map[string]interface{})
err = jsonutil.DecodeJSON(cw.body.Bytes(), &data)
if err != nil {
// best effort, ignore
}
// best effort, ignore error
_ = jsonutil.DecodeJSON(cw.body.Bytes(), &data)
httpResp := &logical.HTTPResponse{Data: data, Headers: cw.Header()}
input.Response = logical.HTTPResponseToLogicalResponse(httpResp)
err = core.AuditLogger().AuditResponse(ctx, input)
Expand All @@ -339,12 +332,23 @@ func handleAuditNonLogical(core *vault.Core, h http.Handler) http.Handler {
// are performed.
func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerProperties) http.Handler {
var maxRequestDuration time.Duration
var maxRequestJsonMemory int64
var maxRequestJsonStrings int64
if props.ListenerConfig != nil {
maxRequestDuration = props.ListenerConfig.MaxRequestDuration
maxRequestJsonMemory = props.ListenerConfig.MaxRequestJsonMemory
maxRequestJsonStrings = props.ListenerConfig.MaxRequestJsonStrings
}
if maxRequestDuration == 0 {
maxRequestDuration = vault.DefaultMaxRequestDuration
}
if maxRequestJsonMemory == 0 {
maxRequestJsonMemory = vault.DefaultMaxJsonMemory
}
if maxRequestJsonStrings == 0 {
maxRequestJsonStrings = vault.DefaultMaxJsonStrings
}

// Swallow this error since we don't want to pollute the logs and we also don't want to
// return an HTTP error here. This information is best effort.
hostname, _ := os.Hostname()
Expand Down Expand Up @@ -386,6 +390,10 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
nw.Header().Set(consts.NamespaceHeaderName, nsHeader)
}

// Safely limit our input JSON
ctx = addMaximumJsonMemoryToContext(ctx, maxRequestJsonMemory)
ctx = addMaximumJsonStringsToContext(ctx, maxRequestJsonStrings)

ctx = namespace.ContextWithNamespaceHeader(ctx, nsHeader)
r = r.WithContext(ctx)

Expand Down Expand Up @@ -571,21 +579,6 @@ func WrapForwardedForHandler(h http.Handler, l *configutil.Listener) http.Handle
})
}

// stripPrefix is a helper to strip a prefix from the path. It will
// return false from the second return value if it the prefix doesn't exist.
func stripPrefix(prefix, path string) (string, bool) {
if !strings.HasPrefix(path, prefix) {
return "", false
}

path = path[len(prefix):]
if path == "" {
return "", false
}

return path, true
}

func handleUIHeaders(core *vault.Core, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
header := w.Header()
Expand Down Expand Up @@ -686,7 +679,7 @@ func handleUIStub() http.Handler {

func handleUIRedirect() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, "/ui/", 307)
http.Redirect(w, req, "/ui/", http.StatusTemporaryRedirect)
})
}

Expand Down Expand Up @@ -730,15 +723,31 @@ func parseQuery(values url.Values) map[string]interface{} {
return nil
}

func parseJSONRequest(r *http.Request, w http.ResponseWriter, out interface{}) (io.ReadCloser, error) {
// Limit the maximum number of bytes to MaxRequestSize to protect
// against an indefinite amount of data being read.
reader := r.Body
err := jsonutil.DecodeJSONFromReader(reader, out)
func parseJSONRequest(r *http.Request, w http.ResponseWriter, out interface{}) error {
ctx := r.Context()

// Enforce limits on JSON complexity.
_, _, err := EnforceJSONComplexityLimits(ctx, r.Body)
if err != nil {
return fmt.Errorf("failed to limit JSON input: %w", err)
}

// Reset to the beginning.
if err := resetBody(r); err != nil {
return fmt.Errorf("failed to reset body: %w", err)
}

err = jsonutil.DecodeJSONFromReader(r.Body, out)
if err != nil && err != io.EOF {
return nil, fmt.Errorf("failed to parse JSON input: %w", err)
return fmt.Errorf("failed to parse JSON input: %w", err)
}
return nil, err

// Reset to the beginning again.
if err := resetBody(r); err != nil {
return fmt.Errorf("failed to reset body: %w", err)
}

return err
}

// parseFormRequest parses values from a form POST.
Expand Down Expand Up @@ -769,47 +778,32 @@ func parseFormRequest(r *http.Request) (map[string]interface{}, error) {
return data, nil
}

// handleRequestForwarding determines whether to forward a request or not,
// falling back on the older behavior of redirecting the client
func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Note: in an HA setup, this call will also ensure that connections to
// the leader are set up, as that happens once the advertised cluster
// values are read during this function
isLeader, leaderAddr, _, err := core.Leader()
if err != nil {
if err == vault.ErrHANotEnabled {
// Standalone node, serve request normally
handler.ServeHTTP(w, r)
return
}
// Some internal error occurred
respondError(w, http.StatusInternalServerError, err)
return
}
if isLeader {
// No forwarding needed, we're leader
handler.ServeHTTP(w, r)
return
}
if leaderAddr == "" {
respondError(w, http.StatusInternalServerError, errors.New("local node not active but active cluster node not found"))
return
}

forwardRequest(core, w, r)
})
}

func forwardRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) {
// Reset our body before forwarding to ensure an accurate location.
if err := resetBody(r); err != nil {
respondStandby(core, w, r.URL)
return
}

if r.Header.Get(vault.IntNoForwardingHeaderName) != "" {
respondStandby(core, w, r.URL)
return
}

_, leaderAddr, _, err := core.Leader()
if err != nil {
// Some internal error occurred
respondError(w, http.StatusInternalServerError, err)
return
}
if leaderAddr == "" {
respondError(w, http.StatusInternalServerError, errors.New("local node not active but active cluster node not found"))
return
}

if r.Header.Get(NoRequestForwardingHeaderName) != "" {
// Forwarding explicitly disabled, fall back to previous behavior
core.Logger().Debug("handleRequestForwarding: forwarding disabled by client request")
core.Logger().Debug("forwardRequest: forwarding disabled by client request")
respondStandby(core, w, r.URL)
return
}
Expand Down Expand Up @@ -847,11 +841,8 @@ func forwardRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) {
// case of an error.
func request(core *vault.Core, w http.ResponseWriter, rawReq *http.Request, r *logical.Request) (*logical.Response, bool, bool) {
resp, err := core.HandleRequest(rawReq.Context(), r)
if errwrap.Contains(err, consts.ErrStandby.Error()) {
respondStandby(core, w, rawReq.URL)
return resp, false, false
}
if err != nil && errwrap.Contains(err, logical.ErrPerfStandbyPleaseForward.Error()) {

if logical.ShouldForward(err) || (resp != nil && logical.ShouldForward(resp.Error())) {
return nil, false, true
}

Expand Down Expand Up @@ -943,7 +934,7 @@ func respondStandby(core *vault.Core, w http.ResponseWriter, reqURL *url.URL) {
// because we don't actually know if its permanent and
// the request method should be preserved.
w.Header().Set("Location", finalURL.String())
w.WriteHeader(307)
w.WriteHeader(http.StatusTemporaryRedirect)
}

// getTokenFromReq parse headers of the incoming request to extract token if
Expand Down
11 changes: 5 additions & 6 deletions internal/http/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ import (

func wrapHelpHandler(h http.Handler, core *vault.Core) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
// If the help parameter is not blank, then show the help. We request
// forward because standby nodes do not have mounts and other state.
// If the help parameter is not blank, then show the help.
if v := req.URL.Query().Get("help"); v != "" || req.Method == "HELP" {
handleRequestForwarding(core,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handleHelp(core, w, r)
})).ServeHTTP(writer, req)
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handleHelp(core, w, r)
}).ServeHTTP(writer, req)
return
}

Expand All @@ -30,6 +28,7 @@ func wrapHelpHandler(h http.Handler, core *vault.Core) http.Handler {

func handleHelp(core *vault.Core, w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/v1/") {
//nolint:staticcheck // User facing error
respondError(w, http.StatusNotFound, errors.New("Missing /v1/ prefix in path. Use vault path-help command to retrieve API help for paths"))
return
}
Expand Down
Loading
Loading