From 80d18ee90d71127e7cdaf2e8bfe98618d9501246 Mon Sep 17 00:00:00 2001
From: Greg <2653109+glinton@users.noreply.github.com>
Date: Thu, 13 Feb 2020 11:37:41 -0700
Subject: [PATCH] feat: add flag to redirect login page to specified OAuth IdP
 (#5380)

Co-Authored-By: Bucky Schwarz <hoorayimhelping@users.noreply.github.com>
---
 CHANGELOG.md          |  1 +
 server/mux.go         |  6 ++++--
 server/routes.go      | 11 ++++++-----
 server/routes_test.go |  2 +-
 server/server.go      |  3 +++
 ui/src/auth/Login.js  |  4 ++++
 6 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61bca4b34..76ae06086 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@
 1. [#5367](https://github.com/influxdata/chronograf/pull/5367): Template variables can now select their source database
 1. [#5362](https://github.com/influxdata/chronograf/pull/5362): Add migrate command to chronoctl
 1. [#5308](https://github.com/influxdata/chronograf/pull/5308): The hosts page can be disabled by setting the new environment variable `HOST_PAGE_DISABLED` to `true`, or by passing in `--host-page-disabled` or `-H` flags
+1. [#5380](https://github.com/influxdata/chronograf/pull/5380): Add ability to redirect OAuth login page to OAuth IdP via flag `--redir-auth-login` or environmtent variable `REDIR_AUTH_LOGIN`
 1. [#5383](https://github.com/influxdata/chronograf/pull/5383): Add support for 64-bit arm processors
 
 ### Other
diff --git a/server/mux.go b/server/mux.go
index b9579ae09..343b5e63c 100644
--- a/server/mux.go
+++ b/server/mux.go
@@ -29,6 +29,7 @@ type MuxOpts struct {
 	Develop       bool                 // Develop loads assets from filesystem instead of bindata
 	Basepath      string               // URL path prefix under which all chronograf routes will be mounted
 	UseAuth       bool                 // UseAuth turns on Github OAuth and JWT
+	RedirAuth     string               // RedirAuth specifies which auth to redirect login.
 	Auth          oauth2.Authenticator // Auth is used to authenticate and authorize
 	ProviderFuncs []func(func(oauth2.Provider, oauth2.Mux))
 	StatusFeedURL string       // JSON Feed URL for the client Status page News Feed
@@ -392,8 +393,9 @@ func AuthAPI(opts MuxOpts, router chronograf.Router) (http.Handler, AuthRoutes)
 			router.Handler("GET", logoutPath, m.Logout())
 			router.Handler("GET", callbackPath, m.Callback())
 			routes = append(routes, AuthRoute{
-				Name:  p.Name(),
-				Label: strings.Title(p.Name()),
+				Name:          p.Name(),
+				Label:         strings.Title(p.Name()),
+				RedirectLogin: p.Name() == opts.RedirAuth,
 				// AuthRoutes are content served to the page. When Basepath is set, it
 				// says that all content served to the page will be prefixed with the
 				// basepath. Since these routes are consumed by JS, it will need the
diff --git a/server/routes.go b/server/routes.go
index 085bfcdb5..1fa70385c 100644
--- a/server/routes.go
+++ b/server/routes.go
@@ -10,11 +10,12 @@ import (
 
 // AuthRoute are the routes for each type of OAuth2 provider
 type AuthRoute struct {
-	Name     string `json:"name"`     // Name uniquely identifies the provider
-	Label    string `json:"label"`    // Label is a user-facing string to present in the UI
-	Login    string `json:"login"`    // Login is the route to the login redirect path
-	Logout   string `json:"logout"`   // Logout is the route to the logout redirect path
-	Callback string `json:"callback"` // Callback is the route the provider calls to exchange the code/state
+	Name          string `json:"name"`          // Name uniquely identifies the provider
+	Label         string `json:"label"`         // Label is a user-facing string to present in the UI
+	Login         string `json:"login"`         // Login is the route to the login redirect path
+	Logout        string `json:"logout"`        // Logout is the route to the logout redirect path
+	Callback      string `json:"callback"`      // Callback is the route the provider calls to exchange the code/state
+	RedirectLogin bool   `json:"redirectLogin"` // RedirectLogin tells the ui to redirect to this auth's login.
 }
 
 // AuthRoutes contains all OAuth2 provider routes.
diff --git a/server/routes_test.go b/server/routes_test.go
index e82c62f0c..64e14ad09 100644
--- a/server/routes_test.go
+++ b/server/routes_test.go
@@ -73,7 +73,7 @@ func TestAllRoutesWithAuth(t *testing.T) {
 	if err := json.Unmarshal(body, &routes); err != nil {
 		t.Error("TestAllRoutesWithAuth not able to unmarshal JSON response")
 	}
-	want := `{"protoboards":"/chronograf/v1/protoboards","orgConfig":{"self":"/chronograf/v1/org_config","logViewer":"/chronograf/v1/org_config/logviewer"},"layouts":"/chronograf/v1/layouts","users":"/chronograf/v1/organizations/default/users","allUsers":"/chronograf/v1/users","organizations":"/chronograf/v1/organizations","mappings":"/chronograf/v1/mappings","sources":"/chronograf/v1/sources","me":"/chronograf/v1/me","environment":"/chronograf/v1/env","dashboards":"/chronograf/v1/dashboards","config":{"self":"/chronograf/v1/config","auth":"/chronograf/v1/config/auth"},"auth":[{"name":"github","label":"GitHub","login":"/oauth/github/login","logout":"/oauth/github/logout","callback":"/oauth/github/callback"}],"logout":"/oauth/logout","external":{"statusFeed":""},"flux":{"ast":"/chronograf/v1/flux/ast","self":"/chronograf/v1/flux","suggestions":"/chronograf/v1/flux/suggestions"},"validateTextTemplates":"chronograf/v1/validate_text_templates"}
+	want := `{"protoboards":"/chronograf/v1/protoboards","orgConfig":{"self":"/chronograf/v1/org_config","logViewer":"/chronograf/v1/org_config/logviewer"},"layouts":"/chronograf/v1/layouts","users":"/chronograf/v1/organizations/default/users","allUsers":"/chronograf/v1/users","organizations":"/chronograf/v1/organizations","mappings":"/chronograf/v1/mappings","sources":"/chronograf/v1/sources","me":"/chronograf/v1/me","environment":"/chronograf/v1/env","dashboards":"/chronograf/v1/dashboards","config":{"self":"/chronograf/v1/config","auth":"/chronograf/v1/config/auth"},"auth":[{"name":"github","redirectLogin":false,"label":"GitHub","login":"/oauth/github/login","logout":"/oauth/github/logout","callback":"/oauth/github/callback"}],"logout":"/oauth/logout","external":{"statusFeed":""},"flux":{"ast":"/chronograf/v1/flux/ast","self":"/chronograf/v1/flux","suggestions":"/chronograf/v1/flux/suggestions"},"validateTextTemplates":"chronograf/v1/validate_text_templates"}
 `
 	eq, err := jsonEqual(want, string(body))
 	if err != nil {
diff --git a/server/server.go b/server/server.go
index 519d10079..e4fad4bc1 100644
--- a/server/server.go
+++ b/server/server.go
@@ -101,6 +101,8 @@ type Server struct {
 	Auth0Organizations []string `long:"auth0-organizations" description:"Auth0 organizations permitted to access Chronograf (comma separated)" env:"AUTH0_ORGS" env-delim:","`
 	Auth0SuperAdminOrg string   `long:"auth0-superadmin-org" description:"Auth0 organization from which users are automatically granted SuperAdmin status" env:"AUTH0_SUPERADMIN_ORG"`
 
+	RedirAuth string `long:"redir-auth-login" description:"Automatically redirect login to specified OAuth provider." env:"REDIR_AUTH_LOGIN"`
+
 	StatusFeedURL          string            `long:"status-feed-url" description:"URL of a JSON Feed to display as a News Feed on the client Status page." default:"https://influxdata.com/feed/json" env:"STATUS_FEED_URL"`
 	CustomLinks            map[string]string `long:"custom-link" description:"Custom link to be added to the client User menu. Multiple links can be added by using multiple of the same flag with different 'name:url' values, or as an environment variable with comma-separated 'name:url' values. E.g. via flags: '--custom-link=InfluxData:https://www.influxdata.com --custom-link=Chronograf:https://github.com/influxdata/chronograf'. E.g. via environment variable: 'export CUSTOM_LINKS=InfluxData:https://www.influxdata.com,Chronograf:https://github.com/influxdata/chronograf'" env:"CUSTOM_LINKS" env-delim:","`
 	TelegrafSystemInterval time.Duration     `long:"telegraf-system-interval" default:"1m" description:"Duration used in the GROUP BY time interval for the hosts list" env:"TELEGRAF_SYSTEM_INTERVAL"`
@@ -403,6 +405,7 @@ func (s *Server) Serve(ctx context.Context) {
 		Auth:          auth,
 		Logger:        logger,
 		UseAuth:       s.useAuth(),
+		RedirAuth:     s.RedirAuth,
 		ProviderFuncs: providerFuncs,
 		Basepath:      s.Basepath,
 		StatusFeedURL: s.StatusFeedURL,
diff --git a/ui/src/auth/Login.js b/ui/src/auth/Login.js
index b1f99891f..8824458a3 100644
--- a/ui/src/auth/Login.js
+++ b/ui/src/auth/Login.js
@@ -9,6 +9,10 @@ import SplashPage from 'shared/components/SplashPage'
 const VERSION = process.env.npm_package_version
 
 const Login = ({authData: {auth}}) => {
+  if (Array.isArray(auth.links) && auth.links.length === 1 && auth.links[0].redirectLogin) {
+    window.location.href = auth.links[0].login
+  }
+
   if (auth.isAuthLoading) {
     return <PageSpinner />
   }