|
|
@@ -0,0 +1,131 @@
|
|
|
+package social
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "net/http"
|
|
|
+ "regexp"
|
|
|
+
|
|
|
+ "github.com/grafana/grafana/pkg/models"
|
|
|
+
|
|
|
+ "golang.org/x/oauth2"
|
|
|
+)
|
|
|
+
|
|
|
+type SocialGitlab struct {
|
|
|
+ *SocialBase
|
|
|
+ allowedDomains []string
|
|
|
+ allowedGroups []string
|
|
|
+ apiUrl string
|
|
|
+ allowSignup bool
|
|
|
+}
|
|
|
+
|
|
|
+var (
|
|
|
+ ErrMissingGroupMembership = &Error{"User not a member of one of the required groups"}
|
|
|
+)
|
|
|
+
|
|
|
+func (s *SocialGitlab) Type() int {
|
|
|
+ return int(models.GITLAB)
|
|
|
+}
|
|
|
+
|
|
|
+func (s *SocialGitlab) IsEmailAllowed(email string) bool {
|
|
|
+ return isEmailAllowed(email, s.allowedDomains)
|
|
|
+}
|
|
|
+
|
|
|
+func (s *SocialGitlab) IsSignupAllowed() bool {
|
|
|
+ return s.allowSignup
|
|
|
+}
|
|
|
+
|
|
|
+func (s *SocialGitlab) IsGroupMember(client *http.Client) bool {
|
|
|
+ if len(s.allowedGroups) == 0 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ for groups, url := s.GetGroups(client, s.apiUrl+"/groups"); groups != nil; groups, url = s.GetGroups(client, url) {
|
|
|
+ for _, allowedGroup := range s.allowedGroups {
|
|
|
+ for _, group := range groups {
|
|
|
+ if group == allowedGroup {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+func (s *SocialGitlab) GetGroups(client *http.Client, url string) ([]string, string) {
|
|
|
+ type Group struct {
|
|
|
+ FullPath string `json:"full_path"`
|
|
|
+ }
|
|
|
+
|
|
|
+ var (
|
|
|
+ groups []Group
|
|
|
+ next string
|
|
|
+ )
|
|
|
+
|
|
|
+ if url == "" {
|
|
|
+ return nil, next
|
|
|
+ }
|
|
|
+
|
|
|
+ response, err := HttpGet(client, url)
|
|
|
+ if err != nil {
|
|
|
+ s.log.Error("Error getting groups from GitLab API", "err", err)
|
|
|
+ return nil, next
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := json.Unmarshal(response.Body, &groups); err != nil {
|
|
|
+ s.log.Error("Error parsing JSON from GitLab API", "err", err)
|
|
|
+ return nil, next
|
|
|
+ }
|
|
|
+
|
|
|
+ fullPaths := make([]string, len(groups))
|
|
|
+ for i, group := range groups {
|
|
|
+ fullPaths[i] = group.FullPath
|
|
|
+ }
|
|
|
+
|
|
|
+ if link, ok := response.Headers["Link"]; ok {
|
|
|
+ pattern := regexp.MustCompile(`<([^>]+)>; rel="next"`)
|
|
|
+ if matches := pattern.FindStringSubmatch(link[0]); matches != nil {
|
|
|
+ next = matches[1]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return fullPaths, next
|
|
|
+}
|
|
|
+
|
|
|
+func (s *SocialGitlab) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) {
|
|
|
+
|
|
|
+ var data struct {
|
|
|
+ Id int
|
|
|
+ Username string
|
|
|
+ Email string
|
|
|
+ Name string
|
|
|
+ State string
|
|
|
+ }
|
|
|
+
|
|
|
+ response, err := HttpGet(client, s.apiUrl+"/user")
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("Error getting user info: %s", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ err = json.Unmarshal(response.Body, &data)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("Error getting user info: %s", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if data.State != "active" {
|
|
|
+ return nil, fmt.Errorf("User %s is inactive", data.Username)
|
|
|
+ }
|
|
|
+
|
|
|
+ userInfo := &BasicUserInfo{
|
|
|
+ Name: data.Name,
|
|
|
+ Login: data.Username,
|
|
|
+ Email: data.Email,
|
|
|
+ }
|
|
|
+
|
|
|
+ if !s.IsGroupMember(client) {
|
|
|
+ return nil, ErrMissingGroupMembership
|
|
|
+ }
|
|
|
+
|
|
|
+ return userInfo, nil
|
|
|
+}
|