idp: set github timestamps (#943)

This commit is contained in:
Caleb Doxsey 2020-06-21 15:50:56 -06:00 committed by GitHub
parent cfbc5c2114
commit fbce3dd359
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 47 deletions

4
go.sum
View file

@ -714,6 +714,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@ -766,10 +767,12 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cookieo9/resources-go.v2 v2.0.0-20150225115733-d27c04069d0d h1:YjTGSRV59gG1DHCq68v2B771I9dGFxvMkugf7OKglpk=
gopkg.in/cookieo9/resources-go.v2 v2.0.0-20150225115733-d27c04069d0d/go.mod h1:kbUs813+JgwKQdecaTv87br/FZUaSEuPj8vbr2vq8sY=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -782,6 +785,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=

View file

@ -30,7 +30,6 @@ const (
defaultProviderURL = "https://github.com"
githubAPIURL = "https://api.github.com"
userPath = "/user"
teamPath = "/user/teams"
revokePath = "/applications/%s/grant"
emailPath = "/user/emails"
// https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps
@ -41,6 +40,8 @@ const (
refreshDeadline = time.Minute * 60
)
var maxTime = time.Unix(1<<63-1, 0)
// https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/
var defaultScopes = []string{"user:email", "read:org"}
@ -82,6 +83,9 @@ func (p *Provider) Authenticate(ctx context.Context, code string, v interface{})
return nil, fmt.Errorf("github: token exchange failed %v", err)
}
// github tokens never expire
oauth2Token.Expiry = maxTime
err = p.UpdateUserInfo(ctx, oauth2Token, v)
if err != nil {
return nil, err
@ -94,7 +98,6 @@ func (p *Provider) Authenticate(ctx context.Context, code string, v interface{})
//
// https://developer.github.com/v3/users/#get-the-authenticated-user
func (p *Provider) UpdateUserInfo(ctx context.Context, t *oauth2.Token, v interface{}) error {
err := p.userInfo(ctx, t, v)
if err != nil {
return fmt.Errorf("github: could not retrieve user info %w", err)
@ -105,56 +108,15 @@ func (p *Provider) UpdateUserInfo(ctx context.Context, t *oauth2.Token, v interf
return fmt.Errorf("github: could not retrieve user email %w", err)
}
err = p.userTeams(ctx, t, v)
if err != nil {
return fmt.Errorf("github: could not retrieve groups %w", err)
}
return nil
}
// Refresh is a no-op for github, because github sessions never expire.
func (p *Provider) Refresh(ctx context.Context, t *oauth2.Token, v interface{}) (*oauth2.Token, error) {
t.Expiry = time.Now().Add(refreshDeadline)
return t, nil
}
// userTeams returns a slice of teams the user belongs by making a request
// to github API
//
// https://developer.github.com/v3/teams/#list-user-teams
// https://developer.github.com/v3/auth/
func (p *Provider) userTeams(ctx context.Context, t *oauth2.Token, v interface{}) error {
var response []struct {
ID json.Number `json:"id"`
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
Slug string `json:"slug"`
Description string `json:"description,omitempty"`
ReposURL string `json:"repos_url,omitempty"`
Privacy string `json:"privacy,omitempty"`
}
headers := map[string]string{"Authorization": fmt.Sprintf("token %s", t.AccessToken)}
teamURL := githubAPIURL + teamPath
err := httputil.Client(ctx, http.MethodGet, teamURL, version.UserAgent(), headers, nil, &response)
if err != nil {
return err
}
log.Debug().Interface("teams", response).Msg("github: user teams")
var out struct {
Groups []string `json:"groups"`
}
for _, org := range response {
out.Groups = append(out.Groups, org.ID.String())
}
b, err := json.Marshal(out)
if err != nil {
return err
}
return json.Unmarshal(b, v)
}
// userEmail returns the primary email of the user by making
// a query to github API.
//
@ -217,14 +179,18 @@ func (p *Provider) userInfo(ctx context.Context, t *oauth2.Token, v interface{})
Picture string `json:"picture,omitempty"`
// needs to be set manually
Expiry *jwt.NumericDate `json:"exp,omitempty"`
NotBefore *jwt.NumericDate `json:"nbf,omitempty"`
IssuedAt *jwt.NumericDate `json:"iat,omitempty"`
}
out.Expiry = jwt.NewNumericDate(time.Now().Add(refreshDeadline))
out.NotBefore = jwt.NewNumericDate(time.Now())
out.IssuedAt = jwt.NewNumericDate(time.Now())
out.User = response.Login
out.Subject = response.Login
out.Name = response.Name
out.Picture = response.AvatarURL
// set the session expiry
out.Expiry = jwt.NewNumericDate(time.Now().Add(refreshDeadline))
b, err := json.Marshal(out)
if err != nil {
return err