109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
package oauth2
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/influxdata/chronograf"
|
|
|
|
"golang.org/x/oauth2"
|
|
goauth2 "google.golang.org/api/oauth2/v2"
|
|
"google.golang.org/api/option"
|
|
)
|
|
|
|
// GoogleEndpoint is Google's OAuth 2.0 endpoint.
|
|
// Copied here to remove tons of package dependencies
|
|
var GoogleEndpoint = oauth2.Endpoint{
|
|
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
|
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
|
}
|
|
var _ Provider = &Google{}
|
|
|
|
// Google is an oauth2 provider supporting google.
|
|
type Google struct {
|
|
ClientID string
|
|
ClientSecret string
|
|
RedirectURL string
|
|
Domains []string // Optional google email domain checking
|
|
Logger chronograf.Logger
|
|
}
|
|
|
|
// Name is the name of the provider
|
|
func (g *Google) Name() string {
|
|
return "google"
|
|
}
|
|
|
|
// ID returns the google application client id
|
|
func (g *Google) ID() string {
|
|
return g.ClientID
|
|
}
|
|
|
|
// Secret returns the google application client secret
|
|
func (g *Google) Secret() string {
|
|
return g.ClientSecret
|
|
}
|
|
|
|
// Scopes for google is only the email address
|
|
// Documentation is here: https://developers.google.com/+/web/api/rest/oauth#email
|
|
func (g *Google) Scopes() []string {
|
|
return []string{
|
|
goauth2.UserinfoEmailScope,
|
|
goauth2.UserinfoProfileScope,
|
|
}
|
|
}
|
|
|
|
// Config is the Google OAuth2 exchange information and endpoints
|
|
func (g *Google) Config() *oauth2.Config {
|
|
return &oauth2.Config{
|
|
ClientID: g.ID(),
|
|
ClientSecret: g.Secret(),
|
|
Scopes: g.Scopes(),
|
|
Endpoint: GoogleEndpoint,
|
|
RedirectURL: g.RedirectURL,
|
|
}
|
|
}
|
|
|
|
// PrincipalID returns the google email address of the user.
|
|
func (g *Google) PrincipalID(provider *http.Client) (string, error) {
|
|
srv, err := goauth2.NewService(context.TODO(), option.WithHTTPClient(provider))
|
|
if err != nil {
|
|
g.Logger.Error("Unable to communicate with Google ", err.Error())
|
|
return "", err
|
|
}
|
|
info, err := srv.Userinfo.Get().Do()
|
|
if err != nil {
|
|
g.Logger.Error("Unable to retrieve Google email ", err.Error())
|
|
return "", err
|
|
}
|
|
// No domain filtering required, so, the user is autenticated.
|
|
if len(g.Domains) == 0 {
|
|
return info.Email, nil
|
|
}
|
|
|
|
// Check if the account domain is acceptable
|
|
for _, requiredDomain := range g.Domains {
|
|
if info.Hd == requiredDomain {
|
|
return info.Email, nil
|
|
}
|
|
}
|
|
g.Logger.Error("Domain '", info.Hd, "' is not a member of required Google domain(s): ", g.Domains)
|
|
return "", fmt.Errorf("Not in required domain")
|
|
}
|
|
|
|
// Group returns the string of domain a user belongs to in Google
|
|
func (g *Google) Group(provider *http.Client) (string, error) {
|
|
srv, err := goauth2.NewService(context.TODO(), option.WithHTTPClient(provider))
|
|
if err != nil {
|
|
g.Logger.Error("Unable to communicate with Google ", err.Error())
|
|
return "", err
|
|
}
|
|
info, err := srv.Userinfo.Get().Do()
|
|
if err != nil {
|
|
g.Logger.Error("Unable to retrieve Google email ", err.Error())
|
|
return "", err
|
|
}
|
|
|
|
return info.Hd, nil
|
|
}
|