From e8f4afae71c5a12af1389e823bdde8cd32a17925 Mon Sep 17 00:00:00 2001 From: mozillazg Date: Sat, 5 Nov 2016 11:52:11 +0800 Subject: [PATCH] new option: -github-user -github-user="": restrict logins to any of these users, separated by a comma --- README.md | 2 ++ main.go | 1 + options.go | 3 ++- providers/github.go | 60 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e6e4c964..64b6eb32d 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ The GitHub auth provider supports two additional parameters to restrict authenti -github-org="": restrict logins to members of this organisation -github-team="": restrict logins to members of any of these teams, separated by a comma + -github-user="": restrict logins to any of these users, separated by a comma If you are using GitHub enterprise, make sure you set the following to the appropriate url: @@ -178,6 +179,7 @@ Usage of oauth2_proxy: -email-domain=: authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email -github-org="": restrict logins to members of this organisation -github-team="": restrict logins to members of this team + -github-user="": restrict logins to these users -google-admin-email="": the google admin to impersonate for api calls -google-group=: restrict logins to members of this google group (may be given multiple times). -google-service-account-json="": the path to the service account json credentials diff --git a/main.go b/main.go index ba3366876..098ec1ec3 100644 --- a/main.go +++ b/main.go @@ -42,6 +42,7 @@ func main() { flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") flagSet.String("github-org", "", "restrict logins to members of this organisation") flagSet.String("github-team", "", "restrict logins to members of this team") + flagSet.String("github-user", "", "restrict logins to these users") flagSet.Var(&googleGroups, "google-group", "restrict logins to members of this google group (may be given multiple times).") flagSet.String("google-admin-email", "", "the google admin to impersonate for api calls") flagSet.String("google-service-account-json", "", "the path to the service account json credentials") diff --git a/options.go b/options.go index 4777d9d1e..abf7018e1 100644 --- a/options.go +++ b/options.go @@ -31,6 +31,7 @@ type Options struct { EmailDomains []string `flag:"email-domain" cfg:"email_domains"` GitHubOrg string `flag:"github-org" cfg:"github_org"` GitHubTeam string `flag:"github-team" cfg:"github_team"` + GitHubUser string `flag:"github-user" cfg:"github_user"` GoogleGroups []string `flag:"google-group" cfg:"google_group"` GoogleAdminEmail string `flag:"google-admin-email" cfg:"google_admin_email"` GoogleServiceAccountJSON string `flag:"google-service-account-json" cfg:"google_service_account_json"` @@ -228,7 +229,7 @@ func parseProviderInfo(o *Options, msgs []string) []string { case *providers.AzureProvider: p.Configure(o.AzureTenant) case *providers.GitHubProvider: - p.SetOrgTeam(o.GitHubOrg, o.GitHubTeam) + p.SetOrgTeamUser(o.GitHubOrg, o.GitHubTeam, o.GitHubUser) case *providers.GoogleProvider: if o.GoogleServiceAccountJSON != "" { file, err := os.Open(o.GoogleServiceAccountJSON) diff --git a/providers/github.go b/providers/github.go index f6d78b2af..34f3f8068 100644 --- a/providers/github.go +++ b/providers/github.go @@ -15,6 +15,7 @@ type GitHubProvider struct { *ProviderData Org string Team string + User string } func NewGitHubProvider(p *ProviderData) *GitHubProvider { @@ -46,9 +47,10 @@ func NewGitHubProvider(p *ProviderData) *GitHubProvider { } return &GitHubProvider{ProviderData: p} } -func (p *GitHubProvider) SetOrgTeam(org, team string) { +func (p *GitHubProvider) SetOrgTeamUser(org, team, user string) { p.Org = org p.Team = team + p.User = user if org != "" || team != "" { p.Scope += " read:org" } @@ -178,6 +180,58 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) { return false, nil } +func (p *GitHubProvider) hasUser(accessToken string) (bool, error) { + // https://developer.github.com/v3/users/#get-the-authenticated-user + + var user struct { + Login string `json:"login"` + } + + params := url.Values{ + "access_token": {accessToken}, + "limit": {"100"}, + } + + endpoint := &url.URL{ + Scheme: p.ValidateURL.Scheme, + Host: p.ValidateURL.Host, + Path: path.Join(p.ValidateURL.Path, "/user"), + RawQuery: params.Encode(), + } + req, _ := http.NewRequest("GET", endpoint.String(), nil) + req.Header.Set("Accept", "application/vnd.github.v3+json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return false, err + } + + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + return false, err + } + if resp.StatusCode != 200 { + return false, fmt.Errorf( + "got %d from %q %s", resp.StatusCode, stripToken(endpoint.String()), body) + } + + if err := json.Unmarshal(body, &user); err != nil { + return false, err + } + + presentUsers := []string{user.Login} + us := strings.Split(p.User, ",") + for _, u := range us { + if u == user.Login { + log.Printf("Found Github User: %q", user.Login) + return true, nil + } + } + + log.Printf("Missing User:%q in %v", p.User, presentUsers) + return false, nil +} + func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) { var emails []struct { @@ -196,6 +250,10 @@ func (p *GitHubProvider) GetEmailAddress(s *SessionState) (string, error) { return "", err } } + } else if p.User != "" { + if ok, err := p.hasUser(s.AccessToken); err != nil || !ok { + return "", err + } } params := url.Values{