Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 101 additions & 2 deletions db-connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -5056,7 +5056,7 @@ func GetOpenApiDatastore(ctx context.Context, id string) (ParsedOpenApi, error)
}

// Index = Username
func SetSession(ctx context.Context, user User, value string) error {
func SetSession(ctx context.Context, user *User, value string) error {
//parsedKey := strings.ToLower(user.Username)
// Non indexed User data
parsedKey := user.Id
Expand All @@ -5068,6 +5068,12 @@ func SetSession(ctx context.Context, user User, value string) error {

user.Session = value

now := time.Now().Unix()
if user.SessionCreatedAt == 0 {
user.SessionCreatedAt = now
}
user.SessionLastActivityAt = now

nameKey := "Users"
if project.DbType == "opensearch" {
data, err := json.Marshal(user)
Expand Down Expand Up @@ -5119,6 +5125,15 @@ func SetSession(ctx context.Context, user User, value string) error {
}
}

// Always invalidate the cache entry for the (possibly reused) current
// session token after a successful write. Without this, reusing an
// existing token (e.g. SSO re-login for a user with an active session)
// left the previous cache invalidation branch above a no-op, allowing
// GetSessionNew to keep serving a stale SessionLastActivityAt snapshot
// for up to the cache TTL - which could incorrectly trip the idle/max
// session lifetime check and bounce the user back to /login.
DeleteCache(ctx, fmt.Sprintf("session_%s", user.Session))

return nil
}

Expand Down Expand Up @@ -9955,6 +9970,72 @@ func GetPipelines(ctx context.Context, OrgId string) ([]Pipeline, error) {
return pipelines, nil
}

// getSessionUserRealtime looks up the User owning sessionId via two
// real-time (non-search) OpenSearch Document.Get calls: first the "sessions"
// index (keyed by the session token itself as document ID, see SetSession),
// then the "Users" index (keyed by user ID). Both Document.Get reads are
// immediately consistent, unlike _search, which is only eventually
// consistent up to the index refresh_interval. Returns (User{}, false) for
// any failure (not found, decode error, mismatch) so callers can fall back
// to the _search-based lookup.
func getSessionUserRealtime(ctx context.Context, sessionId string) (User, bool) {
sessionResp, err := project.Es.Document.Get(ctx, opensearchapi.DocumentGetReq{
Index: strings.ToLower(GetESIndexPrefix("sessions")),
DocumentID: sessionId,
})
if err != nil {
return User{}, false
}

sessionRes := sessionResp.Inspect().Response
defer sessionRes.Body.Close()
if sessionRes.StatusCode != 200 && sessionRes.StatusCode != 201 {
return User{}, false
}

sessionBody, err := ioutil.ReadAll(sessionRes.Body)
if err != nil {
return User{}, false
}

wrappedSession := SessionWrapper{}
if err := json.Unmarshal(sessionBody, &wrappedSession); err != nil || len(wrappedSession.Source.Id) == 0 {
return User{}, false
}

userResp, err := project.Es.Document.Get(ctx, opensearchapi.DocumentGetReq{
Index: strings.ToLower(GetESIndexPrefix("Users")),
DocumentID: wrappedSession.Source.Id,
})
if err != nil {
return User{}, false
}

userRes := userResp.Inspect().Response
defer userRes.Body.Close()
if userRes.StatusCode != 200 && userRes.StatusCode != 201 {
return User{}, false
}

userBody, err := ioutil.ReadAll(userRes.Body)
if err != nil {
return User{}, false
}

wrappedUser := UserWrapper{}
if err := json.Unmarshal(userBody, &wrappedUser); err != nil {
return User{}, false
}

// Guard against a stale/mismatched "sessions" doc pointing at a user
// whose session has since changed (e.g. logged out, or session rotated).
if wrappedUser.Source.Session != sessionId {
return User{}, false
}

return wrappedUser.Source, true
}

func GetSessionNew(ctx context.Context, sessionId string) (User, error) {
cacheKey := fmt.Sprintf("session_%s", sessionId)
user := &User{}
Expand All @@ -9978,6 +10059,24 @@ func GetSessionNew(ctx context.Context, sessionId string) (User, error) {
nameKey := "Users"
var users []User
if project.DbType == "opensearch" {
// Real-time lookup path: session tokens are indexed with the token
// itself as the document ID in the "sessions" index (see SetSession),
// so a direct Document.Get is immediately consistent (unlike _search,
// below, which only sees documents after the next index refresh -
// default refresh_interval ~1s). Without this, a session created by a
// fresh login (e.g. SSO) could be briefly invisible to the very next
// request (getinfo right after the login redirect), making a
// just-logged-in user look logged out - surfacing as a bounce back to
// /login that required a second login attempt to succeed once the
// document became searchable. Falls back to the _search-based lookup
// below if this fails for any reason (e.g. a legacy session predating
// the "sessions" index, or a transient error).
if user, ok := getSessionUserRealtime(ctx, sessionId); ok {
users = []User{user}
}
}

if len(users) == 0 && project.DbType == "opensearch" {
var buf bytes.Buffer
query := map[string]interface{}{
"from": 0,
Expand Down Expand Up @@ -10056,7 +10155,7 @@ func GetSessionNew(ctx context.Context, sessionId string) (User, error) {
users = append(users, hit.Source)
}

} else {
} else if project.DbType != "opensearch" {
//log.Printf("[DEBUG] Searching for session %s", sessionId)
q := datastore.NewQuery(nameKey).Filter("session =", sessionId).Limit(1)
_, err := project.Dbclient.GetAll(ctx, q, &users)
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ require (
github.com/google/go-github/v28 v28.1.1
github.com/google/go-querystring v1.1.0
github.com/google/uuid v1.6.0
github.com/klauspost/compress v1.19.2
github.com/microcosm-cc/bluemonday v1.0.27
github.com/openai/openai-go/v3 v3.8.1
github.com/patrickmn/go-cache v2.1.0+incompatible
Expand All @@ -35,7 +36,6 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
golang.org/x/crypto v0.48.0
golang.org/x/oauth2 v0.34.0
golang.org/x/sys v0.41.0
google.golang.org/api v0.236.0
google.golang.org/appengine v1.6.8
gopkg.in/yaml.v2 v2.4.0
Expand Down Expand Up @@ -145,6 +145,7 @@ require (
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/net v0.51.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/term v0.40.0 // indirect
golang.org/x/text v0.34.0 // indirect
golang.org/x/time v0.11.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I=
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
Expand Down Expand Up @@ -230,6 +232,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand All @@ -247,6 +251,8 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
Expand All @@ -261,6 +267,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
Expand Down
Loading
Loading