mirror of
https://github.com/openziti/ziti.git
synced 2026-10-13 15:51:21 +00:00
Merge pull request #461 from openziti/add.api.session.timeout.response
adds expiration-seconds and expires-at headers
This commit is contained in:
@@ -126,28 +126,30 @@ func (ro *AuthRouter) authHandler(ae *env.AppEnv, rc *response.RequestContext, p
|
||||
ConfigTypes: configTypes,
|
||||
IPAddress: remoteIpStr,
|
||||
}
|
||||
sessionId, err := ae.Handlers.ApiSession.Create(s)
|
||||
apiSessionId, err := ae.Handlers.ApiSession.Create(s)
|
||||
|
||||
if err != nil {
|
||||
rc.RespondWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
session, err := ae.Handlers.ApiSession.Read(sessionId)
|
||||
updatedApiSesion, err := ae.Handlers.ApiSession.Read(apiSessionId)
|
||||
|
||||
if err != nil {
|
||||
logger.WithField("cause", err).Error("loading session by id resulted in an error")
|
||||
rc.RespondWithApiError(apierror.NewUnauthorized())
|
||||
}
|
||||
|
||||
apiSession := MapToCurrentApiSessionRestModel(session, ae.Config.SessionTimeoutDuration())
|
||||
rc.ApiSession = updatedApiSesion
|
||||
|
||||
apiSession := MapToCurrentApiSessionRestModel(updatedApiSesion, ae.Config.SessionTimeoutDuration())
|
||||
|
||||
envelope := &rest_model.CurrentAPISessionDetailEnvelope{Data: apiSession, Meta: &rest_model.Meta{}}
|
||||
|
||||
expiration := time.Time(*apiSession.ExpiresAt)
|
||||
cookie := http.Cookie{Name: ae.AuthCookieName, Value: token, Expires: expiration}
|
||||
|
||||
rc.ResponseWriter.Header().Set(ae.AuthHeaderName, session.Token)
|
||||
rc.ResponseWriter.Header().Set(ae.AuthHeaderName, updatedApiSesion.Token)
|
||||
http.SetCookie(rc.ResponseWriter, &cookie)
|
||||
ro.createTimer.UpdateSince(start)
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@ func (r *CaRouter) generateJwt(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
|
||||
rc.ResponseWriter.Header().Set("content-type", "application/jwt")
|
||||
response.AddVersionHeader(rc.ResponseWriter)
|
||||
response.AddSessionExpirationHeader(rc)
|
||||
rc.ResponseWriter.WriteHeader(http.StatusOK)
|
||||
_, _ = rc.ResponseWriter.Write([]byte(jwt))
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ func (factory *CurrentApiSessionLinkFactoryImpl) Links(entity models.Entity) res
|
||||
|
||||
func MapToCurrentApiSessionRestModel(s *model.ApiSession, sessionTimeout time.Duration) *rest_model.CurrentAPISessionDetail {
|
||||
expiresAt := strfmt.DateTime(s.UpdatedAt.Add(sessionTimeout))
|
||||
expirationSeconds := int64(s.ExpirationDuration.Seconds())
|
||||
apiSession := &rest_model.CurrentAPISessionDetail{
|
||||
APISessionDetail: rest_model.APISessionDetail{
|
||||
BaseEntity: BaseEntityToRestModel(s, CurrentApiSessionLinkFactory),
|
||||
@@ -67,7 +68,8 @@ func MapToCurrentApiSessionRestModel(s *model.ApiSession, sessionTimeout time.Du
|
||||
ConfigTypes: stringz.SetToSlice(s.ConfigTypes),
|
||||
IPAddress: &s.IPAddress,
|
||||
},
|
||||
ExpiresAt: &expiresAt,
|
||||
ExpiresAt: &expiresAt,
|
||||
ExpirationSeconds: &expirationSeconds,
|
||||
}
|
||||
|
||||
return apiSession
|
||||
|
||||
@@ -25,15 +25,18 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"go.etcd.io/bbolt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ApiSession struct {
|
||||
models.BaseEntity
|
||||
Token string
|
||||
IdentityId string
|
||||
Identity *Identity
|
||||
IPAddress string
|
||||
ConfigTypes map[string]struct{}
|
||||
Token string
|
||||
IdentityId string
|
||||
Identity *Identity
|
||||
IPAddress string
|
||||
ConfigTypes map[string]struct{}
|
||||
ExpiresAt time.Time
|
||||
ExpirationDuration time.Duration
|
||||
}
|
||||
|
||||
func (entity *ApiSession) toBoltEntity(tx *bbolt.Tx, handler Handler) (boltz.Entity, error) {
|
||||
@@ -74,6 +77,9 @@ func (entity *ApiSession) fillFrom(handler Handler, tx *bbolt.Tx, boltEntity bol
|
||||
entity.IdentityId = boltApiSession.IdentityId
|
||||
entity.ConfigTypes = stringz.SliceToSet(boltApiSession.ConfigTypes)
|
||||
entity.IPAddress = boltApiSession.IPAddress
|
||||
entity.ExpiresAt = entity.UpdatedAt.Add(handler.GetEnv().GetConfig().Api.SessionTimeoutSeconds)
|
||||
entity.ExpirationDuration = handler.GetEnv().GetConfig().Api.SessionTimeoutSeconds
|
||||
|
||||
boltIdentity, err := handler.GetEnv().GetStores().Identity.LoadOneById(tx, boltApiSession.IdentityId)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -21,9 +21,22 @@ import (
|
||||
"github.com/openziti/edge/build"
|
||||
version3 "github.com/openziti/edge/internal/version"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
ApiSessionExpirationSecondsHeader = "expiration-seconds"
|
||||
ApiSessionExpiresAtheader = "expires-at"
|
||||
)
|
||||
|
||||
func AddVersionHeader(rw http.ResponseWriter) {
|
||||
buildInfo := build.GetBuildInfo()
|
||||
rw.Header().Set(ZitiControllerVersionHeader, fmt.Sprintf("%s/%s/%s", buildInfo.Version(), buildInfo.Revision(), version3.GetApiVersion()))
|
||||
}
|
||||
|
||||
func AddSessionExpirationHeader(rc *RequestContext) {
|
||||
if rc.ApiSession != nil {
|
||||
rc.ResponseWriter.Header().Set(ApiSessionExpirationSecondsHeader, strconv.FormatInt(int64(rc.ApiSession.ExpirationDuration.Seconds()), 10))
|
||||
rc.ResponseWriter.Header().Set(ApiSessionExpiresAtheader, rc.ApiSession.ExpiresAt.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,14 +115,17 @@ func (responder *ResponderImpl) RespondWithOk(data interface{}, meta *rest_model
|
||||
}
|
||||
|
||||
func (responder *ResponderImpl) Respond(data interface{}, httpStatus int) {
|
||||
AddSessionExpirationHeader(responder.rc)
|
||||
Respond(responder.rc.ResponseWriter, responder.rc.Request.URL.Path, responder.rc.Id, responder.GetProducer(), data, httpStatus)
|
||||
}
|
||||
|
||||
func (responder *ResponderImpl) RespondWithError(err error) {
|
||||
AddSessionExpirationHeader(responder.rc)
|
||||
RespondWithError(responder.rc.ResponseWriter, responder.rc.Request, responder.rc.Id, responder.GetProducer(), err)
|
||||
}
|
||||
|
||||
func (responder *ResponderImpl) RespondWithApiError(apiError *apierror.ApiError) {
|
||||
AddSessionExpirationHeader(responder.rc)
|
||||
RespondWithApiError(responder.rc.ResponseWriter, responder.rc.Request, responder.rc.Id, responder.GetProducer(), apiError)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ import (
|
||||
type CurrentAPISessionDetail struct {
|
||||
APISessionDetail
|
||||
|
||||
// expiration seconds
|
||||
// Required: true
|
||||
ExpirationSeconds *int64 `json:"expirationSeconds"`
|
||||
|
||||
// expires at
|
||||
// Required: true
|
||||
// Format: date-time
|
||||
@@ -59,12 +63,16 @@ func (m *CurrentAPISessionDetail) UnmarshalJSON(raw []byte) error {
|
||||
|
||||
// AO1
|
||||
var dataAO1 struct {
|
||||
ExpirationSeconds *int64 `json:"expirationSeconds"`
|
||||
|
||||
ExpiresAt *strfmt.DateTime `json:"expiresAt"`
|
||||
}
|
||||
if err := swag.ReadJSON(raw, &dataAO1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.ExpirationSeconds = dataAO1.ExpirationSeconds
|
||||
|
||||
m.ExpiresAt = dataAO1.ExpiresAt
|
||||
|
||||
return nil
|
||||
@@ -80,9 +88,13 @@ func (m CurrentAPISessionDetail) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
_parts = append(_parts, aO0)
|
||||
var dataAO1 struct {
|
||||
ExpirationSeconds *int64 `json:"expirationSeconds"`
|
||||
|
||||
ExpiresAt *strfmt.DateTime `json:"expiresAt"`
|
||||
}
|
||||
|
||||
dataAO1.ExpirationSeconds = m.ExpirationSeconds
|
||||
|
||||
dataAO1.ExpiresAt = m.ExpiresAt
|
||||
|
||||
jsonDataAO1, errAO1 := swag.WriteJSON(dataAO1)
|
||||
@@ -102,6 +114,10 @@ func (m *CurrentAPISessionDetail) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateExpirationSeconds(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateExpiresAt(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
@@ -112,6 +128,15 @@ func (m *CurrentAPISessionDetail) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CurrentAPISessionDetail) validateExpirationSeconds(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("expirationSeconds", "body", m.ExpirationSeconds); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CurrentAPISessionDetail) validateExpiresAt(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("expiresAt", "body", m.ExpiresAt); err != nil {
|
||||
|
||||
@@ -99,4 +99,4 @@ func unmarshalPostureCheckList(data []byte, consumer runtime.Consumer) (PostureC
|
||||
switch getType.Empty {
|
||||
}
|
||||
return nil, errors.New(422, "invalid value: %q", getType.Empty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6583,9 +6583,13 @@ func init() {
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"expiresAt"
|
||||
"expiresAt",
|
||||
"expirationSeconds"
|
||||
],
|
||||
"properties": {
|
||||
"expirationSeconds": {
|
||||
"type": "integer"
|
||||
},
|
||||
"expiresAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
@@ -24882,9 +24886,13 @@ func init() {
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"expiresAt"
|
||||
"expiresAt",
|
||||
"expirationSeconds"
|
||||
],
|
||||
"properties": {
|
||||
"expirationSeconds": {
|
||||
"type": "integer"
|
||||
},
|
||||
"expiresAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
|
||||
@@ -4136,10 +4136,13 @@ definitions:
|
||||
- type: object
|
||||
required:
|
||||
- expiresAt
|
||||
- expirationSeconds
|
||||
properties:
|
||||
expiresAt:
|
||||
type: string
|
||||
format: date-time
|
||||
expirationSeconds:
|
||||
type: integer
|
||||
###################################################################
|
||||
# Identities
|
||||
##################################################################
|
||||
|
||||
Reference in New Issue
Block a user