Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
32 changes: 32 additions & 0 deletions api/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,38 @@ func (s *ClientSuite) Test_ElevateClient_expectBadRequestOnMissingDuration() {
assert.Nil(s.T(), client.ElevatedUntil)
}

func (s *ClientSuite) Test_ElevateClient_expectBadRequestOnDurationAboveMax() {
s.db.User(5).Client(8)

test.WithUser(s.ctx, 5)
// One second past the 30-day ceiling must be rejected.
s.withElevateRequest(8, model.MaxElevationDurationSeconds+1)

s.a.ElevateClient(s.ctx)

assert.Equal(s.T(), 400, s.recorder.Code)
client, err := s.db.GetClientByID(8)
assert.NoError(s.T(), err)
assert.Nil(s.T(), client.ElevatedUntil)
}

func (s *ClientSuite) Test_ElevateClient_expectBadRequestOnOverflowDuration() {
s.db.User(5).Client(8)

test.WithUser(s.ctx, 5)
// A value that would overflow time.Duration (wrapping to a past
// timestamp) must be rejected rather than silently accepted.
s.ctx.AddParam("id", "8")
s.withElevateBody(`{"durationSeconds":9223372036854775807}`)

s.a.ElevateClient(s.ctx)

assert.Equal(s.T(), 400, s.recorder.Code)
client, err := s.db.GetClientByID(8)
assert.NoError(s.T(), err)
assert.Nil(s.T(), client.ElevatedUntil)
}

func (s *ClientSuite) withFormData(formData string) {
s.ctx.Request = httptest.NewRequest("POST", "/token", strings.NewReader(formData))
s.ctx.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
Expand Down
2 changes: 1 addition & 1 deletion api/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ type pendingOIDCSession struct {

type pendingElevation struct {
ClientID uint `form:"id" binding:"required"`
DurationSeconds int `form:"durationSeconds" binding:"required"`
DurationSeconds int `form:"durationSeconds" binding:"required,min=1,max=2592000"`
}

// OIDCAPI provides handlers for OIDC authentication.
Expand Down
9 changes: 8 additions & 1 deletion model/elevate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ type ElevateRequest struct {
//
// required: true
// example: 900
DurationSeconds int `form:"durationSeconds" query:"durationSeconds" json:"durationSeconds" binding:"required"`
DurationSeconds int `form:"durationSeconds" query:"durationSeconds" json:"durationSeconds" binding:"required,min=1,max=2592000"`
}

var DefaultElevationDuration = time.Hour

// MaxElevationDurationSeconds is the upper bound (30 days) accepted for a
// requested elevation duration. It bounds ElevateRequest.DurationSeconds so a
// request can neither make elevation effectively permanent nor overflow
// time.Duration (which wraps past ~292 years, silently yielding a past
// elevatedUntil timestamp). Requests above this are rejected with 400.
const MaxElevationDurationSeconds = 2592000
Loading