From 9a0b4d62516c887cbba13808e69e4aaa2dc734d1 Mon Sep 17 00:00:00 2001 From: Tim Raymond Date: Thu, 16 Feb 2017 12:56:59 -0500 Subject: [PATCH] Configure Mux to use Heroku OAuth2 provider If a --token-secret, --heroku-client-id, and --heroku-secret are provided to Chronograf, it will add Heroku as an OAuth2 provider. These tokens can be obtained (as of this writing) by visiting your "manage account" page, navigating to "Applications," and then clicking "Register New API Client" under the "API Clients" section. --- server/mux.go | 22 ++++++++++++++++++++++ server/routes.go | 10 ++++++++++ server/server.go | 18 +++++++++++++----- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/server/mux.go b/server/mux.go index abbc51c760..78c7731c0e 100644 --- a/server/mux.go +++ b/server/mux.go @@ -31,6 +31,8 @@ type MuxOpts struct { GoogleClientID string // GoogleClientID is the Google OAuth id GoogleClientSecret string // GoogleClientSecret is the Google OAuth secret GoogleDomains []string // GoogleDomains is the list of domains a user may be a member of + HerokuClientID string // HerokuClientID is the Heroku OAuth id + HerokuSecret string // HerokuSecret is the Heroku OAuth secret PublicURL string // PublicURL is the public facing URL for the server } @@ -42,6 +44,10 @@ func (m *MuxOpts) UseGoogle() bool { return m.TokenSecret != "" && m.GoogleClientID != "" && m.GoogleClientSecret != "" && m.PublicURL != "" } +func (m *MuxOpts) UseHeroku() bool { + return m.TokenSecret != "" && m.HerokuClientID != "" && m.HerokuSecret != "" +} + func (m *MuxOpts) Routes() AuthRoutes { routes := AuthRoutes{} if m.UseGithub() { @@ -50,6 +56,9 @@ func (m *MuxOpts) Routes() AuthRoutes { if m.UseGoogle() { routes = append(routes, NewGoogleRoute()) } + if m.UseHeroku() { + routes = append(routes, NewHerokuRoute()) + } return routes } @@ -195,6 +204,19 @@ func AuthAPI(opts MuxOpts, router *httprouter.Router) http.Handler { router.Handler("GET", "/oauth/google/callback", goMux.Callback()) } + if opts.UseHeroku() { + heroku := oauth2.Heroku{ + ClientID: opts.HerokuClientID, + ClientSecret: opts.HerokuSecret, + Logger: opts.Logger, + } + + hMux := oauth2.NewJWTMux(&heroku, &auth, opts.Logger) + router.Handler("GET", "/oauth/heroku/login", hMux.Login()) + router.Handler("GET", "/oauth/heroku/logout", hMux.Logout()) + router.Handler("GET", "/oauth/heroku/callback", hMux.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) { diff --git a/server/routes.go b/server/routes.go index 4dbef40b54..4a8d899876 100644 --- a/server/routes.go +++ b/server/routes.go @@ -79,3 +79,13 @@ func NewGoogleRoute() AuthRoute { Callback: "/oauth/google/callback", } } + +func NewHerokuRoute() AuthRoute { + return AuthRoute{ + Name: "heroku", + Label: "Heroku", + Login: "/oauth/heroku/login", + Logout: "/oauth/heroku/logout", + Callback: "/oauth/heroku/callback", + } +} diff --git a/server/server.go b/server/server.go index 87cd4901ce..81d943fc04 100644 --- a/server/server.go +++ b/server/server.go @@ -40,18 +40,23 @@ type Server struct { TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure conections" env:"TLS_PRIVATE_KEY"` */ - Develop bool `short:"d" long:"develop" description:"Run server in develop mode."` - BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (/var/lib/chronograf/chronograf-v1.db)" env:"BOLT_PATH" default:"chronograf-v1.db"` - CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts (/usr/share/chronograf/canned)" env:"CANNED_PATH" default:"canned"` - TokenSecret string `short:"t" long:"token-secret" description:"Secret to sign tokens" env:"TOKEN_SECRET"` + Develop bool `short:"d" long:"develop" description:"Run server in develop mode."` + BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (/var/lib/chronograf/chronograf-v1.db)" env:"BOLT_PATH" default:"chronograf-v1.db"` + CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts (/usr/share/chronograf/canned)" env:"CANNED_PATH" default:"canned"` + TokenSecret string `short:"t" long:"token-secret" description:"Secret to sign tokens" env:"TOKEN_SECRET"` + 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:","` + 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:","` PublicURL string `long:"public-url" description:"Full public URL used to access Chronograf from a web browser. Used for Google OAuth2 authentication. (http://localhost:8888)" env:"PUBLIC_URL"` + HerokuClientID string `long:"heroku-client-id" description:"Heroku Client ID for OAuth 2 support" env:"HEROKU_CLIENT_ID"` + HerokuSecret string `long:"heroku-secret" description:"Heroku Secret for OAuth 2 support" env:"HEROKU_SECRET"` + 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"` @@ -70,7 +75,8 @@ type BuildInfo struct { func (s *Server) useAuth() bool { gh := s.TokenSecret != "" && s.GithubClientID != "" && s.GithubClientSecret != "" google := s.TokenSecret != "" && s.GoogleClientID != "" && s.GoogleClientSecret != "" && s.PublicURL != "" - return gh || google + heroku := s.TokenSecret != "" && s.HerokuClientID != "" && s.HerokuSecret != "" + return gh || google || heroku } // Serve starts and runs the chronograf server @@ -87,6 +93,8 @@ func (s *Server) Serve() error { GoogleClientID: s.GoogleClientID, GoogleClientSecret: s.GoogleClientSecret, GoogleDomains: s.GoogleDomains, + HerokuClientID: s.HerokuClientID, + HerokuSecret: s.HerokuSecret, PublicURL: s.PublicURL, Logger: logger, UseAuth: s.useAuth(),