Skip to content

Commit

Permalink
Merge pull request #7489 from TheThingsNetwork/fix/client-support-use…
Browse files Browse the repository at this point in the history
…r-rights-limitations

Impose support user rights limitation on GetAccessToken operation
  • Loading branch information
KrishnaIyer authored Jan 28, 2025
2 parents 4dbf1f6 + fa98cc6 commit e2eb497
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pkg/identityserver/bunstore/oauth_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,11 @@ func (s *oauthStore) GetAccessToken(ctx context.Context, id string) (*ttnpb.OAut
return nil, err
}

// NOTE: This imposes a limitation on the client's rights if the token's user is the unique support user.
if model.User.Account.UID == ttnpb.SupportUserID {
model.Rights = convertIntSlice[ttnpb.Right, int](ttnpb.AllReadAdminRights.GetRights())
}

pb, err := accessTokenToPB(model, nil, nil)
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions pkg/identityserver/bunstore/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ func TestOAuthStore(t *testing.T) {

st := storetest.New(t, newTestStore)
st.TestOAuthStore(t)
st.TestOAuthStoreSupportUser(t)
st.TestOAuthStorePagination(t)
st.TestOAuthStorePaginationDefaults(t)
}
Expand Down
61 changes: 61 additions & 0 deletions pkg/identityserver/storetest/oauth_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,67 @@ func (st *StoreTest) TestOAuthStore(t *T) {
})
}

// TestOAuthStoreSupportUser tests the behavior of AccessTokens with the unique support userID.
func (st *StoreTest) TestOAuthStoreSupportUser(t *T) {
supportUsr := st.population.NewUser()
supportUsr.Ids.UserId = ttnpb.SupportUserID
supportUsr.Name = "support"
supportUsr.PrimaryEmailAddress = "[email protected]"

ses1 := st.population.NewUserSession(supportUsr.GetIds())
cli1 := st.population.NewClient(nil)
cli1.SkipAuthorization = true

s, ok := st.PrepareDB(t).(interface {
Store
is.OAuthStore
})
defer st.DestroyDB(t, true, "users", "accounts", "user_sessions", "clients")
if !ok {
t.Skip("Store does not implement OAuthStore")
}
defer s.Close()

var createdAccessToken *ttnpb.OAuthAccessToken

t.Run("CreateAccessToken", func(t *T) {
a, ctx := test.New(t)
var err error
start := time.Now().Truncate(time.Second)

createdAccessToken, err = s.CreateAccessToken(ctx, &ttnpb.OAuthAccessToken{
UserIds: supportUsr.GetIds(),
UserSessionId: ses1.GetSessionId(),
ClientIds: cli1.GetIds(),
Id: "token_id",
AccessToken: "access_token",
RefreshToken: "refresh_token",
Rights: []ttnpb.Right{ttnpb.Right_RIGHT_ALL},
ExpiresAt: timestamppb.New(start.Add(5 * time.Minute)),
}, "")
if a.So(err, should.BeNil) && a.So(createdAccessToken, should.NotBeNil) {
a.So(createdAccessToken.UserIds, should.Resemble, supportUsr.GetIds())
a.So(createdAccessToken.UserSessionId, should.Equal, ses1.GetSessionId())
a.So(createdAccessToken.ClientIds, should.Resemble, cli1.GetIds())
a.So(createdAccessToken.Id, should.Equal, "token_id")
a.So(createdAccessToken.AccessToken, should.Equal, "access_token")
a.So(createdAccessToken.RefreshToken, should.Equal, "refresh_token")
a.So(createdAccessToken.Rights, should.Resemble, []ttnpb.Right{ttnpb.Right_RIGHT_ALL})
a.So(*ttnpb.StdTime(createdAccessToken.ExpiresAt), should.Equal, start.Add(5*time.Minute))
a.So(*ttnpb.StdTime(createdAccessToken.CreatedAt), should.HappenWithin, 5*time.Second, start)
}
})

t.Run("GetAccessToken", func(t *T) {
a, ctx := test.New(t)
got, err := s.GetAccessToken(ctx, "token_id")
if a.So(err, should.BeNil) && a.So(got, should.NotBeNil) {
// NOTE: This should be limited due to referencing the unique support userID.
a.So(got.Rights, should.Resemble, ttnpb.AllReadAdminRights.GetRights())
}
})
}

func (st *StoreTest) TestOAuthStorePagination(t *T) {
a, ctx := test.New(t)

Expand Down

0 comments on commit e2eb497

Please sign in to comment.