Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 1b8ee3a

Browse files
authored
Merge pull request #101 from keybase/zapu/implicit-admin-bug
Fix a bug where kssh and keybaseca would try to fetch KV store data from teams user is not an explicit member of.
2 parents 71d55f0 + 60a0e7b commit 1b8ee3a

File tree

4 files changed

+48
-23
lines changed

4 files changed

+48
-23
lines changed

src/keybaseca/bot/bot.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,7 @@ func (b *Bot) DeleteAllClientConfigs() error {
252252
}
253253

254254
func (b *Bot) getAllTeams() (teams []string, err error) {
255-
memberships, err := b.api.ListUserMemberships(b.api.GetUsername())
256-
if err != nil {
257-
return teams, err
258-
}
259-
for _, m := range memberships {
260-
teams = append(teams, m.FqName)
261-
}
262-
return teams, nil
255+
return shared.GetAllTeams(b.api)
263256
}
264257

265258
// LogError logs the given error to Keybase chat and to the configured log file. Used so

src/keybaseca/sshutils/sshutils.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,10 @@ func SignKey(caKeyLocation, keyID, principals, expiration, publicKey string) (si
151151
return string(signatureBytes), nil
152152
}
153153

154-
// Get the principals that should be placed in the signed certificate.
155-
// Note that this function is a security boundary since if it was bypassed an
156-
// attacker would be able to provision SSH keys for environments that they should not have access to.
154+
// Get the principals that should be placed in the signed certificate. Note
155+
// that this function is a security boundary since if it was bypassed an
156+
// attacker would be able to provision SSH keys for environments that they
157+
// should not have access to.
157158
func getPrincipals(conf config.Config, sr shared.SignatureRequest) (string, error) {
158159
// Start by getting the list of teams the user is in
159160
api, err := botwrapper.GetKBChat(conf.GetKeybaseHomeDir(), conf.GetKeybasePaperKey(), conf.GetKeybaseUsername(), conf.GetKeybaseTimeout())
@@ -165,11 +166,13 @@ func getPrincipals(conf config.Config, sr shared.SignatureRequest) (string, erro
165166
return "", fmt.Errorf("failed to retrieve the list of teams the user is in: %v", err)
166167
}
167168

168-
// Maps from a team to whether or not the user is in the current team (with writer, admin, or owner permissions)
169+
// Maps from a team to whether or not the user is in the current team (with
170+
// writer, admin, or owner permissions)
169171
teamToMembership := make(map[string]bool)
170172
for _, result := range results {
171-
if result.Role != 0 {
172-
// result.Role == 0 means they are an impicit admin in the team and are not actually a member
173+
// Check if the user is actually in the team, and not a restricted bot
174+
// or implicit admin.
175+
if shared.CanRoleReadTeam(result.Role) {
173176
teamToMembership[result.FqName] = true
174177
}
175178
}

src/kssh/requester.go

+1-9
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,7 @@ func (r *Requester) LoadConfigForBot(botName string) (Config, error) {
8888
}
8989

9090
func (r *Requester) getAllTeams() (teams []string, err error) {
91-
// TODO: dedup with same method in keybaseca/bot
92-
memberships, err := r.api.ListUserMemberships(r.api.GetUsername())
93-
if err != nil {
94-
return teams, err
95-
}
96-
for _, m := range memberships {
97-
teams = append(teams, m.FqName)
98-
}
99-
return teams, nil
91+
return shared.GetAllTeams(r.api)
10092
}
10193

10294
// Get a signed SSH key from interacting with the CA chatbot

src/shared/teams.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package shared
2+
3+
import (
4+
"github.com/keybase/go-keybase-chat-bot/kbchat"
5+
"github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
6+
)
7+
8+
// CanRoleReadTeam checks if given role can access team data. User has to be an
9+
// actual team member (not implicit admin) to be able to access data, and
10+
// cannot be a RESTRICTED BOT.
11+
func CanRoleReadTeam(role keybase1.TeamRole) bool {
12+
switch role {
13+
case keybase1.TeamRole_READER,
14+
keybase1.TeamRole_WRITER,
15+
keybase1.TeamRole_ADMIN,
16+
keybase1.TeamRole_OWNER,
17+
keybase1.TeamRole_BOT:
18+
return true
19+
default:
20+
return false
21+
}
22+
}
23+
24+
// GetAllTeams makes an API call and returns list of team names readable for
25+
// current user.
26+
func GetAllTeams(api *kbchat.API) (teams []string, err error) {
27+
memberships, err := api.ListUserMemberships(api.GetUsername())
28+
if err != nil {
29+
return teams, err
30+
}
31+
for _, m := range memberships {
32+
if CanRoleReadTeam(m.Role) {
33+
teams = append(teams, m.FqName)
34+
}
35+
}
36+
return teams, nil
37+
}

0 commit comments

Comments
 (0)