Skip to content

Commit 7c1e327

Browse files
authored
Get extra emails when using SAML (#27)
1 parent 2c6e55c commit 7c1e327

File tree

6 files changed

+58
-13
lines changed

6 files changed

+58
-13
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,14 @@ Flags:
7676
7777
Use "baton-github [command] --help" for more information about a command.
7878
```
79+
80+
# Authentication
81+
82+
To use this Baton connector, you need to create a GitHub organization access token with the following permissions:
83+
84+
Org:
85+
- Member Read and Write
86+
87+
Repo:
88+
- Administrator: Read and Write
89+
- This permission implies Metadata: Read

pkg/connector/helpers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ type listUsersQuery struct {
185185
Node struct {
186186
SamlIdentity struct {
187187
NameId string
188+
Emails []struct {
189+
Value string
190+
}
188191
}
189192
User struct {
190193
Login string

pkg/connector/org.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ func (o *orgResourceType) Grants(
192192
continue
193193
}
194194

195-
ur, err := userResource(ctx, user, user.GetEmail())
195+
ur, err := userResource(ctx, user, user.GetEmail(), nil)
196196
if err != nil {
197197
return nil, "", nil, err
198198
}

pkg/connector/repository.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func (o *repositoryResourceType) Grants(
182182
continue
183183
}
184184

185-
ur, err := userResource(ctx, user, user.GetEmail())
185+
ur, err := userResource(ctx, user, user.GetEmail(), nil)
186186
if err != nil {
187187
return nil, "", nil, err
188188
}

pkg/connector/team.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func (o *teamResourceType) Grants(ctx context.Context, resource *v2.Resource, pT
235235
return nil, "", nil, fmt.Errorf("github-connectorv2: failed to get team membership for user: %w", err)
236236
}
237237

238-
ur, err := userResource(ctx, user, user.GetEmail())
238+
ur, err := userResource(ctx, user, user.GetEmail(), nil)
239239
if err != nil {
240240
return nil, "", nil, err
241241
}

pkg/connector/user.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package connector
33
import (
44
"context"
55
"fmt"
6+
"net/mail"
67
"strconv"
78
"strings"
89

@@ -16,7 +17,7 @@ import (
1617
)
1718

1819
// Create a new connector resource for a github user.
19-
func userResource(ctx context.Context, user *github.User, userEmail string) (*v2.Resource, error) {
20+
func userResource(ctx context.Context, user *github.User, userEmail string, extraEmails []string) (*v2.Resource, error) {
2021
displayName := user.GetName()
2122
if displayName == "" {
2223
// users do not always specify a name and we only get public email from
@@ -41,15 +42,21 @@ func userResource(ctx context.Context, user *github.User, userEmail string) (*v2
4142
"user_id": strconv.Itoa(int(user.GetID())),
4243
}
4344

45+
userTrait := []resource.UserTraitOption{
46+
resource.WithEmail(userEmail, true),
47+
resource.WithUserProfile(profile),
48+
resource.WithStatus(v2.UserTrait_Status_STATUS_ENABLED),
49+
}
50+
51+
for _, email := range extraEmails {
52+
userTrait = append(userTrait, resource.WithEmail(email, false))
53+
}
54+
4455
ret, err := resource.NewUserResource(
4556
displayName,
4657
resourceTypeUser,
4758
user.GetID(),
48-
[]resource.UserTraitOption{
49-
resource.WithEmail(userEmail, true),
50-
resource.WithUserProfile(profile),
51-
resource.WithStatus(v2.UserTrait_Status_STATUS_ENABLED),
52-
},
59+
userTrait,
5360
resource.WithAnnotation(
5461
&v2.ExternalLink{Url: user.GetHTMLURL()},
5562
&v2.V1Identifier{Id: strconv.FormatInt(user.GetID(), 10)},
@@ -94,7 +101,6 @@ func (o *userResourceType) List(ctx context.Context, parentID *v2.ResourceId, pt
94101
if err != nil {
95102
return nil, "", nil, err
96103
}
97-
q := listUsersQuery{}
98104
var restApiRateLimit *v2.RateLimitDescription
99105

100106
opts := github.ListMembersOptions{
@@ -121,15 +127,16 @@ func (o *userResourceType) List(ctx context.Context, parentID *v2.ResourceId, pt
121127
return nil, "", nil, err
122128
}
123129

130+
q := listUsersQuery{}
124131
rv := make([]*v2.Resource, 0, len(users))
125132
for _, user := range users {
126133
u, _, err := o.client.Users.GetByID(ctx, user.GetID())
127134
if err != nil {
128135
return nil, "", nil, err
129136
}
130137
userEmail := u.GetEmail()
138+
var extraEmails []string
131139
if hasSamlBool {
132-
q = listUsersQuery{}
133140
variables := map[string]interface{}{
134141
"orgLoginName": githubv4.String(orgName),
135142
"userName": githubv4.String(u.GetLogin()),
@@ -139,10 +146,29 @@ func (o *userResourceType) List(ctx context.Context, parentID *v2.ResourceId, pt
139146
return nil, "", nil, err
140147
}
141148
if len(q.Organization.SamlIdentityProvider.ExternalIdentities.Edges) == 1 {
142-
userEmail = q.Organization.SamlIdentityProvider.ExternalIdentities.Edges[0].Node.SamlIdentity.NameId
149+
samlIdent := q.Organization.SamlIdentityProvider.ExternalIdentities.Edges[0].Node.SamlIdentity
150+
userEmail = samlIdent.NameId
151+
setUserEmail := false
152+
153+
if userEmail != "" {
154+
setUserEmail = true
155+
}
156+
for _, email := range samlIdent.Emails {
157+
ok := isEmail(email.Value)
158+
if !ok {
159+
continue
160+
}
161+
162+
if !setUserEmail {
163+
userEmail = email.Value
164+
setUserEmail = true
165+
} else {
166+
extraEmails = append(extraEmails, email.Value)
167+
}
168+
}
143169
}
144170
}
145-
ur, err := userResource(ctx, u, userEmail)
171+
ur, err := userResource(ctx, u, userEmail, extraEmails)
146172
if err != nil {
147173
return nil, "", nil, err
148174
}
@@ -162,6 +188,11 @@ func (o *userResourceType) List(ctx context.Context, parentID *v2.ResourceId, pt
162188
return rv, pageToken, annotations, nil
163189
}
164190

191+
func isEmail(email string) bool {
192+
_, err := mail.ParseAddress(email)
193+
return err == nil
194+
}
195+
165196
func (o *userResourceType) Entitlements(_ context.Context, _ *v2.Resource, _ *pagination.Token) ([]*v2.Entitlement, string, annotations.Annotations, error) {
166197
return nil, "", nil, nil
167198
}

0 commit comments

Comments
 (0)