Add google oauth provider. Need redirect_uri

pull/10616/head
Chris Goller 2017-02-14 23:11:11 -06:00
parent 9c3ffed99e
commit ae5e4edacf
5 changed files with 117 additions and 22 deletions

1
Godeps
View File

@ -15,3 +15,4 @@ github.com/sergi/go-diff 1d28411638c1e67fe1930830df207bef72496ae9
github.com/tylerb/graceful 50a48b6e73fcc75b45e22c05b79629a67c79e938
golang.org/x/net 749a502dd1eaf3e5bfd4f8956748c502357c0bbe
golang.org/x/oauth2 1e695b1c8febf17aad3bfa7bf0a819ef94b98ad5
google.golang.org/api bc20c61134e1d25265dd60049f5735381e79b631

View File

@ -16,6 +16,7 @@
* github.com/tylerb/graceful [MIT](https://github.com/tylerb/graceful/blob/master/LICENSE)
* golang.org/x/net [BSD](https://github.com/golang/net/blob/master/LICENSE)
* golang.org/x/oauth2 [BSD](https://github.com/golang/oauth2/blob/master/LICENSE)
* google.golang.org/api/oauth2/v2 [BSD](https://github.com/google/google-api-go-client/blob/master/LICENSE)
### Javascript
* Base64 0.2.1 [WTFPL](http://github.com/davidchambers/Base64.js)

View File

@ -1,19 +1,88 @@
package oauth2
import (
"fmt"
"net/http"
"github.com/influxdata/chronograf"
"golang.org/x/oauth2"
goauth2 "google.golang.org/api/oauth2/v2"
)
// Endpoint 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{}
type Google struct {
Provider
Domains []string // Optional google email domain checking
ClientID string
ClientSecret string
Domains []string // Optional google email domain checking
Logger chronograf.Logger
}
/*
client := conf.Client(oauth2.NoContext, tok)
email, err := client.Get("https://www.googleapis.com/oauth2/v3/userinfo")
if err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
// 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,
}
defer email.Body.Close()
data, _ := ioutil.ReadAll(email.Body)
log.Println("Email body: ", string(data))
c.Status(http.StatusOK)
*/
}
// 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: "http://localhost:8888/oauth/google/callback", // TODO: we are required to have a redirect_uri from google
}
}
// PrincipalID returns the google email address of the user.
func (g *Google) PrincipalID(provider *http.Client) (string, error) {
srv, err := goauth2.New(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")
}

View File

@ -26,7 +26,10 @@ type MuxOpts struct {
TokenSecret string // TokenSecret is the JWT secret
GithubClientID string // GithubClientID is the GH OAuth id
GithubClientSecret string // GithubClientSecret is the GH OAuth secret
GithubOrgs []string // GithubOrgs is the list of organizations a user my be a member of
GithubOrgs []string // GithubOrgs is the list of organizations a user may be a member of
GoogleClientID string // GoogleClientID is the Google OAuth id
GoogleClientSecret string // GoogleClientSecret is the Google OAuth secret
GoogleDomains []string // GoogleOrgs is the list of domains a user may be a member of
}
// NewMux attaches all the route handlers; handler returned servers chronograf.
@ -145,6 +148,18 @@ func AuthAPI(opts MuxOpts, router *httprouter.Router) http.Handler {
router.Handler("GET", "/oauth/github/logout", ghMux.Logout())
router.Handler("GET", "/oauth/github/callback", ghMux.Callback())
google := oauth2.Google{
ClientID: opts.GoogleClientID,
ClientSecret: opts.GoogleClientSecret,
Domains: opts.GoogleDomains,
Logger: opts.Logger,
}
goMux := oauth2.NewJWTMux(&google, &auth, opts.Logger)
router.Handler("GET", "/oauth/google/login", goMux.Login())
router.Handler("GET", "/oauth/google/logout", goMux.Logout())
router.Handler("GET", "/oauth/google/callback", goMux.Callback())
tokenMiddleware := oauth2.AuthorizedToken(&auth, &oauth2.CookieExtractor{Name: "session"}, opts.Logger, router)
// Wrap the API with token validation middleware.
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@ -47,13 +47,17 @@ type Server struct {
GithubClientID string `short:"i" long:"github-client-id" description:"Github Client ID for OAuth 2 support" env:"GH_CLIENT_ID"`
GithubClientSecret string `short:"s" long:"github-client-secret" description:"Github Client Secret for OAuth 2 support" env:"GH_CLIENT_SECRET"`
GithubOrgs []string `short:"o" long:"github-organization" description:"Github organization user is required to have active membership" env:"GH_ORGS" env-delim:","`
ReportingDisabled bool `short:"r" long:"reporting-disabled" description:"Disable reporting of usage stats (os,arch,version,cluster_id,uptime) once every 24hr" env:"REPORTING_DISABLED"`
LogLevel string `short:"l" long:"log-level" value-name:"choice" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" choice:"panic" default:"info" description:"Set the logging level" env:"LOG_LEVEL"`
Basepath string `short:"p" long:"basepath" description:"A URL path prefix under which all chronograf routes will be mounted" env:"BASE_PATH"`
ShowVersion bool `short:"v" long:"version" description:"Show Chronograf version info"`
BuildInfo BuildInfo
Listener net.Listener
handler http.Handler
GoogleClientID string `long:"google-client-id" description:"Google Client ID for OAuth 2 support" env:"GOOGLE_CLIENT_ID"`
GoogleClientSecret string `long:"google-client-secret" description:"Google Client Secret for OAuth 2 support" env:"GOGGLE_CLIENT_SECRET"`
GoogleDomains []string `long:"google-domains" description:"Google email domain user is required to have active membership" env:"GOOGLE_DOMAINS" env-delim:","`
ReportingDisabled bool `short:"r" long:"reporting-disabled" description:"Disable reporting of usage stats (os,arch,version,cluster_id,uptime) once every 24hr" env:"REPORTING_DISABLED"`
LogLevel string `short:"l" long:"log-level" value-name:"choice" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" choice:"panic" default:"info" description:"Set the logging level" env:"LOG_LEVEL"`
Basepath string `short:"p" long:"basepath" description:"A URL path prefix under which all chronograf routes will be mounted" env:"BASE_PATH"`
ShowVersion bool `short:"v" long:"version" description:"Show Chronograf version info"`
BuildInfo BuildInfo
Listener net.Listener
handler http.Handler
}
// BuildInfo is sent to the usage client to track versions and commits
@ -63,7 +67,9 @@ type BuildInfo struct {
}
func (s *Server) useAuth() bool {
return s.TokenSecret != "" && s.GithubClientID != "" && s.GithubClientSecret != ""
gh := s.TokenSecret != "" && s.GithubClientID != "" && s.GithubClientSecret != ""
google := s.TokenSecret != "" && s.GoogleClientID != "" && s.GoogleClientSecret != ""
return gh || google
}
// Serve starts and runs the chronograf server
@ -77,6 +83,9 @@ func (s *Server) Serve() error {
GithubClientID: s.GithubClientID,
GithubClientSecret: s.GithubClientSecret,
GithubOrgs: s.GithubOrgs,
GoogleClientID: s.GoogleClientID,
GoogleClientSecret: s.GoogleClientSecret,
GoogleDomains: s.GoogleDomains,
Logger: logger,
UseAuth: s.useAuth(),
}, service)