From 2ce3b86e0ff69538935db3149d1ed2f24aea09a3 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Mon, 13 Apr 2020 23:57:13 -0400 Subject: Simplify --- server/auth/gitlab/gitlab.go | 225 ------------------------------------------- 1 file changed, 225 deletions(-) delete mode 100644 server/auth/gitlab/gitlab.go (limited to 'server/auth/gitlab/gitlab.go') diff --git a/server/auth/gitlab/gitlab.go b/server/auth/gitlab/gitlab.go deleted file mode 100644 index 70d3d1c..0000000 --- a/server/auth/gitlab/gitlab.go +++ /dev/null @@ -1,225 +0,0 @@ -package gitlab - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "log" - "net/http" - "strconv" - - "github.com/nsheridan/cashier/server/config" - "github.com/nsheridan/cashier/server/metrics" - - "golang.org/x/oauth2" -) - -const ( - name = "gitlab" -) - -// Config is an implementation of `auth.Provider` for authenticating using a -// Gitlab account. -type Config struct { - config *oauth2.Config - group string - whitelist map[string]bool - allusers bool - apiurl string - log bool -} - -// Note on Gitlab REST API calls. We don't parse errors because it's -// kind of a pain: -// https://gitlab.com/help/api/README.md#data-validation-and-error-reporting -// The two v4 api calls used are /user and /groups/:group/members/:uid -// https://gitlab.com/help/api/users.md#for-normal-users-1 -// https://gitlab.com/help/api/members.md#get-a-member-of-a-group-or-project -type serviceUser struct { - ID int `json:"id"` - Username string `json:"username"` - Email string `json:"email"` -} - -type serviceGroupMember struct { - ID int `json:"id"` - State string `json:"state"` - AccessLevel int `json:"access_level"` -} - -func (c *Config) logMsg(message error) { - if c.log { - log.Print(message) - } -} - -// A new oauth2 http client. -func (c *Config) newClient(token *oauth2.Token) *http.Client { - return c.config.Client(oauth2.NoContext, token) -} - -func (c *Config) getURL(token *oauth2.Token, url string) (*bytes.Buffer, error) { - client := c.newClient(token) - resp, err := client.Get(url) - if err != nil { - return nil, fmt.Errorf("Failed to get groups: %s", err) - } - defer resp.Body.Close() - var body bytes.Buffer - io.Copy(&body, resp.Body) - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Gitlab error(http: %d) getting %s: '%s'", - resp.StatusCode, url, body.String()) - } - return &body, nil -} - -// Gets info on the current user. -func (c *Config) getUser(token *oauth2.Token) *serviceUser { - url := c.apiurl + "user" - body, err := c.getURL(token, url) - if err != nil { - c.logMsg(err) - return nil - } - var user serviceUser - if err := json.NewDecoder(body).Decode(&user); err != nil { - c.logMsg(fmt.Errorf("Failed to decode user (%s): %s", url, err)) - return nil - } - return &user -} - -// Gets current user group membership info. -func (c *Config) checkGroupMembership(token *oauth2.Token, uid int, group string) bool { - url := fmt.Sprintf("%sgroups/%s/members/%d", c.apiurl, group, uid) - body, err := c.getURL(token, url) - if err != nil { - c.logMsg(err) - return false - } - var m serviceGroupMember - if err := json.NewDecoder(body).Decode(&m); err != nil { - c.logMsg(fmt.Errorf("Failed to parse groups (%s): %s", url, err)) - return false - } - return m.ID == uid -} - -// New creates a new Gitlab provider from a configuration. -func New(c *config.Auth) (*Config, error) { - logOpt, _ := strconv.ParseBool(c.ProviderOpts["log"]) - uw := make(map[string]bool) - for _, u := range c.UsersWhitelist { - uw[u] = true - } - allUsers, _ := strconv.ParseBool(c.ProviderOpts["allusers"]) - if !allUsers && c.ProviderOpts["group"] == "" && len(uw) == 0 { - return nil, errors.New("gitlab_opts group and the users whitelist must not be both empty if allusers isn't true") - } - siteURL := "https://gitlab.com/" - if c.ProviderOpts["siteurl"] != "" { - siteURL = c.ProviderOpts["siteurl"] - if siteURL[len(siteURL)-1] != '/' { - return nil, errors.New("gitlab_opts siteurl must end in /") - } - } else { - if allUsers { - return nil, errors.New("gitlab_opts if allusers is set, siteurl must be set") - } - } - // TODO: Should make sure siteURL is just the host bit. - oauth2.RegisterBrokenAuthHeaderProvider(siteURL) - - return &Config{ - config: &oauth2.Config{ - ClientID: c.OauthClientID, - ClientSecret: c.OauthClientSecret, - RedirectURL: c.OauthCallbackURL, - Endpoint: oauth2.Endpoint{ - AuthURL: siteURL + "oauth/authorize", - TokenURL: siteURL + "oauth/token", - }, - Scopes: []string{ - "api", - }, - }, - group: c.ProviderOpts["group"], - whitelist: uw, - allusers: allUsers, - apiurl: siteURL + "api/v4/", - log: logOpt, - }, nil -} - -// Name returns the name of the provider. -func (c *Config) Name() string { - return name -} - -// Valid validates the oauth token. -func (c *Config) Valid(token *oauth2.Token) bool { - if !token.Valid() { - log.Printf("Auth fail (oauth2 Valid failure)") - return false - } - if c.allusers { - log.Printf("Auth success (allusers)") - metrics.M.AuthValid.WithLabelValues("gitlab").Inc() - return true - } - u := c.getUser(token) - if u == nil { - return false - } - if len(c.whitelist) > 0 && !c.whitelist[c.Username(token)] { - c.logMsg(errors.New("Auth fail (not in whitelist)")) - return false - } - if c.group == "" { - // There's no group and token is valid. Can only reach - // here if user whitelist is set and user is in whitelist. - c.logMsg(errors.New("Auth success (no groups specified in server config)")) - metrics.M.AuthValid.WithLabelValues("gitlab").Inc() - return true - } - if !c.checkGroupMembership(token, u.ID, c.group) { - c.logMsg(errors.New("Auth failure (not in allowed group)")) - return false - } - metrics.M.AuthValid.WithLabelValues("gitlab").Inc() - c.logMsg(errors.New("Auth success (in allowed group)")) - return true -} - -// Revoke is a no-op revoke method. Gitlab doesn't allow token -// revocation - tokens live for an hour. -// Returns nil to satisfy the Provider interface. -func (c *Config) Revoke(token *oauth2.Token) error { - return nil -} - -// StartSession retrieves an authentication endpoint from Gitlab. -func (c *Config) StartSession(state string) string { - return c.config.AuthCodeURL(state) -} - -// Exchange authorizes the session and returns an access token. -func (c *Config) Exchange(code string) (*oauth2.Token, error) { - t, err := c.config.Exchange(oauth2.NoContext, code) - if err == nil { - metrics.M.AuthExchange.WithLabelValues("gitlab").Inc() - } - return t, err -} - -// Username retrieves the username of the Gitlab user. -func (c *Config) Username(token *oauth2.Token) string { - u := c.getUser(token) - if u == nil { - return "" - } - return u.Username -} -- cgit v1.2.3