github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/server/oauth_google.go (about) 1 package server 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strings" 10 11 "github.com/pyroscope-io/pyroscope/pkg/config" 12 "github.com/sirupsen/logrus" 13 "golang.org/x/oauth2" 14 ) 15 16 type oauthHandlerGoogle struct { 17 oauthBase 18 allowedDomains []string 19 } 20 21 func newOauthGoogleHandler(cfg config.GoogleOauth, baseURL string, log *logrus.Logger) (*oauthHandlerGoogle, error) { 22 authURL, err := url.Parse(cfg.AuthURL) 23 if err != nil { 24 return nil, err 25 } 26 27 h := &oauthHandlerGoogle{ 28 oauthBase: oauthBase{ 29 config: &oauth2.Config{ 30 ClientID: cfg.ClientID, 31 ClientSecret: cfg.ClientSecret, 32 Scopes: []string{"https://www.googleapis.com/auth/userinfo.email"}, 33 Endpoint: oauth2.Endpoint{AuthURL: cfg.AuthURL, TokenURL: cfg.TokenURL}, 34 }, 35 authURL: authURL, 36 log: log, 37 callbackRoute: "/auth/google/callback", 38 redirectRoute: "/auth/google/redirect", 39 apiURL: "https://www.googleapis.com/oauth2/v2", 40 baseURL: baseURL, 41 }, 42 allowedDomains: cfg.AllowedDomains, 43 } 44 45 if cfg.RedirectURL != "" { 46 h.config.RedirectURL = cfg.RedirectURL 47 } 48 49 return h, nil 50 } 51 52 func (o oauthHandlerGoogle) userAuth(client *http.Client) (extUserInfo, error) { 53 type userProfileResponse struct { 54 ID string 55 Email string 56 VerifiedEmail bool 57 Picture string 58 } 59 60 resp, err := client.Get(o.apiURL + "/userinfo") 61 if err != nil { 62 return extUserInfo{}, fmt.Errorf("failed to get oauth user info: %w", err) 63 } 64 defer resp.Body.Close() 65 66 var userProfile userProfileResponse 67 err = json.NewDecoder(resp.Body).Decode(&userProfile) 68 if err != nil { 69 return extUserInfo{}, fmt.Errorf("failed to decode user profile response: %w", err) 70 } 71 u := extUserInfo{ 72 Name: userProfile.Email, 73 Email: userProfile.Email, 74 } 75 if userProfile.Email == "" { 76 return extUserInfo{}, errors.New("user email is empty") 77 } 78 79 if len(o.allowedDomains) == 0 || (len(o.allowedDomains) > 0 && isAllowedDomain(o.allowedDomains, userProfile.Email)) { 80 return u, nil 81 } 82 83 return extUserInfo{}, errForbidden 84 } 85 86 func isAllowedDomain(allowedDomains []string, email string) bool { 87 for _, domain := range allowedDomains { 88 if strings.HasSuffix(email, fmt.Sprintf("@%s", domain)) { 89 return true 90 } 91 } 92 93 return false 94 } 95 96 func (o oauthHandlerGoogle) getOauthBase() oauthBase { 97 return o.oauthBase 98 }