mirror of
https://github.com/openziti/ziti.git
synced 2026-09-10 16:55:41 +00:00
f1264086d4
- resolves zt-session tokens eagerly when the request context is created, so every request carrying one marks activity and gets session lifetime headers, regardless of endpoint - marks last activity in SecurityCtx.resolveZtSession once the session is loaded - adds SecurityTokenCtx.HasZtSessionHeader, a header-only check that does not parse bearer tokens - emits only session lifetime headers from the API wrappers and drops the unused session-error header branch, so a stale token on an anonymous endpoint stays silent as it did on 1.6.x - tests that requests to authenticated and anonymous endpoints with a zt-session mark activity, carry lifetime headers, and are reflected by current-api-session
85 lines
2.8 KiB
Go
85 lines
2.8 KiB
Go
/*
|
|
Copyright NetFoundry Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package response
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
|
|
"github.com/openziti/foundation/v2/errorz"
|
|
"github.com/openziti/ziti/v2/common/build"
|
|
)
|
|
|
|
const (
|
|
ApiSessionExpirationSecondsHeader = "expiration-seconds"
|
|
ApiSessionExpiresAtHeader = "expires-at"
|
|
ServerHeader = "server"
|
|
)
|
|
|
|
// AddHeaders sets standard response headers for every API response, including the server
|
|
// version banner and API-session expiry information.
|
|
func AddHeaders(rc *RequestContext) {
|
|
buildInfo := build.GetBuildInfo()
|
|
if buildInfo != nil {
|
|
rc.ResponseWriter.Header().Set(ServerHeader, "ziti-controller/"+buildInfo.Version())
|
|
}
|
|
|
|
addApiSessionLifetimeHeaders(rc)
|
|
}
|
|
|
|
// AddApiSessionHeaders writes API-session lifetime headers when a resolved session is
|
|
// available, and appends WWW-Authenticate or other structured error headers from any
|
|
// MFA error so that clients can determine the next required action. Session-level errors
|
|
// are not reported here; the unauthorized response for a protected endpoint carries them.
|
|
func AddApiSessionHeaders(rc *RequestContext) {
|
|
if !addApiSessionLifetimeHeaders(rc) {
|
|
return
|
|
}
|
|
|
|
if mfaErr := rc.SecurityCtx.GetMfaErrorWithoutResolve(); mfaErr != nil {
|
|
addApiErrorHeaders(rc, mfaErr)
|
|
}
|
|
}
|
|
|
|
// addApiSessionLifetimeHeaders writes the expiration headers for an already-resolved API
|
|
// session and reports whether a session was present.
|
|
func addApiSessionLifetimeHeaders(rc *RequestContext) bool {
|
|
apiSession, _ := rc.SecurityCtx.GetApiSessionWithoutResolve()
|
|
if apiSession == nil {
|
|
return false
|
|
}
|
|
|
|
rc.ResponseWriter.Header().Set(ApiSessionExpirationSecondsHeader, strconv.FormatInt(int64(apiSession.ExpirationDuration.Seconds()), 10))
|
|
rc.ResponseWriter.Header().Set(ApiSessionExpiresAtHeader, apiSession.ExpiresAt.String())
|
|
return true
|
|
}
|
|
|
|
// addApiErrorHeaders extracts header key-value pairs from an errorz.ApiError and writes
|
|
// them to the response. This allows structured errors (e.g., WWW-Authenticate challenges)
|
|
// to propagate their metadata directly to the HTTP client.
|
|
func addApiErrorHeaders(rc *RequestContext, err error) {
|
|
apiErr := &errorz.ApiError{}
|
|
|
|
if errors.As(err, &apiErr) {
|
|
for key, values := range apiErr.Headers {
|
|
for _, value := range values {
|
|
rc.ResponseWriter.Header().Add(key, value)
|
|
}
|
|
}
|
|
}
|
|
}
|