Skip to content

Commit f28b2b1

Browse files
authored
[3.2.7 backport] CBG-4694 do not return invalid sessions with GET (#7595)
1 parent ee58261 commit f28b2b1

File tree

6 files changed

+49
-27
lines changed

6 files changed

+49
-27
lines changed

auth/session.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,24 @@ func (auth *Authenticator) CreateSession(ctx context.Context, user User, ttl tim
114114
return session, nil
115115
}
116116

117+
// GetSession returns a session by ID. Return a not found error if the session is not found, or is invalid.
117118
func (auth *Authenticator) GetSession(sessionID string) (*LoginSession, error) {
118119
var session LoginSession
119120
_, err := auth.datastore.Get(auth.DocIDForSession(sessionID), &session)
120121
if err != nil {
121-
if base.IsDocNotFoundError(err) {
122-
err = nil
123-
}
124122
return nil, err
125123
}
124+
user, err := auth.GetUser(session.Username)
125+
if err != nil {
126+
return nil, err
127+
}
128+
if user == nil {
129+
return nil, base.ErrNotFound
130+
}
131+
if session.SessionUUID != user.GetSessionUUID() {
132+
return nil, base.ErrNotFound
133+
}
134+
126135
return &session, nil
127136
}
128137

auth/session_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,9 @@ func TestDeleteSession(t *testing.T) {
9191
assert.NoError(t, dataStore.Set(auth.DocIDForSession(mockSession.ID), noSessionExpiry, nil, mockSession))
9292
assert.NoError(t, auth.DeleteSession(ctx, mockSession.ID, ""))
9393

94-
// Just to verify the session has been deleted gracefully.
9594
session, err := auth.GetSession(mockSession.ID)
9695
assert.Nil(t, session)
97-
assert.NoError(t, err)
96+
base.RequireDocNotFoundError(t, err)
9897
}
9998

10099
// Coverage for MakeSessionCookie. The MakeSessionCookie should create a cookie

docs/api/paths/admin/db-_session.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ post:
4040
description: User name to generate the session for.
4141
type: string
4242
ttl:
43-
description: Time until the session expires. Uses default value of 24 hours if left blank.
43+
description: Time until the session expires. Uses default value of 24 hours if left blank. This value must be greater or equal to 1.
4444
type: integer
4545
responses:
4646
'200':

rest/session_api.go

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,9 @@ func (h *handler) getUserSession() error {
242242

243243
h.assertAdminOnly()
244244
session, err := h.db.Authenticator(h.ctx()).GetSession(h.PathVar("sessionid"))
245-
246-
if session == nil {
247-
if err == nil {
248-
err = kNotFoundError
249-
}
245+
if err != nil {
250246
return err
251247
}
252-
253248
return h.respondWithSessionInfoForSession(session)
254249
}
255250

@@ -292,22 +287,17 @@ func (h *handler) deleteUserSessionWithValidation(sessionId string, userName str
292287
// Validate that the session being deleted belongs to the user. This adds some
293288
// overhead - for user-agnostic session deletion should use deleteSession
294289
session, getErr := h.db.Authenticator(h.ctx()).GetSession(sessionId)
295-
if session == nil {
296-
if getErr == nil {
297-
getErr = kNotFoundError
298-
}
290+
if getErr != nil {
299291
return getErr
300292
}
301293

302-
if getErr == nil {
303-
if session.Username == userName {
304-
delErr := h.db.Authenticator(h.ctx()).DeleteSession(h.ctx(), sessionId, userName)
305-
if delErr != nil {
306-
return delErr
307-
}
308-
} else {
309-
return kNotFoundError
294+
if session.Username == userName {
295+
delErr := h.db.Authenticator(h.ctx()).DeleteSession(h.ctx(), sessionId, userName)
296+
if delErr != nil {
297+
return delErr
310298
}
299+
} else {
300+
return kNotFoundError
311301
}
312302
return nil
313303
}

rest/session_test.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,19 +447,19 @@ func TestSessionAPI(t *testing.T) {
447447

448448
// Attempt to GET the deleted session and make sure it's not found
449449
response = rt.SendAdminRequest("GET", fmt.Sprintf("/db/_session/%s", user1sessions[0]), "")
450-
RequireStatus(t, response, 404)
450+
RequireNotFoundError(t, response)
451451

452452
// 2. DELETE a session with user validation
453453
response = rt.SendAdminRequest("DELETE", fmt.Sprintf("/db/_user/%s/_session/%s", "user1", user1sessions[1]), "")
454454
RequireStatus(t, response, 200)
455455

456456
// Attempt to GET the deleted session and make sure it's not found
457457
response = rt.SendAdminRequest("GET", fmt.Sprintf("/db/_session/%s", user1sessions[1]), "")
458-
RequireStatus(t, response, 404)
458+
RequireNotFoundError(t, response)
459459

460460
// 3. DELETE a session not belonging to the user (should fail)
461461
response = rt.SendAdminRequest("DELETE", fmt.Sprintf("/db/_user/%s/_session/%s", "user1", user2sessions[0]), "")
462-
RequireStatus(t, response, 404)
462+
RequireNotFoundError(t, response)
463463

464464
// GET the session and make sure it still exists
465465
response = rt.SendAdminRequest("GET", fmt.Sprintf("/db/_session/%s", user2sessions[0]), "")
@@ -469,6 +469,23 @@ func TestSessionAPI(t *testing.T) {
469469
response = rt.SendAdminRequest("DELETE", "/db/_user/user2/_session", "")
470470
RequireStatus(t, response, 200)
471471

472+
// Validate that all sessions were deleted
473+
for i := range 5 {
474+
response = rt.SendAdminRequest("GET", fmt.Sprintf("/db/_session/%s", user2sessions[i]), "")
475+
RequireNotFoundError(t, response)
476+
}
477+
478+
// 5. DELETE sessions when password is changed
479+
// Change password for user3
480+
response = rt.SendAdminRequest("PUT", "/db/_user/user3", `{"password":"5678"}`)
481+
RequireStatus(t, response, 200)
482+
483+
// Validate that all sessions were deleted
484+
for i := range 5 {
485+
response = rt.SendAdminRequest("GET", fmt.Sprintf("/db/_session/%s", user3sessions[i]), "")
486+
RequireNotFoundError(t, response)
487+
}
488+
472489
// DELETE the users
473490
RequireStatus(t, rt.SendAdminRequest("DELETE", "/db/_user/user1", ""), 200)
474491
RequireStatus(t, rt.SendAdminRequest("GET", "/db/_user/user1", ""), 404)

rest/utilities_testing.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2827,3 +2827,10 @@ func (sc *ServerContext) reloadDatabaseWithConfigLoadFromBucket(nonContextStruct
28272827
defer sc.lock.Unlock()
28282828
return sc._reloadDatabaseWithConfig(nonContextStruct.Ctx, config, true, true)
28292829
}
2830+
2831+
func RequireNotFoundError(t *testing.T, response *TestResponse) {
2832+
RequireStatus(t, response, http.StatusNotFound)
2833+
var body db.Body
2834+
require.NoError(t, base.JSONUnmarshal(response.Body.Bytes(), &body))
2835+
require.Equal(t, db.Body{"error": "not_found", "reason": "missing"}, body)
2836+
}

0 commit comments

Comments
 (0)